Skip to content

Commit 015a057

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 3f6fe4e commit 015a057

25 files changed

+584
-255
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

+7-1
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;
@@ -2247,6 +2249,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
22472249
unsigned Index,
22482250
bool Final) const;
22492251

2252+
TemplateName getDeducedTemplateName(TemplateName Underlying,
2253+
DefaultArguments DefaultArgs) const;
2254+
22502255
enum GetBuiltinTypeError {
22512256
/// No error
22522257
GE_None,
@@ -2726,7 +2731,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
27262731
/// template name uses the shortest form of the dependent
27272732
/// nested-name-specifier, which itself contains all canonical
27282733
/// types, values, and templates.
2729-
TemplateName getCanonicalTemplateName(const TemplateName &Name) const;
2734+
TemplateName getCanonicalTemplateName(TemplateName Name,
2735+
bool IgnoreDeduced = false) const;
27302736

27312737
/// Determine whether the given template names refer to the same
27322738
/// template.

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

+57-2
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,13 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage,
172180
unsigned Index, bool Final);
173181
};
174182

183+
struct DefaultArguments {
184+
unsigned StartPos;
185+
ArrayRef<TemplateArgument> Args;
186+
187+
operator bool() const { return !Args.empty(); }
188+
};
189+
175190
/// Represents a C++ template name within the type system.
176191
///
177192
/// A C++ template name refers to a template within the C++ type
@@ -245,6 +260,10 @@ class TemplateName {
245260
/// A template name that refers to a template declaration found through a
246261
/// specific using shadow declaration.
247262
UsingTemplate,
263+
264+
/// A template name that refers to another TemplateName with deduced default
265+
/// arguments.
266+
DeducedTemplate,
248267
};
249268

250269
TemplateName() = default;
@@ -256,6 +275,7 @@ class TemplateName {
256275
explicit TemplateName(QualifiedTemplateName *Qual);
257276
explicit TemplateName(DependentTemplateName *Dep);
258277
explicit TemplateName(UsingShadowDecl *Using);
278+
explicit TemplateName(DeducedTemplateStorage *Deduced);
259279

260280
/// Determine whether this template name is NULL.
261281
bool isNull() const;
@@ -272,6 +292,12 @@ class TemplateName {
272292
/// set of function templates, returns NULL.
273293
TemplateDecl *getAsTemplateDecl() const;
274294

295+
/// Retrieves the underlying template declaration that
296+
/// this template name refers to, along with the
297+
/// deduced default arguments, if any.
298+
std::pair<TemplateDecl *, DefaultArguments>
299+
getTemplateDeclAndDefaultArgs() const;
300+
275301
/// Retrieve the underlying, overloaded function template
276302
/// declarations that this template name refers to, if known.
277303
///
@@ -312,6 +338,11 @@ class TemplateName {
312338
/// template declaration is introduced, if any.
313339
UsingShadowDecl *getAsUsingShadowDecl() const;
314340

341+
/// Retrieve the deduced template info, if any.
342+
DeducedTemplateStorage *getAsDeducedTemplateName() const;
343+
344+
std::optional<TemplateName> desugar(bool IgnoreDeduced) const;
345+
315346
TemplateName getUnderlying() const;
316347

317348
TemplateNameDependence getDependence() const;
@@ -409,6 +440,30 @@ class SubstTemplateTemplateParmStorage
409440
std::optional<unsigned> PackIndex);
410441
};
411442

443+
class DeducedTemplateStorage : public UncommonTemplateNameStorage,
444+
public llvm::FoldingSetNode {
445+
friend class ASTContext;
446+
447+
TemplateName Underlying;
448+
449+
DeducedTemplateStorage(TemplateName Underlying,
450+
const DefaultArguments &DefArgs);
451+
452+
public:
453+
TemplateName getUnderlying() const { return Underlying; }
454+
455+
DefaultArguments getDefaultArguments() const {
456+
return {/*StartPos=*/Bits.Index,
457+
/*Args=*/{reinterpret_cast<const TemplateArgument *>(this + 1),
458+
Bits.Data}};
459+
}
460+
461+
void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context);
462+
463+
static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
464+
TemplateName Underlying, const DefaultArguments &DefArgs);
465+
};
466+
412467
inline TemplateName TemplateName::getUnderlying() const {
413468
if (SubstTemplateTemplateParmStorage *subst
414469
= 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)