https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/94981
>From b238961ba3a174d7dc211caf36ff8fd6c8429a76 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Mon, 20 May 2024 01:15:03 -0300 Subject: [PATCH] [clang] Implement CWG2398 provisional TTP matching to class templates This extends default argument deduction to cover class templates as well, and also applies outside of partial ordering, adding to the provisional wording introduced in 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. --- clang-tools-extra/clangd/DumpAST.cpp | 1 + .../clangd/SemanticHighlighting.cpp | 1 + clang/include/clang/AST/ASTContext.h | 11 +- clang/include/clang/AST/ASTImporter.h | 5 + clang/include/clang/AST/DependenceFlags.h | 5 + clang/include/clang/AST/PropertiesBase.td | 17 ++ clang/include/clang/AST/TemplateName.h | 63 ++++++- clang/include/clang/Sema/Sema.h | 10 +- clang/lib/AST/ASTContext.cpp | 153 +++++++++++++--- clang/lib/AST/ASTDiagnostic.cpp | 45 +++-- clang/lib/AST/ASTImporter.cpp | 15 ++ clang/lib/AST/ASTStructuralEquivalence.cpp | 3 + clang/lib/AST/Decl.cpp | 3 +- clang/lib/AST/ItaniumMangle.cpp | 20 ++- clang/lib/AST/ODRHash.cpp | 1 + clang/lib/AST/TemplateName.cpp | 163 ++++++++++++++---- clang/lib/AST/TextNodeDumper.cpp | 12 ++ clang/lib/AST/Type.cpp | 3 +- clang/lib/AST/TypePrinter.cpp | 3 +- clang/lib/Sema/SemaDeclCXX.cpp | 9 +- clang/lib/Sema/SemaTemplate.cpp | 63 +++++-- clang/lib/Sema/SemaTemplateDeduction.cpp | 158 +++++------------ .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 24 +-- .../CXX/temp/temp.decls/temp.alias/p2.cpp | 5 +- clang/test/CodeGenCXX/mangle-cwg2398.cpp | 11 ++ clang/test/SemaTemplate/cwg2398.cpp | 62 +++++-- clang/tools/libclang/CIndex.cpp | 3 + clang/unittests/AST/ASTImporterTest.cpp | 17 ++ 28 files changed, 629 insertions(+), 257 deletions(-) create mode 100644 clang/test/CodeGenCXX/mangle-cwg2398.cpp diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp index 9a525efb938e8..e605f82e91fe4 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 a366f1331c2d3..e6d16af2495fe 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -1120,6 +1120,7 @@ class CollectExtraHighlightings 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 de86cb5e9d7fc..837bcacbc0bfc 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 @@ class ASTContext : public RefCountedBase<ASTContext> { unsigned Index, bool Final) const; + TemplateName getDeducedTemplateName(TemplateName Underlying, + DefaultArguments DefaultArgs) const; + enum GetBuiltinTypeError { /// No error GE_None, @@ -2735,11 +2740,13 @@ class ASTContext : public RefCountedBase<ASTContext> { /// 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 4ffd913846575..7b890bdf492fa 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 3b3c1afb096ad..bdcaabc143cc4 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 6df1d93a7ba2e..bd0b316a4958a 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 24a7fde76195d..6919e127629c6 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 @@ class UncommonTemplateNameStorage { 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 @@ class UncommonTemplateNameStorage { : 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 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage, 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 @@ class TemplateName { /// 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 @@ class TemplateName { 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 @@ class TemplateName { /// 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 @@ class TemplateName { /// 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 @@ class SubstTemplateTemplateParmStorage 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 174b9dbc6d980..a847fb8fe5500 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9216,6 +9216,9 @@ class Sema final : public SemaBase { /// 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 @@ class Sema final : public SemaBase { /// \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 @@ class Sema final : public SemaBase { 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 a4e6d3b108c8a..d291a0a936df7 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 0680ff5e3a385..15c3efe421271 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 @@ class TemplateDiff { return; // Different base templates. - if (!hasSameTemplate(FromOrigTST, ToOrigTST)) { + if (!hasSameTemplate(Context, FromOrigTST, ToOrigTST)) { return; } @@ -2131,10 +2141,11 @@ class TemplateDiff { 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 1b67feaae8874..3061d7abefbd9 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 37555c324282f..d81f45d5720a4 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 9d0a835a12c45..24229b78f3e8e 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 203db72c43733..7916ab97b5815 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 1249531eab09f..2366cd5a441a6 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 d4e8a8971a971..044a1a92469ac 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 bd1e630cd9047..992533672c778 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 656b733a13b0e..6c777be6278ab 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 4add4d3af69a3..e995713d01ddd 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 d38700d56e4ff..20f89c4849808 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 a032e3ec6f635..2296750cebc72 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 a432918cbf5e2..3efc3030fc261 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 0681520764d9a..26b2fa793b48a 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 a5b39fe5c51f7..bc39431253880 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 0000000000000..a8a0aed17c70f --- /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 7675d4287cb88..51a7c7b3612e4 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 35312e3d2ae70..b39e4c195c9e5 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 92f9bae6cb064..392ef9bd85a4a 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 }; }" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits