Skip to content

Commit fa65804

Browse files
authored
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as well, applying only to 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.
1 parent a0c43be commit fa65804

26 files changed

+748
-371
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
@@ -160,6 +160,9 @@ Resolutions to C++ Defect Reports
160160
- Allow ``void{}`` as a prvalue of type ``void``.
161161
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).
162162

163+
- Clang now has improved resolution to CWG2398, allowing class templates to have
164+
default arguments deduced when partial ordering.
165+
163166
- Clang now allows comparing unequal object pointers that have been cast to ``void *``
164167
in constant expressions. These comparisons always worked in non-constant expressions.
165168
(`CWG2749: Treatment of "pointer to void" for relational comparisons <https://cplusplus.github.io/CWG/issues/2749.html>`_).

clang/include/clang/AST/ASTContext.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
265265
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
266266
ASTContext&>
267267
SubstTemplateTemplateParmPacks;
268+
mutable llvm::ContextualFoldingSet<DeducedTemplateStorage, ASTContext &>
269+
DeducedTemplates;
268270

269271
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
270272
ArrayParameterTypes;
@@ -2304,6 +2306,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
23042306
unsigned Index,
23052307
bool Final) const;
23062308

2309+
/// Represents a TemplateName which had some of its default arguments
2310+
/// deduced. This both represents this default argument deduction as sugar,
2311+
/// and provides the support for it's equivalences through canonicalization.
2312+
/// For example DeducedTemplateNames which have the same set of default
2313+
/// arguments are equivalent, and are also equivalent to the underlying
2314+
/// template when the deduced template arguments are the same.
2315+
TemplateName getDeducedTemplateName(TemplateName Underlying,
2316+
DefaultArguments DefaultArgs) const;
2317+
23072318
enum GetBuiltinTypeError {
23082319
/// No error
23092320
GE_None,
@@ -2787,11 +2798,13 @@ class ASTContext : public RefCountedBase<ASTContext> {
27872798
/// template name uses the shortest form of the dependent
27882799
/// nested-name-specifier, which itself contains all canonical
27892800
/// types, values, and templates.
2790-
TemplateName getCanonicalTemplateName(const TemplateName &Name) const;
2801+
TemplateName getCanonicalTemplateName(TemplateName Name,
2802+
bool IgnoreDeduced = false) const;
27912803

27922804
/// Determine whether the given template names refer to the same
27932805
/// template.
2794-
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
2806+
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y,
2807+
bool IgnoreDeduced = false) const;
27952808

27962809
/// Determine whether the two declarations refer to the same entity.
27972810
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
@@ -11733,6 +11733,9 @@ class Sema final : public SemaBase {
1173311733
/// receive true if the cause for the error is the associated constraints of
1173411734
/// the template not being satisfied by the template arguments.
1173511735
///
11736+
/// \param DefaultArgs any default arguments from template specialization
11737+
/// deduction.
11738+
///
1173611739
/// \param PartialOrderingTTP If true, assume these template arguments are
1173711740
/// the injected template arguments for a template template parameter.
1173811741
/// This will relax the requirement that all its possible uses are valid:
@@ -11742,7 +11745,8 @@ class Sema final : public SemaBase {
1174211745
/// \returns true if an error occurred, false otherwise.
1174311746
bool CheckTemplateArgumentList(
1174411747
TemplateDecl *Template, SourceLocation TemplateLoc,
11745-
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
11748+
TemplateArgumentListInfo &TemplateArgs,
11749+
const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
1174611750
SmallVectorImpl<TemplateArgument> &SugaredConverted,
1174711751
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
1174811752
bool UpdateArgsWithConversions = true,
@@ -12479,8 +12483,8 @@ class Sema final : public SemaBase {
1247912483
sema::TemplateDeductionInfo &Info);
1248012484

1248112485
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
12482-
TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc,
12483-
bool IsDeduced);
12486+
TemplateParameterList *PParam, TemplateDecl *AArg,
12487+
const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced);
1248412488

1248512489
/// Mark which template parameters are used in a given expression.
1248612490
///

0 commit comments

Comments
 (0)