Skip to content

Commit f05e859

Browse files
committed
[clang] Implement CWG2398 provisional TTP matching to class templates
This extends default argument deduction to cover class templates as well, and also applies outside of partial ordering, adding to the provisional wording introduced in #89807. This solves some ambuguity introduced in P0522 regarding how template template parameters are partially ordered, and should reduce the negative impact of enabling `-frelaxed-template-template-args` by default. Given the following example: ```C++ template <class T1, class T2 = float> struct A; template <class T3> struct B; template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1 template <class T6, class T7> struct B<A<T6, T7>>; // #2 template struct B<A<int>>; ``` Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This patch restores the pre-P0522 behavior, `#2` is picked again. As the consequences are not restricted to partial ordering, the following code becomes valid: ```C++ template<class T, class U> struct A {}; A<int, float> v; template<template<class> class TT> void f(TT<int>); // OK: TT picks 'float' as the default argument for the second parameter. void g() { f(v); } ``` Also, since 'f' deduced from `A<int, float>` is different from 'f' deduced from `A<int, double>`, this implements an additional mangling rule. --- Since this changes provisional implementation of CWG2398 which has not been released yet, and already contains a changelog entry, we don't provide a changelog entry here.
1 parent 2e1ad93 commit f05e859

28 files changed

+629
-257
lines changed

clang-tools-extra/clangd/DumpAST.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
187187
TEMPLATE_KIND(SubstTemplateTemplateParm);
188188
TEMPLATE_KIND(SubstTemplateTemplateParmPack);
189189
TEMPLATE_KIND(UsingTemplate);
190+
TEMPLATE_KIND(DeducedTemplate);
190191
#undef TEMPLATE_KIND
191192
}
192193
llvm_unreachable("Unhandled NameKind enum");

clang-tools-extra/clangd/SemanticHighlighting.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,7 @@ class CollectExtraHighlightings
11201120
case TemplateName::SubstTemplateTemplateParm:
11211121
case TemplateName::SubstTemplateTemplateParmPack:
11221122
case TemplateName::UsingTemplate:
1123+
case TemplateName::DeducedTemplate:
11231124
// Names that could be resolved to a TemplateDecl are handled elsewhere.
11241125
break;
11251126
}

clang/include/clang/AST/ASTContext.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
262262
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
263263
ASTContext&>
264264
SubstTemplateTemplateParmPacks;
265+
mutable llvm::ContextualFoldingSet<DeducedTemplateStorage, ASTContext &>
266+
DeducedTemplates;
265267

266268
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
267269
ArrayParameterTypes;
@@ -2254,6 +2256,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
22542256
unsigned Index,
22552257
bool Final) const;
22562258

2259+
TemplateName getDeducedTemplateName(TemplateName Underlying,
2260+
DefaultArguments DefaultArgs) const;
2261+
22572262
enum GetBuiltinTypeError {
22582263
/// No error
22592264
GE_None,
@@ -2733,11 +2738,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
27332738
/// template name uses the shortest form of the dependent
27342739
/// nested-name-specifier, which itself contains all canonical
27352740
/// types, values, and templates.
2736-
TemplateName getCanonicalTemplateName(const TemplateName &Name) const;
2741+
TemplateName getCanonicalTemplateName(TemplateName Name,
2742+
bool IgnoreDeduced = false) const;
27372743

27382744
/// Determine whether the given template names refer to the same
27392745
/// template.
2740-
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
2746+
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y,
2747+
bool IgnoreDeduced = false) const;
27412748

27422749
/// Determine whether the two declarations refer to the same entity.
27432750
bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const;

clang/include/clang/AST/ASTImporter.h

+5
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,11 @@ class TypeSourceInfo;
485485
/// the declarations it contains.
486486
[[nodiscard]] llvm::Error ImportDefinition(Decl *From);
487487

488+
llvm::Error
489+
ImportTemplateArguments(ArrayRef<TemplateArgument> FromArgs,
490+
SmallVectorImpl<TemplateArgument> &ToArgs);
491+
Expected<TemplateArgument> Import(const TemplateArgument &From);
492+
488493
/// Cope with a name conflict when importing a declaration into the
489494
/// given context.
490495
///

clang/include/clang/AST/DependenceFlags.h

+5
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ toTemplateNameDependence(NestedNameSpecifierDependence D) {
315315
return Dependence(D).templateName();
316316
}
317317

318+
inline TemplateNameDependence
319+
toTemplateNameDependence(TemplateArgumentDependence D) {
320+
return Dependence(D).templateName();
321+
}
322+
318323
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
319324

320325
} // namespace clang

clang/include/clang/AST/PropertiesBase.td

+17
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,23 @@ let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParmPack"> in {
750750
return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, final);
751751
}]>;
752752
}
753+
let Class = PropertyTypeCase<TemplateName, "DeducedTemplate"> in {
754+
def : ReadHelper<[{
755+
auto DTS = node.getAsDeducedTemplateName();
756+
}]>;
757+
def : Property<"underlying", TemplateName> {
758+
let Read = [{ DTS->getUnderlying() }];
759+
}
760+
def : Property<"startPos", UInt32> {
761+
let Read = [{ DTS->getDefaultArguments().StartPos }];
762+
}
763+
def : Property<"defaultArgs", Array<TemplateArgument>> {
764+
let Read = [{ DTS->getDefaultArguments().Args }];
765+
}
766+
def : Creator<[{
767+
return ctx.getDeducedTemplateName(underlying, {startPos, defaultArgs});
768+
}]>;
769+
}
753770

754771
// Type cases for TemplateArgument.
755772
def : PropertyTypeKind<TemplateArgument, TemplateArgumentKind,

clang/include/clang/AST/TemplateName.h

+60-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class NestedNameSpecifier;
3434
enum OverloadedOperatorKind : int;
3535
class OverloadedTemplateStorage;
3636
class AssumedTemplateStorage;
37+
class DeducedTemplateStorage;
3738
struct PrintingPolicy;
3839
class QualifiedTemplateName;
3940
class SubstTemplateTemplateParmPackStorage;
@@ -50,16 +51,17 @@ class UncommonTemplateNameStorage {
5051
enum Kind {
5152
Overloaded,
5253
Assumed, // defined in DeclarationName.h
54+
Deduced,
5355
SubstTemplateTemplateParm,
5456
SubstTemplateTemplateParmPack
5557
};
5658

5759
struct BitsTag {
5860
LLVM_PREFERRED_TYPE(Kind)
59-
unsigned Kind : 2;
61+
unsigned Kind : 3;
6062

6163
// The template parameter index.
62-
unsigned Index : 15;
64+
unsigned Index : 14;
6365

6466
/// The pack index, or the number of stored templates
6567
/// or template arguments, depending on which subclass we have.
@@ -90,6 +92,12 @@ class UncommonTemplateNameStorage {
9092
: nullptr;
9193
}
9294

95+
DeducedTemplateStorage *getAsDeducedTemplateName() {
96+
return Bits.Kind == Deduced
97+
? reinterpret_cast<DeducedTemplateStorage *>(this)
98+
: nullptr;
99+
}
100+
93101
SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() {
94102
return Bits.Kind == SubstTemplateTemplateParm
95103
? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this)
@@ -172,6 +180,15 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage,
172180
unsigned Index, bool Final);
173181
};
174182

183+
struct DefaultArguments {
184+
// The position in the template parameter list
185+
// the first argument corresponds to.
186+
unsigned StartPos;
187+
ArrayRef<TemplateArgument> Args;
188+
189+
operator bool() const { return !Args.empty(); }
190+
};
191+
175192
/// Represents a C++ template name within the type system.
176193
///
177194
/// A C++ template name refers to a template within the C++ type
@@ -245,6 +262,10 @@ class TemplateName {
245262
/// A template name that refers to a template declaration found through a
246263
/// specific using shadow declaration.
247264
UsingTemplate,
265+
266+
/// A template name that refers to another TemplateName with deduced default
267+
/// arguments.
268+
DeducedTemplate,
248269
};
249270

250271
TemplateName() = default;
@@ -256,6 +277,7 @@ class TemplateName {
256277
explicit TemplateName(QualifiedTemplateName *Qual);
257278
explicit TemplateName(DependentTemplateName *Dep);
258279
explicit TemplateName(UsingShadowDecl *Using);
280+
explicit TemplateName(DeducedTemplateStorage *Deduced);
259281

260282
/// Determine whether this template name is NULL.
261283
bool isNull() const;
@@ -270,7 +292,13 @@ class TemplateName {
270292
/// to, if any. If the template name does not refer to a specific
271293
/// declaration because it is a dependent name, or if it refers to a
272294
/// set of function templates, returns NULL.
273-
TemplateDecl *getAsTemplateDecl() const;
295+
TemplateDecl *getAsTemplateDecl(bool IgnoreDeduced = false) const;
296+
297+
/// Retrieves the underlying template declaration that
298+
/// this template name refers to, along with the
299+
/// deduced default arguments, if any.
300+
std::pair<TemplateDecl *, DefaultArguments>
301+
getTemplateDeclAndDefaultArgs() const;
274302

275303
/// Retrieve the underlying, overloaded function template
276304
/// declarations that this template name refers to, if known.
@@ -312,6 +340,11 @@ class TemplateName {
312340
/// template declaration is introduced, if any.
313341
UsingShadowDecl *getAsUsingShadowDecl() const;
314342

343+
/// Retrieve the deduced template info, if any.
344+
DeducedTemplateStorage *getAsDeducedTemplateName() const;
345+
346+
std::optional<TemplateName> desugar(bool IgnoreDeduced) const;
347+
315348
TemplateName getUnderlying() const;
316349

317350
TemplateNameDependence getDependence() const;
@@ -411,6 +444,30 @@ class SubstTemplateTemplateParmStorage
411444
std::optional<unsigned> PackIndex);
412445
};
413446

447+
class DeducedTemplateStorage : public UncommonTemplateNameStorage,
448+
public llvm::FoldingSetNode {
449+
friend class ASTContext;
450+
451+
TemplateName Underlying;
452+
453+
DeducedTemplateStorage(TemplateName Underlying,
454+
const DefaultArguments &DefArgs);
455+
456+
public:
457+
TemplateName getUnderlying() const { return Underlying; }
458+
459+
DefaultArguments getDefaultArguments() const {
460+
return {/*StartPos=*/Bits.Index,
461+
/*Args=*/{reinterpret_cast<const TemplateArgument *>(this + 1),
462+
Bits.Data}};
463+
}
464+
465+
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
466+
467+
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
468+
TemplateName Underlying, const DefaultArguments &DefArgs);
469+
};
470+
414471
inline TemplateName TemplateName::getUnderlying() const {
415472
if (SubstTemplateTemplateParmStorage *subst
416473
= getAsSubstTemplateTemplateParm())

clang/include/clang/Sema/Sema.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -9210,6 +9210,9 @@ class Sema final : public SemaBase {
92109210
/// receive true if the cause for the error is the associated constraints of
92119211
/// the template not being satisfied by the template arguments.
92129212
///
9213+
/// \param DefaultArgs any default arguments from template specialization
9214+
/// deduction.
9215+
///
92139216
/// \param PartialOrderingTTP If true, assume these template arguments are
92149217
/// the injected template arguments for a template template parameter.
92159218
/// This will relax the requirement that all its possible uses are valid:
@@ -9219,7 +9222,8 @@ class Sema final : public SemaBase {
92199222
/// \returns true if an error occurred, false otherwise.
92209223
bool CheckTemplateArgumentList(
92219224
TemplateDecl *Template, SourceLocation TemplateLoc,
9222-
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
9225+
TemplateArgumentListInfo &TemplateArgs,
9226+
const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
92239227
SmallVectorImpl<TemplateArgument> &SugaredConverted,
92249228
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
92259229
bool UpdateArgsWithConversions = true,
@@ -9718,8 +9722,8 @@ class Sema final : public SemaBase {
97189722
sema::TemplateDeductionInfo &Info);
97199723

97209724
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
9721-
TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc,
9722-
bool IsDeduced);
9725+
TemplateParameterList *PParam, TemplateDecl *AArg,
9726+
const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced);
97239727

97249728
void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
97259729
unsigned Depth, llvm::SmallBitVector &Used);

0 commit comments

Comments
 (0)