summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatheus Izvekov <mizvekov@gmail.com>2024-05-20 01:15:03 -0300
committerMatheus Izvekov <mizvekov@gmail.com>2024-06-19 00:50:41 -0300
commitb238961ba3a174d7dc211caf36ff8fd6c8429a76 (patch)
tree2d3e0e83d7a3d52be1e3572e0bd656bdf231d318
parent728fb233b01330243a574c51ad524acffc3ffa2d (diff)
[clang] Implement CWG2398 provisional TTP matching to class templatesupstream/users/mizvekov/clang-cwg2398-ttp-matches-class-template
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 https://github.com/llvm/llvm-project/pull/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.
-rw-r--r--clang-tools-extra/clangd/DumpAST.cpp1
-rw-r--r--clang-tools-extra/clangd/SemanticHighlighting.cpp1
-rw-r--r--clang/include/clang/AST/ASTContext.h11
-rw-r--r--clang/include/clang/AST/ASTImporter.h5
-rw-r--r--clang/include/clang/AST/DependenceFlags.h5
-rw-r--r--clang/include/clang/AST/PropertiesBase.td17
-rw-r--r--clang/include/clang/AST/TemplateName.h63
-rw-r--r--clang/include/clang/Sema/Sema.h10
-rw-r--r--clang/lib/AST/ASTContext.cpp153
-rw-r--r--clang/lib/AST/ASTDiagnostic.cpp45
-rw-r--r--clang/lib/AST/ASTImporter.cpp15
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp3
-rw-r--r--clang/lib/AST/Decl.cpp3
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp20
-rw-r--r--clang/lib/AST/ODRHash.cpp1
-rw-r--r--clang/lib/AST/TemplateName.cpp163
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp12
-rw-r--r--clang/lib/AST/Type.cpp3
-rw-r--r--clang/lib/AST/TypePrinter.cpp3
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp9
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp63
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp158
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp24
-rw-r--r--clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp5
-rw-r--r--clang/test/CodeGenCXX/mangle-cwg2398.cpp11
-rw-r--r--clang/test/SemaTemplate/cwg2398.cpp62
-rw-r--r--clang/tools/libclang/CIndex.cpp3
-rw-r--r--clang/unittests/AST/ASTImporterTest.cpp17
28 files changed, 629 insertions, 257 deletions
diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp
index 9a525efb938e..e605f82e91fe 100644
--- a/clang-tools-extra/clangd/DumpAST.cpp
+++ b/clang-tools-extra/clangd/DumpAST.cpp
@@ -187,6 +187,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
TEMPLATE_KIND(SubstTemplateTemplateParm);
TEMPLATE_KIND(SubstTemplateTemplateParmPack);
TEMPLATE_KIND(UsingTemplate);
+ TEMPLATE_KIND(DeducedTemplate);
#undef TEMPLATE_KIND
}
llvm_unreachable("Unhandled NameKind enum");
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index a366f1331c2d..e6d16af2495f 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -1120,6 +1120,7 @@ public:
case TemplateName::SubstTemplateTemplateParm:
case TemplateName::SubstTemplateTemplateParmPack:
case TemplateName::UsingTemplate:
+ case TemplateName::DeducedTemplate:
// Names that could be resolved to a TemplateDecl are handled elsewhere.
break;
}
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index de86cb5e9d7f..837bcacbc0bf 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -262,6 +262,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage,
ASTContext&>
SubstTemplateTemplateParmPacks;
+ mutable llvm::ContextualFoldingSet<DeducedTemplateStorage, ASTContext &>
+ DeducedTemplates;
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
ArrayParameterTypes;
@@ -2256,6 +2258,9 @@ public:
unsigned Index,
bool Final) const;
+ TemplateName getDeducedTemplateName(TemplateName Underlying,
+ DefaultArguments DefaultArgs) const;
+
enum GetBuiltinTypeError {
/// No error
GE_None,
@@ -2735,11 +2740,13 @@ public:
/// template name uses the shortest form of the dependent
/// nested-name-specifier, which itself contains all canonical
/// types, values, and templates.
- TemplateName getCanonicalTemplateName(const TemplateName &Name) const;
+ TemplateName getCanonicalTemplateName(TemplateName Name,
+ bool IgnoreDeduced = false) const;
/// Determine whether the given template names refer to the same
/// template.
- bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
+ bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y,
+ bool IgnoreDeduced = false) const;
/// Determine whether the two declarations refer to the same entity.
bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const;
diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h
index 4ffd91384657..7b890bdf492f 100644
--- a/clang/include/clang/AST/ASTImporter.h
+++ b/clang/include/clang/AST/ASTImporter.h
@@ -485,6 +485,11 @@ class TypeSourceInfo;
/// the declarations it contains.
[[nodiscard]] llvm::Error ImportDefinition(Decl *From);
+ llvm::Error
+ ImportTemplateArguments(ArrayRef<TemplateArgument> FromArgs,
+ SmallVectorImpl<TemplateArgument> &ToArgs);
+ Expected<TemplateArgument> Import(const TemplateArgument &From);
+
/// Cope with a name conflict when importing a declaration into the
/// given context.
///
diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h
index 3b3c1afb096a..bdcaabc143cc 100644
--- a/clang/include/clang/AST/DependenceFlags.h
+++ b/clang/include/clang/AST/DependenceFlags.h
@@ -315,6 +315,11 @@ toTemplateNameDependence(NestedNameSpecifierDependence D) {
return Dependence(D).templateName();
}
+inline TemplateNameDependence
+toTemplateNameDependence(TemplateArgumentDependence D) {
+ return Dependence(D).templateName();
+}
+
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
} // namespace clang
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 6df1d93a7ba2..bd0b316a4958 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -750,6 +750,23 @@ let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParmPack"> in {
return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, final);
}]>;
}
+let Class = PropertyTypeCase<TemplateName, "DeducedTemplate"> in {
+ def : ReadHelper<[{
+ auto DTS = node.getAsDeducedTemplateName();
+ }]>;
+ def : Property<"underlying", TemplateName> {
+ let Read = [{ DTS->getUnderlying() }];
+ }
+ def : Property<"startPos", UInt32> {
+ let Read = [{ DTS->getDefaultArguments().StartPos }];
+ }
+ def : Property<"defaultArgs", Array<TemplateArgument>> {
+ let Read = [{ DTS->getDefaultArguments().Args }];
+ }
+ def : Creator<[{
+ return ctx.getDeducedTemplateName(underlying, {startPos, defaultArgs});
+ }]>;
+}
// Type cases for TemplateArgument.
def : PropertyTypeKind<TemplateArgument, TemplateArgumentKind,
diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h
index 24a7fde76195..6919e127629c 100644
--- a/clang/include/clang/AST/TemplateName.h
+++ b/clang/include/clang/AST/TemplateName.h
@@ -34,6 +34,7 @@ class NestedNameSpecifier;
enum OverloadedOperatorKind : int;
class OverloadedTemplateStorage;
class AssumedTemplateStorage;
+class DeducedTemplateStorage;
struct PrintingPolicy;
class QualifiedTemplateName;
class SubstTemplateTemplateParmPackStorage;
@@ -50,16 +51,17 @@ protected:
enum Kind {
Overloaded,
Assumed, // defined in DeclarationName.h
+ Deduced,
SubstTemplateTemplateParm,
SubstTemplateTemplateParmPack
};
struct BitsTag {
LLVM_PREFERRED_TYPE(Kind)
- unsigned Kind : 2;
+ unsigned Kind : 3;
// The template parameter index.
- unsigned Index : 15;
+ unsigned Index : 14;
/// The pack index, or the number of stored templates
/// or template arguments, depending on which subclass we have.
@@ -90,6 +92,12 @@ public:
: nullptr;
}
+ DeducedTemplateStorage *getAsDeducedTemplateName() {
+ return Bits.Kind == Deduced
+ ? reinterpret_cast<DeducedTemplateStorage *>(this)
+ : nullptr;
+ }
+
SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() {
return Bits.Kind == SubstTemplateTemplateParm
? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this)
@@ -172,6 +180,15 @@ public:
unsigned Index, bool Final);
};
+struct DefaultArguments {
+ // The position in the template parameter list
+ // the first argument corresponds to.
+ unsigned StartPos;
+ ArrayRef<TemplateArgument> Args;
+
+ operator bool() const { return !Args.empty(); }
+};
+
/// Represents a C++ template name within the type system.
///
/// A C++ template name refers to a template within the C++ type
@@ -245,6 +262,10 @@ public:
/// A template name that refers to a template declaration found through a
/// specific using shadow declaration.
UsingTemplate,
+
+ /// A template name that refers to another TemplateName with deduced default
+ /// arguments.
+ DeducedTemplate,
};
TemplateName() = default;
@@ -256,6 +277,7 @@ public:
explicit TemplateName(QualifiedTemplateName *Qual);
explicit TemplateName(DependentTemplateName *Dep);
explicit TemplateName(UsingShadowDecl *Using);
+ explicit TemplateName(DeducedTemplateStorage *Deduced);
/// Determine whether this template name is NULL.
bool isNull() const;
@@ -270,7 +292,13 @@ public:
/// to, if any. If the template name does not refer to a specific
/// declaration because it is a dependent name, or if it refers to a
/// set of function templates, returns NULL.
- TemplateDecl *getAsTemplateDecl() const;
+ TemplateDecl *getAsTemplateDecl(bool IgnoreDeduced = false) const;
+
+ /// Retrieves the underlying template declaration that
+ /// this template name refers to, along with the
+ /// deduced default arguments, if any.
+ std::pair<TemplateDecl *, DefaultArguments>
+ getTemplateDeclAndDefaultArgs() const;
/// Retrieve the underlying, overloaded function template
/// declarations that this template name refers to, if known.
@@ -312,6 +340,11 @@ public:
/// template declaration is introduced, if any.
UsingShadowDecl *getAsUsingShadowDecl() const;
+ /// Retrieve the deduced template info, if any.
+ DeducedTemplateStorage *getAsDeducedTemplateName() const;
+
+ std::optional<TemplateName> desugar(bool IgnoreDeduced) const;
+
TemplateName getUnderlying() const;
TemplateNameDependence getDependence() const;
@@ -411,6 +444,30 @@ public:
std::optional<unsigned> PackIndex);
};
+class DeducedTemplateStorage : public UncommonTemplateNameStorage,
+ public llvm::FoldingSetNode {
+ friend class ASTContext;
+
+ TemplateName Underlying;
+
+ DeducedTemplateStorage(TemplateName Underlying,
+ const DefaultArguments &DefArgs);
+
+public:
+ TemplateName getUnderlying() const { return Underlying; }
+
+ DefaultArguments getDefaultArguments() const {
+ return {/*StartPos=*/Bits.Index,
+ /*Args=*/{reinterpret_cast<const TemplateArgument *>(this + 1),
+ Bits.Data}};
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const;
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ TemplateName Underlying, const DefaultArguments &DefArgs);
+};
+
inline TemplateName TemplateName::getUnderlying() const {
if (SubstTemplateTemplateParmStorage *subst
= getAsSubstTemplateTemplateParm())
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 174b9dbc6d98..a847fb8fe550 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9216,6 +9216,9 @@ public:
/// receive true if the cause for the error is the associated constraints of
/// the template not being satisfied by the template arguments.
///
+ /// \param DefaultArgs any default arguments from template specialization
+ /// deduction.
+ ///
/// \param PartialOrderingTTP If true, assume these template arguments are
/// the injected template arguments for a template template parameter.
/// This will relax the requirement that all its possible uses are valid:
@@ -9225,7 +9228,8 @@ public:
/// \returns true if an error occurred, false otherwise.
bool CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
- TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
+ TemplateArgumentListInfo &TemplateArgs,
+ const DefaultArguments &DefaultArgs, bool PartialTemplateArgs,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions = true,
@@ -9724,8 +9728,8 @@ public:
sema::TemplateDeductionInfo &Info);
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
- TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc,
- bool IsDeduced);
+ TemplateParameterList *PParam, TemplateDecl *AArg,
+ const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced);
void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
unsigned Depth, llvm::SmallBitVector &Used);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a4e6d3b108c8..d291a0a936df 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -880,8 +880,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()),
- ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()),
- SourceMgr(SM), LangOpts(LOpts),
+ DeducedTemplates(this_()), ArrayParameterTypes(this_()),
+ CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)),
XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
LangOpts.XRayNeverInstrumentFiles,
@@ -5022,7 +5022,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
- const auto *TD = Template.getAsTemplateDecl();
+ const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true);
bool IsTypeAlias = TD && TD->isTypeAlias();
QualType CanonType;
if (!Underlying.isNull())
@@ -5057,7 +5057,12 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
"No dependent template names here!");
// Build the canonical template specialization type.
- TemplateName CanonTemplate = getCanonicalTemplateName(Template);
+ // Any DeducedTemplateNames are ignored, because the effective name of a TST
+ // accounts for the TST arguments laid over any default arguments contained in
+ // its name.
+ TemplateName CanonTemplate =
+ getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
+
bool AnyNonCanonArgs = false;
auto CanonArgs =
::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
@@ -6354,16 +6359,41 @@ ASTContext::getNameForTemplate(TemplateName Name,
case TemplateName::UsingTemplate:
return DeclarationNameInfo(Name.getAsUsingShadowDecl()->getDeclName(),
NameLoc);
+ case TemplateName::DeducedTemplate: {
+ DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName();
+ return getNameForTemplate(DTS->getUnderlying(), NameLoc);
+ }
}
llvm_unreachable("bad template name kind!");
}
-TemplateName
-ASTContext::getCanonicalTemplateName(const TemplateName &Name) const {
+static const TemplateArgument *
+getDefaultTemplateArgumentOrNone(const NamedDecl *P) {
+ auto handleParam = [](auto *TP) -> const TemplateArgument * {
+ if (!TP->hasDefaultArgument())
+ return nullptr;
+ return &TP->getDefaultArgument().getArgument();
+ };
+ switch (P->getKind()) {
+ case NamedDecl::TemplateTypeParm:
+ return handleParam(cast<TemplateTypeParmDecl>(P));
+ case NamedDecl::NonTypeTemplateParm:
+ return handleParam(cast<NonTypeTemplateParmDecl>(P));
+ case NamedDecl::TemplateTemplateParm:
+ return handleParam(cast<TemplateTemplateParmDecl>(P));
+ default:
+ llvm_unreachable("Unexpected template parameter kind");
+ }
+}
+
+TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name,
+ bool IgnoreDeduced) const {
+ while (std::optional<TemplateName> UnderlyingOrNone =
+ Name.desugar(IgnoreDeduced))
+ Name = *UnderlyingOrNone;
+
switch (Name.getKind()) {
- case TemplateName::UsingTemplate:
- case TemplateName::QualifiedTemplate:
case TemplateName::Template: {
TemplateDecl *Template = Name.getAsTemplateDecl();
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Template))
@@ -6383,12 +6413,6 @@ ASTContext::getCanonicalTemplateName(const TemplateName &Name) const {
return DTN->CanonicalTemplateName;
}
- case TemplateName::SubstTemplateTemplateParm: {
- SubstTemplateTemplateParmStorage *subst
- = Name.getAsSubstTemplateTemplateParm();
- return getCanonicalTemplateName(subst->getReplacement());
- }
-
case TemplateName::SubstTemplateTemplateParmPack: {
SubstTemplateTemplateParmPackStorage *subst =
Name.getAsSubstTemplateTemplateParmPack();
@@ -6398,15 +6422,58 @@ ASTContext::getCanonicalTemplateName(const TemplateName &Name) const {
canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(),
subst->getFinal(), subst->getIndex());
}
+ case TemplateName::DeducedTemplate: {
+ assert(IgnoreDeduced == false);
+ DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName();
+ DefaultArguments DefArgs = DTS->getDefaultArguments();
+ TemplateName Underlying = DTS->getUnderlying();
+
+ TemplateName CanonUnderlying =
+ getCanonicalTemplateName(Underlying, /*IgnoreDeduced=*/true);
+ bool NonCanonical = CanonUnderlying != Underlying;
+ auto CanonArgs =
+ getCanonicalTemplateArguments(*this, DefArgs.Args, NonCanonical);
+
+ ArrayRef<NamedDecl *> Params =
+ CanonUnderlying.getAsTemplateDecl()->getTemplateParameters()->asArray();
+ assert(CanonArgs.size() <= Params.size());
+ // A deduced template name which deduces the same default arguments already
+ // declared in the underlying template, is the same template as the
+ // underlying template. We need need to note any arguments which differ from
+ // the corresponding declaration. If they are not the same, we must build a
+ // deduced template name.
+ for (int I = CanonArgs.size() - 1; I >= 0; --I) {
+ const TemplateArgument *A = getDefaultTemplateArgumentOrNone(Params[I]);
+ if (!A)
+ break;
+ auto CanonParamDefArg = getCanonicalTemplateArgument(*A);
+ TemplateArgument &CanonDefArg = CanonArgs[I];
+ if (CanonDefArg.structurallyEquals(CanonParamDefArg))
+ continue;
+ // Keep popping from the back any deault arguments which are the same.
+ if (I == int(CanonArgs.size() - 1))
+ CanonArgs.pop_back();
+ NonCanonical = true;
+ }
+ return NonCanonical ? getDeducedTemplateName(
+ CanonUnderlying,
+ /*DefaultArgs=*/{DefArgs.StartPos, CanonArgs})
+ : Name;
+ }
+ case TemplateName::UsingTemplate:
+ case TemplateName::QualifiedTemplate:
+ case TemplateName::SubstTemplateTemplateParm:
+ llvm_unreachable("always sugar node");
}
llvm_unreachable("bad template name!");
}
bool ASTContext::hasSameTemplateName(const TemplateName &X,
- const TemplateName &Y) const {
- return getCanonicalTemplateName(X).getAsVoidPointer() ==
- getCanonicalTemplateName(Y).getAsVoidPointer();
+ const TemplateName &Y,
+ bool IgnoreDeduced) const {
+ return getCanonicalTemplateName(X, IgnoreDeduced) ==
+ getCanonicalTemplateName(Y, IgnoreDeduced);
}
bool ASTContext::isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const {
@@ -6895,7 +6962,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::StructuralValue:
return TemplateArgument(*this,
getCanonicalType(Arg.getStructuralValueType()),
- Arg.getAsStructuralValue());
+ Arg.getAsStructuralValue(), Arg.getIsDefaulted());
case TemplateArgument::Type:
return TemplateArgument(getCanonicalType(Arg.getAsType()),
@@ -6907,8 +6974,10 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
*this, Arg.pack_elements(), AnyNonCanonArgs);
if (!AnyNonCanonArgs)
return Arg;
- return TemplateArgument::CreatePackCopy(const_cast<ASTContext &>(*this),
- CanonArgs);
+ auto NewArg = TemplateArgument::CreatePackCopy(
+ const_cast<ASTContext &>(*this), CanonArgs);
+ NewArg.setIsDefaulted(Arg.getIsDefaulted());
+ return NewArg;
}
}
@@ -9463,6 +9532,30 @@ ASTContext::getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack,
return TemplateName(Subst);
}
+/// Retrieve the template name that represents a template name
+/// deduced from a specialization.
+TemplateName
+ASTContext::getDeducedTemplateName(TemplateName Underlying,
+ DefaultArguments DefaultArgs) const {
+ if (!DefaultArgs)
+ return Underlying;
+
+ llvm::FoldingSetNodeID ID;
+ DeducedTemplateStorage::Profile(ID, *this, Underlying, DefaultArgs);
+
+ void *InsertPos = nullptr;
+ DeducedTemplateStorage *DTS =
+ DeducedTemplates.FindNodeOrInsertPos(ID, InsertPos);
+ if (!DTS) {
+ void *Mem = Allocate(sizeof(DeducedTemplateStorage) +
+ sizeof(TemplateArgument) * DefaultArgs.Args.size(),
+ alignof(DeducedTemplateStorage));
+ DTS = new (Mem) DeducedTemplateStorage(Underlying, DefaultArgs);
+ DeducedTemplates.InsertNode(DTS, InsertPos);
+ }
+ return TemplateName(DTS);
+}
+
/// getFromTargetType - Given one of the integer types provided by
/// TargetInfo, produce the corresponding type. The unsigned @p Type
/// is actually a value of type @c TargetInfo::IntType.
@@ -12567,22 +12660,24 @@ static T *getCommonDeclChecked(T *X, T *Y) {
}
static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X,
- TemplateName Y) {
+ TemplateName Y,
+ bool IgnoreDeduced = false) {
if (X.getAsVoidPointer() == Y.getAsVoidPointer())
return X;
// FIXME: There are cases here where we could find a common template name
// with more sugar. For example one could be a SubstTemplateTemplate*
// replacing the other.
- TemplateName CX = Ctx.getCanonicalTemplateName(X);
+ TemplateName CX = Ctx.getCanonicalTemplateName(X, IgnoreDeduced);
if (CX.getAsVoidPointer() !=
Ctx.getCanonicalTemplateName(Y).getAsVoidPointer())
return TemplateName();
return CX;
}
-static TemplateName
-getCommonTemplateNameChecked(ASTContext &Ctx, TemplateName X, TemplateName Y) {
- TemplateName R = getCommonTemplateName(Ctx, X, Y);
+static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx,
+ TemplateName X, TemplateName Y,
+ bool IgnoreDeduced) {
+ TemplateName R = getCommonTemplateName(Ctx, X, Y, IgnoreDeduced);
assert(R.getAsVoidPointer() != nullptr);
return R;
}
@@ -13069,7 +13164,8 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
TY->template_arguments());
return Ctx.getTemplateSpecializationType(
::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
- TY->getTemplateName()),
+ TY->getTemplateName(),
+ /*IgnoreDeduced=*/true),
As, X->getCanonicalTypeInternal());
}
case Type::Decltype: {
@@ -13297,8 +13393,9 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
case Type::TemplateSpecialization: {
const auto *TX = cast<TemplateSpecializationType>(X),
*TY = cast<TemplateSpecializationType>(Y);
- TemplateName CTN = ::getCommonTemplateName(Ctx, TX->getTemplateName(),
- TY->getTemplateName());
+ TemplateName CTN =
+ ::getCommonTemplateName(Ctx, TX->getTemplateName(),
+ TY->getTemplateName(), /*IgnoreDeduced=*/true);
if (!CTN.getAsVoidPointer())
return QualType();
SmallVector<TemplateArgument, 8> Args;
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 0680ff5e3a38..15c3efe42127 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -1114,8 +1114,8 @@ class TemplateDiff {
// These functions build up the template diff tree, including functions to
// retrieve and compare template arguments.
- static const TemplateSpecializationType *GetTemplateSpecializationType(
- ASTContext &Context, QualType Ty) {
+ static const TemplateSpecializationType *
+ GetTemplateSpecializationType(ASTContext &Context, QualType Ty) {
if (const TemplateSpecializationType *TST =
Ty->getAs<TemplateSpecializationType>())
return TST;
@@ -1159,7 +1159,7 @@ class TemplateDiff {
if (!FromArgTST || !ToArgTST)
return true;
- if (!hasSameTemplate(FromArgTST, ToArgTST))
+ if (!hasSameTemplate(Context, FromArgTST, ToArgTST))
return true;
return false;
@@ -1371,11 +1371,17 @@ class TemplateDiff {
/// argument info into a tree.
void DiffTemplate(const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
+ // FIXME: With P3310R0, A TST formed from a DeducedTemplateName might
+ // differ in template arguments which were not written.
// Begin descent into diffing template tree.
TemplateParameterList *ParamsFrom =
- FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
+ FromTST->getTemplateName()
+ .getAsTemplateDecl(/*IgnoreDeduced=*/true)
+ ->getTemplateParameters();
TemplateParameterList *ParamsTo =
- ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
+ ToTST->getTemplateName()
+ .getAsTemplateDecl(/*IgnoreDeduced=*/true)
+ ->getTemplateParameters();
unsigned TotalArgs = 0;
for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
@@ -1427,20 +1433,24 @@ class TemplateDiff {
/// hasSameBaseTemplate - Returns true when the base templates are the same,
/// even if the template arguments are not.
- static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST,
+ static bool hasSameBaseTemplate(ASTContext &Context,
+ const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
- return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() ==
- ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl();
+ return Context.getCanonicalTemplateName(FromTST->getTemplateName(),
+ /*IgnoreDeduced=*/true) ==
+ Context.getCanonicalTemplateName(ToTST->getTemplateName(),
+ /*IgnoreDeduced=*/true);
}
/// hasSameTemplate - Returns true if both types are specialized from the
/// same template declaration. If they come from different template aliases,
/// do a parallel ascension search to determine the highest template alias in
/// common and set the arguments to them.
- static bool hasSameTemplate(const TemplateSpecializationType *&FromTST,
+ static bool hasSameTemplate(ASTContext &Context,
+ const TemplateSpecializationType *&FromTST,
const TemplateSpecializationType *&ToTST) {
// Check the top templates if they are the same.
- if (hasSameBaseTemplate(FromTST, ToTST))
+ if (hasSameBaseTemplate(Context, FromTST, ToTST))
return true;
// Create vectors of template aliases.
@@ -1455,14 +1465,14 @@ class TemplateDiff {
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
// Check if the lowest template types are the same. If not, return.
- if (!hasSameBaseTemplate(*FromIter, *ToIter))
+ if (!hasSameBaseTemplate(Context, *FromIter, *ToIter))
return false;
// Begin searching up the template aliases. The bottom most template
// matches so move up until one pair does not match. Use the template
// right before that one.
for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) {
- if (!hasSameBaseTemplate(*FromIter, *ToIter))
+ if (!hasSameBaseTemplate(Context, *FromIter, *ToIter))
break;
}
@@ -2123,7 +2133,7 @@ public:
return;
// Different base templates.
- if (!hasSameTemplate(FromOrigTST, ToOrigTST)) {
+ if (!hasSameTemplate(Context, FromOrigTST, ToOrigTST)) {
return;
}
@@ -2131,10 +2141,11 @@ public:
ToQual -= QualType(ToOrigTST, 0).getQualifiers();
// Same base template, but different arguments.
- Tree.SetTemplateDiff(FromOrigTST->getTemplateName().getAsTemplateDecl(),
- ToOrigTST->getTemplateName().getAsTemplateDecl(),
- FromQual, ToQual, false /*FromDefault*/,
- false /*ToDefault*/);
+ Tree.SetTemplateDiff(
+ FromOrigTST->getTemplateName().getAsTemplateDecl(
+ /*IgnoreDeduced=*/true),
+ ToOrigTST->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true),
+ FromQual, ToQual, false /*FromDefault*/, false /*ToDefault*/);
DiffTemplate(FromOrigTST, ToOrigTST);
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 1b67feaae887..3061d7abefbd 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -9891,6 +9891,21 @@ Expected<TemplateName> ASTImporter::Import(TemplateName From) {
return UsingOrError.takeError();
return TemplateName(cast<UsingShadowDecl>(*UsingOrError));
}
+ case TemplateName::DeducedTemplate: {
+ DeducedTemplateStorage *S = From.getAsDeducedTemplateName();
+ auto UnderlyingOrError = Import(S->getUnderlying());
+ if (!UnderlyingOrError)
+ return UnderlyingOrError.takeError();
+
+ ASTNodeImporter Importer(*this);
+ DefaultArguments FromDefArgs = S->getDefaultArguments();
+ SmallVector<TemplateArgument, 8> ToTemplateArgs;
+ if (Error Err =
+ Importer.ImportTemplateArguments(FromDefArgs.Args, ToTemplateArgs))
+ return std::move(Err);
+ return ToContext.getDeducedTemplateName(
+ *UnderlyingOrError, {FromDefArgs.StartPos, ToTemplateArgs});
+ }
}
llvm_unreachable("Invalid template name kind");
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 37555c324282..d81f45d5720a 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -645,6 +645,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// It is sufficient to check value of getAsTemplateDecl.
break;
+ case TemplateName::DeducedTemplate:
+ // FIXME: We can't reach here.
+ llvm_unreachable("unimplemented");
}
return true;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 9d0a835a12c4..24229b78f3e8 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -350,7 +350,8 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template =
- Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl(
+ /*IgnoreDeduced=*/true))
LV.merge(getLVForDecl(Template, computation));
continue;
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 203db72c4373..7916ab97b581 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2385,6 +2385,16 @@ void CXXNameMangler::mangleType(TemplateName TN) {
Out << "_SUBSTPACK_";
break;
}
+ case TemplateName::DeducedTemplate: {
+ DeducedTemplateStorage *S = TN.getAsDeducedTemplateName();
+ mangleType(S->getUnderlying());
+ auto [StartPos, Args] = S->getDefaultArguments();
+ mangleNumber(StartPos);
+ Out << 'I';
+ for (unsigned I = 0; I != Args.size(); ++I)
+ mangleTemplateArg(Args[I], /*NeedExactType=*/true);
+ Out << 'E';
+ }
}
addSubstitution(TN);
@@ -2502,6 +2512,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case TemplateName::OverloadedTemplate:
case TemplateName::AssumedTemplate:
case TemplateName::DependentTemplate:
+ case TemplateName::DeducedTemplate:
llvm_unreachable("invalid base for a template specialization type");
case TemplateName::SubstTemplateTemplateParm: {
@@ -5892,7 +5903,8 @@ struct CXXNameMangler::TemplateArgManglingInfo {
// that of the template.
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
TemplateName ArgTemplateName = Arg.getAsTemplateOrTemplatePattern();
- const TemplateDecl *ArgTemplate = ArgTemplateName.getAsTemplateDecl();
+ const TemplateDecl *ArgTemplate =
+ ArgTemplateName.getAsTemplateDecl(/*IgnoreDeduced=*/true);
if (!ArgTemplate)
return true;
@@ -6759,9 +6771,6 @@ bool CXXNameMangler::mangleSubstitution(QualType T) {
}
bool CXXNameMangler::mangleSubstitution(TemplateName Template) {
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleSubstitution(TD);
-
Template = Context.getASTContext().getCanonicalTemplateName(Template);
return mangleSubstitution(
reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
@@ -6931,9 +6940,6 @@ void CXXNameMangler::addSubstitution(QualType T) {
}
void CXXNameMangler::addSubstitution(TemplateName Template) {
- if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return addSubstitution(TD);
-
Template = Context.getASTContext().getCanonicalTemplateName(Template);
addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
}
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 1249531eab09..2366cd5a441a 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -161,6 +161,7 @@ void ODRHash::AddTemplateName(TemplateName Name) {
case TemplateName::SubstTemplateTemplateParm:
case TemplateName::SubstTemplateTemplateParmPack:
case TemplateName::UsingTemplate:
+ case TemplateName::DeducedTemplate:
break;
}
}
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index d4e8a8971a97..044a1a92469a 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -34,6 +34,30 @@
using namespace clang;
+DeducedTemplateStorage::DeducedTemplateStorage(TemplateName Underlying,
+ const DefaultArguments &DefArgs)
+ : UncommonTemplateNameStorage(Deduced, /*Index=*/DefArgs.StartPos,
+ DefArgs.Args.size()),
+ Underlying(Underlying) {
+ llvm::copy(DefArgs.Args, reinterpret_cast<TemplateArgument *>(this + 1));
+}
+
+void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Context) const {
+ Profile(ID, Context, Underlying, getDefaultArguments());
+}
+
+void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Context,
+ TemplateName Underlying,
+ const DefaultArguments &DefArgs) {
+ Underlying.Profile(ID);
+ ID.AddInteger(DefArgs.StartPos);
+ ID.AddInteger(DefArgs.Args.size());
+ for (const TemplateArgument &Arg : DefArgs.Args)
+ Arg.Profile(ID, Context);
+}
+
TemplateArgument
SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
return TemplateArgument(llvm::ArrayRef(Arguments, Bits.Data));
@@ -115,6 +139,8 @@ TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
TemplateName::TemplateName(UsingShadowDecl *Using) : Storage(Using) {}
+TemplateName::TemplateName(DeducedTemplateStorage *Deduced)
+ : Storage(Deduced) {}
bool TemplateName::isNull() const { return Storage.isNull(); }
@@ -139,28 +165,63 @@ TemplateName::NameKind TemplateName::getKind() const {
return AssumedTemplate;
if (uncommon->getAsSubstTemplateTemplateParm())
return SubstTemplateTemplateParm;
+ if (uncommon->getAsDeducedTemplateName())
+ return DeducedTemplate;
+
+ assert(uncommon->getAsSubstTemplateTemplateParmPack() != nullptr);
return SubstTemplateTemplateParmPack;
}
-TemplateDecl *TemplateName::getAsTemplateDecl() const {
- if (Decl *TemplateOrUsing = Storage.dyn_cast<Decl *>()) {
- if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(TemplateOrUsing))
- return cast<TemplateDecl>(USD->getTargetDecl());
-
- assert(isa<TemplateDecl>(TemplateOrUsing));
- return cast<TemplateDecl>(TemplateOrUsing);
- }
+TemplateDecl *TemplateName::getAsTemplateDecl(bool IgnoreDeduced) const {
+ TemplateName Name = *this;
+ while (std::optional<TemplateName> UnderlyingOrNone =
+ Name.desugar(IgnoreDeduced))
+ Name = *UnderlyingOrNone;
- if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
- return QTN->getUnderlyingTemplate().getAsTemplateDecl();
+ if (!IgnoreDeduced)
+ assert(Name.getAsDeducedTemplateName() == nullptr &&
+ "Unexpected canonical DeducedTemplateName; Did you mean to use "
+ "getTemplateDeclAndDefaultArgs instead?");
- if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
- return sub->getReplacement().getAsTemplateDecl();
+ return cast_if_present<TemplateDecl>(Name.Storage.dyn_cast<Decl *>());
+}
- if (UsingShadowDecl *USD = getAsUsingShadowDecl())
- return cast<TemplateDecl>(USD->getTargetDecl());
+std::pair<TemplateDecl *, DefaultArguments>
+TemplateName::getTemplateDeclAndDefaultArgs() const {
+ for (TemplateName Name = *this; /**/; /**/) {
+ if (Name.getKind() == TemplateName::DeducedTemplate) {
+ DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName();
+ TemplateDecl *TD =
+ DTS->getUnderlying().getAsTemplateDecl(/*IgnoreDeduced=*/true);
+ DefaultArguments DefArgs = DTS->getDefaultArguments();
+ if (TD && DefArgs)
+ assert(DefArgs.StartPos + DefArgs.Args.size() <=
+ TD->getTemplateParameters()->size());
+ return {TD, DTS->getDefaultArguments()};
+ }
+ if (std::optional<TemplateName> UnderlyingOrNone =
+ Name.desugar(/*IgnoreDeduced=*/false)) {
+ Name = *UnderlyingOrNone;
+ continue;
+ }
+ return {cast_if_present<TemplateDecl>(Name.Storage.dyn_cast<Decl *>()), {}};
+ }
+}
- return nullptr;
+std::optional<TemplateName> TemplateName::desugar(bool IgnoreDeduced) const {
+ if (Decl *D = Storage.dyn_cast<Decl *>()) {
+ if (auto *USD = dyn_cast<UsingShadowDecl>(D))
+ return TemplateName(USD->getTargetDecl());
+ return std::nullopt;
+ }
+ if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
+ return QTN->getUnderlyingTemplate();
+ if (SubstTemplateTemplateParmStorage *S = getAsSubstTemplateTemplateParm())
+ return S->getReplacement();
+ if (IgnoreDeduced)
+ if (DeducedTemplateStorage *S = getAsDeducedTemplateName())
+ return S->getUnderlying();
+ return std::nullopt;
}
OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
@@ -214,26 +275,20 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
return nullptr;
}
+DeducedTemplateStorage *TemplateName::getAsDeducedTemplateName() const {
+ if (UncommonTemplateNameStorage *Uncommon =
+ Storage.dyn_cast<UncommonTemplateNameStorage *>())
+ return Uncommon->getAsDeducedTemplateName();
+
+ return nullptr;
+}
+
TemplateNameDependence TemplateName::getDependence() const {
- auto D = TemplateNameDependence::None;
switch (getKind()) {
- case TemplateName::NameKind::QualifiedTemplate:
- if (NestedNameSpecifier *NNS = getAsQualifiedTemplateName()->getQualifier())
- D |= toTemplateNameDependence(NNS->getDependence());
- break;
- case TemplateName::NameKind::DependentTemplate:
- D |= toTemplateNameDependence(
- getAsDependentTemplateName()->getQualifier()->getDependence());
- break;
- case TemplateName::NameKind::SubstTemplateTemplateParmPack:
- D |= TemplateNameDependence::UnexpandedPack;
- break;
- case TemplateName::NameKind::OverloadedTemplate:
- llvm_unreachable("overloaded templates shouldn't survive to here.");
- default:
- break;
- }
- if (TemplateDecl *Template = getAsTemplateDecl()) {
+ case NameKind::Template:
+ case NameKind::UsingTemplate: {
+ TemplateDecl *Template = getAsTemplateDecl();
+ auto D = TemplateNameDependence::None;
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) {
D |= TemplateNameDependence::DependentInstantiation;
if (TTP->isParameterPack())
@@ -246,10 +301,41 @@ TemplateNameDependence TemplateName::getDependence() const {
if (Template->getDeclContext() &&
Template->getDeclContext()->isDependentContext())
D |= TemplateNameDependence::DependentInstantiation;
- } else {
- D |= TemplateNameDependence::DependentInstantiation;
+ return D;
+ }
+ case NameKind::QualifiedTemplate: {
+ QualifiedTemplateName *S = getAsQualifiedTemplateName();
+ TemplateNameDependence D = S->getUnderlyingTemplate().getDependence();
+ if (NestedNameSpecifier *NNS = S->getQualifier())
+ D |= toTemplateNameDependence(NNS->getDependence());
+ return D;
+ }
+ case NameKind::DependentTemplate: {
+ DependentTemplateName *S = getAsDependentTemplateName();
+ auto D = TemplateNameDependence::DependentInstantiation;
+ D |= toTemplateNameDependence(S->getQualifier()->getDependence());
+ return D;
+ }
+ case NameKind::SubstTemplateTemplateParm: {
+ auto *S = getAsSubstTemplateTemplateParm();
+ return S->getReplacement().getDependence();
+ }
+ case NameKind::SubstTemplateTemplateParmPack:
+ return TemplateNameDependence::UnexpandedPack |
+ TemplateNameDependence::DependentInstantiation;
+ case NameKind::DeducedTemplate: {
+ DeducedTemplateStorage *DTS = getAsDeducedTemplateName();
+ TemplateNameDependence D = DTS->getUnderlying().getDependence();
+ for (const TemplateArgument &Arg : DTS->getDefaultArguments().Args)
+ D |= toTemplateNameDependence(Arg.getDependence());
+ return D;
+ }
+ case NameKind::AssumedTemplate:
+ return TemplateNameDependence::DependentInstantiation;
+ case NameKind::OverloadedTemplate:
+ llvm_unreachable("overloaded templates shouldn't survive to here.");
}
- return D;
+ llvm_unreachable("Unknown TemplateName kind");
}
bool TemplateName::isDependent() const {
@@ -331,6 +417,11 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
OS << *SubstPack->getParameterPack();
else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
Assumed->getDeclName().print(OS, Policy);
+ } else if (DeducedTemplateStorage *Deduced = getAsDeducedTemplateName()) {
+ Deduced->getUnderlying().print(OS, Policy);
+ DefaultArguments DefArgs = Deduced->getDefaultArguments();
+ OS << ":" << DefArgs.StartPos;
+ printTemplateArgumentList(OS, DefArgs.Args, Policy);
} else {
assert(getKind() == TemplateName::OverloadedTemplate);
OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index bd1e630cd904..992533672c77 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1198,6 +1198,18 @@ void TextNodeDumper::dumpBareTemplateName(TemplateName TN) {
dumpTemplateName(STS->getReplacement(), "replacement");
return;
}
+ case TemplateName::DeducedTemplate: {
+ OS << " deduced";
+ const DeducedTemplateStorage *DTS = TN.getAsDeducedTemplateName();
+ dumpTemplateName(DTS->getUnderlying(), "underlying");
+ AddChild("defaults", [=] {
+ auto [StartPos, Args] = DTS->getDefaultArguments();
+ OS << " start " << StartPos;
+ for (const TemplateArgument &Arg : Args)
+ AddChild([=] { Visit(Arg, SourceRange()); });
+ });
+ return;
+ }
// FIXME: Implement these.
case TemplateName::OverloadedTemplate:
OS << " overloaded";
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 656b733a13b0..6c777be6278a 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4293,7 +4293,8 @@ TemplateSpecializationType::TemplateSpecializationType(
T.getKind() == TemplateName::SubstTemplateTemplateParm ||
T.getKind() == TemplateName::SubstTemplateTemplateParmPack ||
T.getKind() == TemplateName::UsingTemplate ||
- T.getKind() == TemplateName::QualifiedTemplate) &&
+ T.getKind() == TemplateName::QualifiedTemplate ||
+ T.getKind() == TemplateName::DeducedTemplate) &&
"Unexpected template name for TemplateSpecializationType");
auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1);
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 4add4d3af69a..e995713d01dd 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1603,7 +1603,8 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
raw_ostream &OS, bool FullyQualify) {
IncludeStrongLifetimeRAII Strong(Policy);
- TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
+ TemplateDecl *TD =
+ T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true);
// FIXME: Null TD never exercised in test suite.
if (FullyQualify && TD) {
if (!Policy.SuppressScope)
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d38700d56e4f..20f89c484980 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4504,8 +4504,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
for (auto const &Base : ClassDecl->bases()) {
auto BaseTemplate =
Base.getType()->getAs<TemplateSpecializationType>();
- if (BaseTemplate && Context.hasSameTemplateName(
- BaseTemplate->getTemplateName(), TN)) {
+ if (BaseTemplate &&
+ Context.hasSameTemplateName(BaseTemplate->getTemplateName(), TN,
+ /*IgnoreDeduced=*/true)) {
Diag(IdLoc, diag::ext_unqualified_base_class)
<< SourceRange(IdLoc, Init->getSourceRange().getEnd());
BaseType = Base.getType();
@@ -11542,8 +11543,8 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
if (auto RetTST =
TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) {
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
- bool TemplateMatches =
- Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
+ bool TemplateMatches = Context.hasSameTemplateName(
+ SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);
const QualifiedTemplateName *Qualifiers =
SpecifiedName.getAsQualifiedTemplateName();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index a032e3ec6f63..2296750cebc7 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4580,8 +4580,8 @@ Sema::findFailedBooleanCondition(Expr *Cond) {
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
- DependentTemplateName *DTN
- = Name.getUnderlying().getAsDependentTemplateName();
+ DependentTemplateName *DTN =
+ Name.getUnderlying().getAsDependentTemplateName();
if (DTN && DTN->isIdentifier())
// When building a template-id where the template-name is dependent,
// assume the template is a type template. Either our assumption is
@@ -4592,10 +4592,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TemplateArgs.arguments());
if (Name.getAsAssumedTemplateName() &&
- resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc))
+ resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc))
return QualType();
- TemplateDecl *Template = Name.getAsTemplateDecl();
+ auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
+
if (!Template || isa<FunctionTemplateDecl>(Template) ||
isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
@@ -4613,8 +4614,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
- if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false,
- SugaredConverted, CanonicalConverted,
+ if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
+ DefaultArgs, false, SugaredConverted,
+ CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return QualType();
@@ -5280,7 +5282,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// template.
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
- false, SugaredConverted, CanonicalConverted,
+ /*DefaultArgs=*/{}, false, SugaredConverted,
+ CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -5447,8 +5450,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
- const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- SugaredConverted, CanonicalConverted,
+ const_cast<TemplateArgumentListInfo &>(TemplateArgs),
+ /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -5642,6 +5645,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
if (CheckTemplateArgumentList(
NamedConcept, ConceptNameInfo.getLoc(),
const_cast<TemplateArgumentListInfo &>(*TemplateArgs),
+ /*DefaultArgs=*/{},
/*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/false))
return ExprError();
@@ -6610,7 +6614,8 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
- TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
+ TemplateArgumentListInfo &TemplateArgs, const DefaultArguments &DefaultArgs,
+ bool PartialTemplateArgs,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied,
@@ -6638,9 +6643,29 @@ bool Sema::CheckTemplateArgumentList(
SmallVector<TemplateArgument, 2> CanonicalArgumentPack;
unsigned ArgIdx = 0, NumArgs = NewArgs.size();
LocalInstantiationScope InstScope(*this, true);
- for (TemplateParameterList::iterator Param = Params->begin(),
- ParamEnd = Params->end();
- Param != ParamEnd; /* increment in loop */) {
+ for (TemplateParameterList::iterator ParamBegin = Params->begin(),
+ ParamEnd = Params->end(),
+ Param = ParamBegin;
+ Param != ParamEnd;
+ /* increment in loop */) {
+ if (size_t ParamIdx = Param - ParamBegin;
+ DefaultArgs && ParamIdx >= DefaultArgs.StartPos) {
+ // All written arguments should have been consumed by this point.
+ assert(ArgIdx == NumArgs && "bad default argument deduction");
+ // FIXME: Don't ignore parameter packs.
+ if (ParamIdx == DefaultArgs.StartPos && !(*Param)->isParameterPack()) {
+ assert(Param + DefaultArgs.Args.size() <= ParamEnd);
+ // Default arguments from a DeducedTemplateName are already converted.
+ for (const TemplateArgument &DefArg : DefaultArgs.Args) {
+ SugaredConverted.push_back(DefArg);
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(DefArg));
+ ++Param;
+ }
+ continue;
+ }
+ }
+
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
if (std::optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
@@ -6854,6 +6879,7 @@ bool Sema::CheckTemplateArgumentList(
CTAK_Specified))
return true;
+ SugaredConverted.back().setIsDefaulted(true);
CanonicalConverted.back().setIsDefaulted(true);
// Core issue 150 (assumed resolution): if this is a template template
@@ -8454,7 +8480,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateArgumentLoc &Arg,
bool IsDeduced) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
- TemplateDecl *Template = Name.getAsTemplateDecl();
+ auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
if (!Template) {
// Any dependent template name is fine.
assert(Name.isDependent() && "Non-dependent template isn't a declaration?");
@@ -8505,7 +8531,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
return false;
if (isTemplateTemplateParameterAtLeastAsSpecializedAs(
- Params, Template, Arg.getLocation(), IsDeduced)) {
+ Params, Template, DefaultArgs, Arg.getLocation(), IsDeduced)) {
// P2113
// C++20[temp.func.order]p2
// [...] If both deductions succeed, the partial ordering selects the
@@ -9591,7 +9617,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// template.
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
- false, SugaredConverted, CanonicalConverted,
+ /*DefaultArgs=*/{},
+ /*PartialTemplateArgs=*/false, SugaredConverted,
+ CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -10963,7 +10991,8 @@ DeclResult Sema::ActOnExplicitInstantiation(
// template.
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
- false, SugaredConverted, CanonicalConverted,
+ /*DefaultArgs=*/{}, false, SugaredConverted,
+ CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index a432918cbf5e..3efc3030fc26 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -509,67 +509,12 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced);
}
-/// Create a shallow copy of a given template parameter declaration, with
-/// empty source locations and using the given TemplateArgument as it's
-/// default argument.
-///
-/// \returns The new template parameter declaration.
-static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A,
- TemplateArgument Default) {
- switch (A->getKind()) {
- case Decl::TemplateTypeParm: {
- auto *T = cast<TemplateTypeParmDecl>(A);
- auto *R = TemplateTypeParmDecl::Create(
- S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(),
- T->getDepth(), T->getIndex(), T->getIdentifier(),
- T->wasDeclaredWithTypename(), T->isParameterPack(),
- T->hasTypeConstraint());
- R->setDefaultArgument(
- S.Context,
- S.getTrivialTemplateArgumentLoc(Default, QualType(), SourceLocation()));
- if (R->hasTypeConstraint()) {
- auto *C = R->getTypeConstraint();
- R->setTypeConstraint(C->getConceptReference(),
- C->getImmediatelyDeclaredConstraint());
- }
- return R;
- }
- case Decl::NonTypeTemplateParm: {
- auto *T = cast<NonTypeTemplateParmDecl>(A);
- auto *R = NonTypeTemplateParmDecl::Create(
- S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(),
- T->getDepth(), T->getIndex(), T->getIdentifier(), T->getType(),
- T->isParameterPack(), T->getTypeSourceInfo());
- R->setDefaultArgument(S.Context,
- S.getTrivialTemplateArgumentLoc(
- Default, Default.getNonTypeTemplateArgumentType(),
- SourceLocation()));
- if (auto *PTC = T->getPlaceholderTypeConstraint())
- R->setPlaceholderTypeConstraint(PTC);
- return R;
- }
- case Decl::TemplateTemplateParm: {
- auto *T = cast<TemplateTemplateParmDecl>(A);
- auto *R = TemplateTemplateParmDecl::Create(
- S.Context, A->getDeclContext(), SourceLocation(), T->getDepth(),
- T->getIndex(), T->isParameterPack(), T->getIdentifier(),
- T->wasDeclaredWithTypename(), T->getTemplateParameters());
- R->setDefaultArgument(
- S.Context,
- S.getTrivialTemplateArgumentLoc(Default, QualType(), SourceLocation()));
- return R;
- }
- default:
- llvm_unreachable("Unexpected Decl Kind");
- }
-}
-
static TemplateDeductionResult
-DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
- TemplateName Param, TemplateName Arg,
- TemplateDeductionInfo &Info,
- ArrayRef<TemplateArgument> DefaultArguments,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+DeduceTemplateNames(Sema &S, TemplateParameterList *TemplateParams,
+ TemplateName Param, TemplateName Arg,
+ TemplateDeductionInfo &Info,
+ ArrayRef<TemplateArgument> DefaultArguments,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
if (!ParamDecl) {
// The parameter type is dependent and is not a template template parameter,
@@ -582,42 +527,28 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
if (TempParam->getDepth() != Info.getDeducedDepth())
return TemplateDeductionResult::Success;
- auto NewDeduced = DeducedTemplateArgument(Arg);
- // Provisional resolution for CWG2398: If Arg is also a template template
- // param, and it names a template specialization, then we deduce a
- // synthesized template template parameter based on A, but using the TS's
- // arguments as defaults.
- if (auto *TempArg = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Arg.getAsTemplateDecl())) {
- assert(!TempArg->isExpandedParameterPack());
-
- TemplateParameterList *As = TempArg->getTemplateParameters();
- if (DefaultArguments.size() != 0) {
- assert(DefaultArguments.size() <= As->size());
- SmallVector<NamedDecl *, 4> Params(As->size());
- for (unsigned I = 0; I < DefaultArguments.size(); ++I)
- Params[I] = getTemplateParameterWithDefault(S, As->getParam(I),
- DefaultArguments[I]);
- for (unsigned I = DefaultArguments.size(); I < As->size(); ++I)
- Params[I] = As->getParam(I);
- // FIXME: We could unique these, and also the parameters, but we don't
- // expect programs to contain a large enough amount of these deductions
- // for that to be worthwhile.
- auto *TPL = TemplateParameterList::Create(
- S.Context, SourceLocation(), SourceLocation(), Params,
- SourceLocation(), As->getRequiresClause());
- NewDeduced = DeducedTemplateArgument(
- TemplateName(TemplateTemplateParmDecl::Create(
- S.Context, TempArg->getDeclContext(), SourceLocation(),
- TempArg->getDepth(), TempArg->getPosition(),
- TempArg->isParameterPack(), TempArg->getIdentifier(),
- TempArg->wasDeclaredWithTypename(), TPL)));
+ ArrayRef<NamedDecl *> Params =
+ ParamDecl->getTemplateParameters()->asArray();
+ unsigned StartPos = 0;
+ for (unsigned I = 0, E = std::min(Params.size(), DefaultArguments.size());
+ I < E; ++I) {
+ if (Params[I]->isParameterPack()) {
+ StartPos = DefaultArguments.size();
+ break;
}
+ StartPos = I + 1;
}
- DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
- Deduced[TempParam->getIndex()],
- NewDeduced);
+ // Provisional resolution for CWG2398: If Arg names a template
+ // specialization, then we deduce a synthesized template name
+ // based on A, but using the TS's extra arguments, relative to P, as
+ // defaults.
+ DeducedTemplateArgument NewDeduced =
+ TemplateArgument(S.Context.getDeducedTemplateName(
+ Arg, {StartPos, DefaultArguments.drop_front(StartPos)}));
+
+ DeducedTemplateArgument Result = checkDeducedTemplateArguments(
+ S.Context, Deduced[TempParam->getIndex()], NewDeduced);
if (Result.isNull()) {
Info.Param = TempParam;
Info.FirstArg = Deduced[TempParam->getIndex()];
@@ -630,7 +561,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
}
// Verify that the two template names are equivalent.
- if (S.Context.hasSameTemplateName(Param, Arg))
+ if (S.Context.hasSameTemplateName(
+ Param, Arg, /*IgnoreDeduced=*/DefaultArguments.size() != 0))
return TemplateDeductionResult::Success;
// Mismatch of non-dependent template parameter to argument.
@@ -720,8 +652,9 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
->template_arguments();
// Perform template argument deduction for the template name.
- if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
- AResolved, Deduced);
+ if (auto Result =
+ DeduceTemplateNames(S, TemplateParams, TNP, TNA, Info,
+ /*DefaultArguments=*/AResolved, Deduced);
Result != TemplateDeductionResult::Success)
return Result;
@@ -751,9 +684,9 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
*NNS, false, TemplateName(SA->getSpecializedTemplate()));
// Perform template argument deduction for the template name.
- if (auto Result =
- DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info,
- SA->getTemplateArgs().asArray(), Deduced);
+ if (auto Result = DeduceTemplateNames(
+ S, TemplateParams, TNP, TNA, Info,
+ /*DefaultArguments=*/SA->getTemplateArgs().asArray(), Deduced);
Result != TemplateDeductionResult::Success)
return Result;
@@ -2443,9 +2376,9 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
case TemplateArgument::Template:
if (A.getKind() == TemplateArgument::Template)
- return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(),
- A.getAsTemplate(), Info,
- /*DefaultArguments=*/{}, Deduced);
+ return DeduceTemplateNames(S, TemplateParams, P.getAsTemplate(),
+ A.getAsTemplate(), Info,
+ /*DefaultArguments=*/{}, Deduced);
Info.FirstArg = P;
Info.SecondArg = A;
return TemplateDeductionResult::NonDeducedMismatch;
@@ -3194,7 +3127,7 @@ FinishTemplateArgumentDeduction(
SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
CanonicalConvertedInstArgs;
if (S.CheckTemplateArgumentList(
- Template, Partial->getLocation(), InstArgs, false,
+ Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false,
SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
/*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
return ConstraintsNotSatisfied
@@ -3516,8 +3449,8 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
return TemplateDeductionResult::InstantiationDepth;
if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(),
- ExplicitTemplateArgs, true, SugaredBuilder,
- CanonicalBuilder,
+ ExplicitTemplateArgs, /*DefaultArgs=*/{}, true,
+ SugaredBuilder, CanonicalBuilder,
/*UpdateArgsWithConversions=*/false) ||
Trap.hasErrorOccurred()) {
unsigned Index = SugaredBuilder.size();
@@ -5127,9 +5060,9 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
- if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
- /*PartialTemplateArgs=*/false,
- SugaredConverted, CanonicalConverted))
+ if (S.CheckTemplateArgumentList(
+ Concept, SourceLocation(), TemplateArgs, /*DefaultArgs=*/{},
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted))
return true;
MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted,
/*Final=*/false);
@@ -6362,8 +6295,8 @@ bool Sema::isMoreSpecializedThanPrimary(
}
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
- TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc,
- bool IsDeduced) {
+ TemplateParameterList *P, TemplateDecl *AArg,
+ const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced) {
// C++1z [temp.arg.template]p4: (DR 150)
// A template template-parameter P is at least as specialized as a
// template template-argument A if, given the following rewrite to two
@@ -6411,8 +6344,9 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
// If the rewrite produces an invalid type, then P is not at least as
// specialized as A.
SmallVector<TemplateArgument, 4> SugaredPArgs;
- if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, SugaredPArgs,
- PArgs, /*UpdateArgsWithConversions=*/true,
+ if (CheckTemplateArgumentList(AArg, Loc, PArgList, DefaultArgs, false,
+ SugaredPArgs, PArgs,
+ /*UpdateArgsWithConversions=*/true,
/*ConstraintsNotSatisfied=*/nullptr,
/*PartialOrderTTP=*/true) ||
Trap.hasErrorOccurred())
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 0681520764d9..26b2fa793b48 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3878,10 +3878,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this
// class template.
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
- if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, D->getLocation(),
- InstTemplateArgs, false,
- SugaredConverted, CanonicalConverted,
- /*UpdateArgsWithConversions=*/true))
+ if (SemaRef.CheckTemplateArgumentList(
+ InstClassTemplate, D->getLocation(), InstTemplateArgs,
+ /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/true))
return nullptr;
// Figure out where to insert this class template explicit specialization
@@ -3986,10 +3986,10 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
- if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
- VarTemplateArgsInfo, false,
- SugaredConverted, CanonicalConverted,
- /*UpdateArgsWithConversions=*/true))
+ if (SemaRef.CheckTemplateArgumentList(
+ InstVarTemplate, D->getLocation(), VarTemplateArgsInfo,
+ /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/true))
return nullptr;
// Check whether we've already seen a declaration of this specialization.
@@ -4254,6 +4254,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (SemaRef.CheckTemplateArgumentList(
ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs,
+ /*DefaultArgs=*/{},
/*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted))
return nullptr;
@@ -4365,9 +4366,10 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
// Check that the template argument list is well-formed for this
// class template.
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
- if (SemaRef.CheckTemplateArgumentList(
- VarTemplate, PartialSpec->getLocation(), InstTemplateArgs,
- /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted))
+ if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(),
+ InstTemplateArgs, /*DefaultArgs=*/{},
+ /*PartialTemplateArgs=*/false,
+ SugaredConverted, CanonicalConverted))
return nullptr;
// Check these arguments are valid for a template partial specialization.
diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp
index a5b39fe5c51f..bc3943125388 100644
--- a/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp
@@ -28,13 +28,14 @@ namespace StdExample {
{ /* ... */ }
template<template<class> class TT>
- void f(TT<int>); // expected-note {{candidate template ignored}}
+ void f(TT<int>);
template<template<class,class> class TT>
void g(TT<int, Alloc<int>>);
int h() {
- f(v); // expected-error {{no matching function for call to 'f'}}
+ f(v); // OK: TT = vector, Alloc<int> is used as the default argument for the
+ // second parameter.
g(v); // OK: TT = vector
}
diff --git a/clang/test/CodeGenCXX/mangle-cwg2398.cpp b/clang/test/CodeGenCXX/mangle-cwg2398.cpp
new file mode 100644
index 000000000000..a8a0aed17c70
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-cwg2398.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-pc -emit-llvm -o - %s | FileCheck %s
+
+template<class T, class U> struct A {};
+
+template<template<class> class TT> void f(TT<int>);
+
+// CHECK-LABEL: define{{.*}} void @_Z1zv(
+void z() {
+ f(A<int, double>());
+ // CHECK: call void @_Z1fITtTyE1A1IdEEvT_IiE()
+}
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 7675d4287cb8..51a7c7b3612e 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -4,12 +4,11 @@
namespace issue1 {
template<class T, class U = T> class B {};
template<template<class> class P, class T> void f(P<T>);
- // new-note@-1 {{deduced type 'B<[...], (default) int>' of 1st parameter does not match adjusted type 'B<[...], float>' of argument [with P = B, T = int]}}
- // old-note@-2 2{{template template argument has different template parameters}}
+ // old-note@-1 2{{template template argument has different template parameters}}
void g() {
f(B<int>()); // old-error {{no matching function for call}}
- f(B<int,float>()); // expected-error {{no matching function for call}}
+ f(B<int,float>()); // old-error {{no matching function for call}}
}
} // namespace issue1
@@ -65,13 +64,10 @@ namespace class_template {
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>;
- // new-note@-1 {{partial specialization matches}}
template <class T6, class T7> struct B<A<T6, T7>> {};
- // new-note@-1 {{partial specialization matches}}
template struct B<A<int>>;
- // new-error@-1 {{ambiguous partial specialization}}
} // namespace class_template
namespace type_pack1 {
@@ -272,16 +268,19 @@ namespace classes {
template<template<class> class TT> auto f(TT<int> a) { return a; }
// old-note@-1 2{{template template argument has different template parameters}}
- // new-note@-2 2{{substitution failure: too few template arguments}}
A<int, float> v1;
A<int, double> v2;
using X = decltype(f(v1));
- // expected-error@-1 {{no matching function for call}}
+ // old-error@-1 {{no matching function for call}}
+ // new-note@-2 {{previous definition is here}}
+ // FIXME: The template differ needs to be taught to also
+ // look at differences in arguments which were not written.
using X = decltype(f(v2));
- // expected-error@-1 {{no matching function for call}}
+ // old-error@-1 {{no matching function for call}}
+ // new-error@-2 {{different types ('A<...>' vs 'A<...>')}}
} // namespace canon
namespace expr {
template <class T1, int E1> struct A {
@@ -289,12 +288,11 @@ namespace classes {
};
template <template <class T3> class TT> void f(TT<int> v) {
// old-note@-1 {{template template argument has different template parameters}}
- // new-note@-2 {{substitution failure: too few template arguments}}
static_assert(v.val == 3);
};
void test() {
f(A<int, 3>());
- // expected-error@-1 {{no matching function for call}}
+ // old-error@-1 {{no matching function for call}}
}
} // namespace expr
namespace packs {
@@ -304,14 +302,54 @@ namespace classes {
template <template <class T3> class TT> void f(TT<int> v) {
// old-note@-1 {{template template argument has different template parameters}}
- // new-note@-2 {{deduced type 'A<[...], (no argument), (no argument), (no argument)>' of 1st parameter does not match adjusted type 'A<[...], void, void, void>' of argument [with TT = A]}}
+ // new-note@-2 {{deduced type 'A<[...], (no argument), (no argument), (no argument)>' of 1st parameter does not match adjusted type 'A<[...], void, void, void>' of argument [with TT = A:1<void, void, void>]}}
static_assert(v.val == 3);
};
void test() {
+ // FIXME: Needs deduction of defaulted template parameter packs.
f(A<int, void, void, void>());
// expected-error@-1 {{no matching function for call}}
}
} // namespace packs
+ namespace nested {
+ template <class T1, int V1, int V2> struct A {
+ using type = T1;
+ static constexpr int v1 = V1, v2 = V2;
+ };
+
+ template <template <class T1> class TT1> auto f(TT1<int>) {
+ return TT1<float>();
+ }
+
+ template <template <class T2, int V3> class TT2> auto g(TT2<double, 1>) {
+ // old-note@-1 {{template template argument has different template parameters}}
+ return f(TT2<int, 2>());
+ }
+
+ using B = decltype(g(A<double, 1, 3>()));
+ // old-error@-1 {{no matching function for call}}
+
+ using X = B::type; // old-error {{undeclared identifier 'B'}}
+ using X = float;
+ static_assert(B::v1 == 2); // old-error {{undeclared identifier 'B'}}
+ static_assert(B::v2 == 3); // old-error {{undeclared identifier 'B'}}
+ }
+ namespace defaulted {
+ template <class T1, class T2 = T1*> struct A {
+ using type = T2;
+ };
+
+ template <template <class> class TT> TT<float> f(TT<int>);
+ // old-note@-1 2{{template template argument has different template parameters}}
+
+ using X = int*;
+ using X = decltype(f(A<int>()))::type;
+ // old-error@-1 {{no matching function for call}}
+
+ using Y = double*;
+ using Y = decltype(f(A<int, double*>()))::type;
+ // old-error@-1 {{no matching function for call}}
+ } // namespace defaulted
} // namespace classes
namespace regression1 {
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 35312e3d2ae7..b39e4c195c9e 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1557,6 +1557,9 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
return Visit(MakeCursorTemplateRef(
Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(), Loc,
TU));
+
+ case TemplateName::DeducedTemplate:
+ llvm_unreachable("DeducedTemplate shouldn't appear in source");
}
llvm_unreachable("Invalid TemplateName::Kind!");
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 92f9bae6cb06..392ef9bd85a4 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -1002,6 +1002,23 @@ TEST_P(ImportDecl, ImportUsingTemplate) {
hasAnyTemplateArgumentLoc(templateArgumentLoc())))))))));
}
+TEST_P(ImportDecl, ImportDeducedTemplateName) {
+ MatchVerifier<Decl> Verifier;
+ testImport(
+ R"(
+template <class, class> class A {};
+template <template <class> class TT> TT<char> f(TT<int>);
+void declToImport() {
+ using X = decltype(f(A<int, float>()));
+}
+)",
+ Lang_CXX17, "", Lang_CXX17, Verifier,
+ functionDecl(hasName("declToImport"),
+ hasDescendant(typeAliasDecl(
+ hasName("X"), hasUnderlyingType(hasCanonicalType(
+ asString("class A<char, float>")))))));
+}
+
TEST_P(ImportDecl, ImportUsingEnumDecl) {
MatchVerifier<Decl> Verifier;
testImport("namespace foo { enum bar { baz, toto, quux }; }"