Skip to content

Commit 3f95419

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 14b0812 commit 3f95419

26 files changed

+773
-382
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/docs/ReleaseNotes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ Resolutions to C++ Defect Reports
149149
of the target type, even if the type of the bit-field is larger.
150150
(`CWG2627: Bit-fields and narrowing conversions <https://cplusplus.github.io/CWG/issues/2627.html>`_)
151151

152+
- Clang now has improved resolution to CWG2398, allowing class templates to have
153+
default arguments deduced when partial ordering.
154+
152155
C Language Changes
153156
------------------
154157

clang/include/clang/AST/ASTContext.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
264264
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
265265
ASTContext&>
266266
SubstTemplateTemplateParmPacks;
267+
mutable llvm::ContextualFoldingSet<DeducedTemplateStorage, ASTContext &>
268+
DeducedTemplates;
267269

268270
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
269271
ArrayParameterTypes;
@@ -2291,6 +2293,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
22912293
unsigned Index,
22922294
bool Final) const;
22932295

2296+
TemplateName getDeducedTemplateName(TemplateName Underlying,
2297+
DefaultArguments DefaultArgs) const;
2298+
22942299
enum GetBuiltinTypeError {
22952300
/// No error
22962301
GE_None,
@@ -2774,11 +2779,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
27742779
/// template name uses the shortest form of the dependent
27752780
/// nested-name-specifier, which itself contains all canonical
27762781
/// types, values, and templates.
2777-
TemplateName getCanonicalTemplateName(const TemplateName &Name) const;
2782+
TemplateName getCanonicalTemplateName(TemplateName Name,
2783+
bool IgnoreDeduced = false) const;
27782784

27792785
/// Determine whether the given template names refer to the same
27802786
/// template.
2781-
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
2787+
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y,
2788+
bool IgnoreDeduced = false) const;
27822789

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

clang/include/clang/AST/ASTImporter.h

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

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

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
@@ -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

+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
@@ -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

+7-3
Original file line numberDiff line numberDiff line change
@@ -11725,6 +11725,9 @@ class Sema final : public SemaBase {
1172511725
/// receive true if the cause for the error is the associated constraints of
1172611726
/// the template not being satisfied by the template arguments.
1172711727
///
11728+
/// \param DefaultArgs any default arguments from template specialization
11729+
/// deduction.
11730+
///
1172811731
/// \param PartialOrderingTTP If true, assume these template arguments are
1172911732
/// the injected template arguments for a template template parameter.
1173011733
/// This will relax the requirement that all its possible uses are valid:
@@ -11734,7 +11737,8 @@ class Sema final : public SemaBase {
1173411737
/// \returns true if an error occurred, false otherwise.
1173511738
bool CheckTemplateArgumentList(
1173611739
TemplateDecl *Template, SourceLocation TemplateLoc,
11737-
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
11740+
TemplateArgumentListInfo &TemplateArgs,
11741+
const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
1173811742
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1173911743
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
1174011744
bool UpdateArgsWithConversions = true,
@@ -12471,8 +12475,8 @@ class Sema final : public SemaBase {
1247112475
sema::TemplateDeductionInfo &Info);
1247212476

1247312477
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
12474-
TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc,
12475-
bool IsDeduced);
12478+
TemplateParameterList *PParam, TemplateDecl *AArg,
12479+
const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced);
1247612480

1247712481
/// Mark which template parameters are used in a given expression.
1247812482
///

0 commit comments

Comments
 (0)