Skip to content

Commit 9d06fd6

Browse files
committed
[clang] Implement CWG2398 provisional TTP matching to class templates
This extends default argument deduction to cover class templates as well. 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.
1 parent 89e5db4 commit 9d06fd6

26 files changed

+776
-386
lines changed

clang-tools-extra/clangd/DumpAST.cpp

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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/docs/ReleaseNotes.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ C++2c Feature Support
8484
Resolutions to C++ Defect Reports
8585
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8686

87+
- Clang now has improved resolution to CWG2398, allowing class templates to have
88+
default arguments deduced when partial ordering.
89+
8790
C Language Changes
8891
------------------
8992

@@ -119,7 +122,7 @@ Improvements to Clang's diagnostics
119122
- Some template related diagnostics have been improved.
120123

121124
.. code-block:: c++
122-
125+
123126
void foo() { template <typename> int i; } // error: templates can only be declared in namespace or class scope
124127

125128
struct S {

clang/include/clang/AST/ASTContext.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
263263
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
264264
ASTContext&>
265265
SubstTemplateTemplateParmPacks;
266+
mutable llvm::ContextualFoldingSet<DeducedTemplateStorage, ASTContext &>
267+
DeducedTemplates;
266268

267269
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
268270
ArrayParameterTypes;
@@ -2288,6 +2290,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
22882290
unsigned Index,
22892291
bool Final) const;
22902292

2293+
TemplateName getDeducedTemplateName(TemplateName Underlying,
2294+
DefaultArguments DefaultArgs) const;
2295+
22912296
enum GetBuiltinTypeError {
22922297
/// No error
22932298
GE_None,
@@ -2771,11 +2776,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
27712776
/// template name uses the shortest form of the dependent
27722777
/// nested-name-specifier, which itself contains all canonical
27732778
/// types, values, and templates.
2774-
TemplateName getCanonicalTemplateName(const TemplateName &Name) const;
2779+
TemplateName getCanonicalTemplateName(TemplateName Name,
2780+
bool IgnoreDeduced = false) const;
27752781

27762782
/// Determine whether the given template names refer to the same
27772783
/// template.
2778-
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
2784+
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y,
2785+
bool IgnoreDeduced = false) const;
27792786

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

clang/include/clang/AST/ASTImporter.h

Lines changed: 5 additions & 0 deletions
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

Lines changed: 5 additions & 0 deletions
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

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

756773
// Type cases for TemplateArgument.
757774
def : PropertyTypeKind<TemplateArgument, TemplateArgumentKind,

clang/include/clang/AST/TemplateName.h

Lines changed: 60 additions & 3 deletions
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
@@ -246,6 +263,10 @@ class TemplateName {
246263
/// A template name that refers to a template declaration found through a
247264
/// specific using shadow declaration.
248265
UsingTemplate,
266+
267+
/// A template name that refers to another TemplateName with deduced default
268+
/// arguments.
269+
DeducedTemplate,
249270
};
250271

251272
TemplateName() = default;
@@ -257,6 +278,7 @@ class TemplateName {
257278
explicit TemplateName(QualifiedTemplateName *Qual);
258279
explicit TemplateName(DependentTemplateName *Dep);
259280
explicit TemplateName(UsingShadowDecl *Using);
281+
explicit TemplateName(DeducedTemplateStorage *Deduced);
260282

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

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

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

318351
TemplateNameDependence getDependence() const;
@@ -412,6 +445,30 @@ class SubstTemplateTemplateParmStorage
412445
std::optional<unsigned> PackIndex);
413446
};
414447

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

clang/include/clang/Sema/Sema.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11710,6 +11710,9 @@ class Sema final : public SemaBase {
1171011710
/// receive true if the cause for the error is the associated constraints of
1171111711
/// the template not being satisfied by the template arguments.
1171211712
///
11713+
/// \param DefaultArgs any default arguments from template specialization
11714+
/// deduction.
11715+
///
1171311716
/// \param PartialOrderingTTP If true, assume these template arguments are
1171411717
/// the injected template arguments for a template template parameter.
1171511718
/// This will relax the requirement that all its possible uses are valid:
@@ -11719,7 +11722,8 @@ class Sema final : public SemaBase {
1171911722
/// \returns true if an error occurred, false otherwise.
1172011723
bool CheckTemplateArgumentList(
1172111724
TemplateDecl *Template, SourceLocation TemplateLoc,
11722-
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
11725+
TemplateArgumentListInfo &TemplateArgs,
11726+
const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
1172311727
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1172411728
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
1172511729
bool UpdateArgsWithConversions = true,
@@ -12453,8 +12457,8 @@ class Sema final : public SemaBase {
1245312457
sema::TemplateDeductionInfo &Info);
1245412458

1245512459
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
12456-
TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc,
12457-
bool IsDeduced);
12460+
TemplateParameterList *PParam, TemplateDecl *AArg,
12461+
const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced);
1245812462

1245912463
/// Mark which template parameters are used in a given expression.
1246012464
///

0 commit comments

Comments
 (0)