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 { 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/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 6098101a73a62..903461532940c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -84,6 +84,9 @@ C++2c Feature Support Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Clang now has improved resolution to CWG2398, allowing class templates to have + default arguments deduced when partial ordering. + C Language Changes ------------------ @@ -119,7 +122,7 @@ Improvements to Clang's diagnostics - Some template related diagnostics have been improved. .. code-block:: c++ - + void foo() { template int i; } // error: templates can only be declared in namespace or class scope struct S { diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 6d1c8ca8a2f96..0dc0404cf01cd 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -263,6 +263,8 @@ class ASTContext : public RefCountedBase { mutable llvm::ContextualFoldingSet SubstTemplateTemplateParmPacks; + mutable llvm::ContextualFoldingSet + DeducedTemplates; mutable llvm::ContextualFoldingSet ArrayParameterTypes; @@ -2288,6 +2290,9 @@ class ASTContext : public RefCountedBase { unsigned Index, bool Final) const; + TemplateName getDeducedTemplateName(TemplateName Underlying, + DefaultArguments DefaultArgs) const; + enum GetBuiltinTypeError { /// No error GE_None, @@ -2771,11 +2776,13 @@ class ASTContext : public RefCountedBase { /// 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 FromArgs, + SmallVectorImpl &ToArgs); + Expected 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 5f7d619518762..9b934b20cf255 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -752,6 +752,23 @@ let Class = PropertyTypeCase in { return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, final); }]>; } +let Class = PropertyTypeCase 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> { + let Read = [{ DTS->getDefaultArguments().Args }]; + } + def : Creator<[{ + return ctx.getDeducedTemplateName(underlying, {startPos, defaultArgs}); + }]>; +} // Type cases for TemplateArgument. def : PropertyTypeKind(this) + : nullptr; + } + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() { return Bits.Kind == SubstTemplateTemplateParm ? reinterpret_cast(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 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 @@ -246,6 +263,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; @@ -257,6 +278,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; @@ -271,7 +293,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 + getTemplateDeclAndDefaultArgs() const; /// Retrieve the underlying, overloaded function template /// declarations that this template name refers to, if known. @@ -313,6 +341,11 @@ class TemplateName { /// template declaration is introduced, if any. UsingShadowDecl *getAsUsingShadowDecl() const; + /// Retrieve the deduced template info, if any. + DeducedTemplateStorage *getAsDeducedTemplateName() const; + + std::optional desugar(bool IgnoreDeduced) const; + TemplateName getUnderlying() const; TemplateNameDependence getDependence() const; @@ -412,6 +445,30 @@ class SubstTemplateTemplateParmStorage std::optional 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(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 06a06d7718781..9856c0f2a7b15 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11710,6 +11710,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: @@ -11719,7 +11722,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 &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions = true, @@ -12453,8 +12457,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); /// Mark which template parameters are used in a given expression. /// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a465cdfcf3c89..6c26216e7748a 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -881,8 +881,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, @@ -5352,7 +5352,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()) @@ -5387,7 +5387,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); @@ -6684,16 +6689,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(P)); + case NamedDecl::NonTypeTemplateParm: + return handleParam(cast(P)); + case NamedDecl::TemplateTemplateParm: + return handleParam(cast(P)); + default: + llvm_unreachable("Unexpected template parameter kind"); + } +} + +TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name, + bool IgnoreDeduced) const { + while (std::optional 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(Template)) @@ -6713,12 +6743,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(); @@ -6728,15 +6752,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 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 { @@ -7225,7 +7292,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()), @@ -7237,8 +7304,10 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { *this, Arg.pack_elements(), AnyNonCanonArgs); if (!AnyNonCanonArgs) return Arg; - return TemplateArgument::CreatePackCopy(const_cast(*this), - CanonArgs); + auto NewArg = TemplateArgument::CreatePackCopy( + const_cast(*this), CanonArgs); + NewArg.setIsDefaulted(Arg.getIsDefaulted()); + return NewArg; } } @@ -9793,6 +9862,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. @@ -12926,22 +13019,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; } @@ -13428,7 +13523,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: { @@ -13656,8 +13752,9 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, case Type::TemplateSpecialization: { const auto *TX = cast(X), *TY = cast(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 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()) 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 08ef09d353afc..9cec9a4e444e2 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9899,6 +9899,8 @@ Expected ASTImporter::Import(TemplateName From) { return UsingOrError.takeError(); return TemplateName(cast(*UsingOrError)); } + case TemplateName::DeducedTemplate: + llvm_unreachable("Unexpected DeducedTemplate"); } 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 490c4a2fc525c..caff9242e95aa 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -350,7 +350,8 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef 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 d46d621d4c7d4..6ce49aaed3e15 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2384,6 +2384,8 @@ void CXXNameMangler::mangleType(TemplateName TN) { Out << "_SUBSTPACK_"; break; } + case TemplateName::DeducedTemplate: + llvm_unreachable("Unexpected DeducedTemplate"); } addSubstitution(TN); @@ -2501,6 +2503,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: { @@ -5900,7 +5903,10 @@ struct CXXNameMangler::TemplateArgManglingInfo { // that of the template. auto *TTP = cast(Param); TemplateName ArgTemplateName = Arg.getAsTemplateOrTemplatePattern(); - const TemplateDecl *ArgTemplate = ArgTemplateName.getAsTemplateDecl(); + assert(!ArgTemplateName.getTemplateDeclAndDefaultArgs().second && + "A DeducedTemplateName shouldn't escape partial ordering"); + const TemplateDecl *ArgTemplate = + ArgTemplateName.getAsTemplateDecl(/*IgnoreDeduced=*/true); if (!ArgTemplate) return true; @@ -6767,9 +6773,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(Template.getAsVoidPointer())); @@ -6939,9 +6942,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(Template.getAsVoidPointer())); } diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index fbfe92318dc5e..2162915178eaa 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -162,6 +162,8 @@ void ODRHash::AddTemplateName(TemplateName Name) { case TemplateName::SubstTemplateTemplateParmPack: case TemplateName::UsingTemplate: break; + case TemplateName::DeducedTemplate: + llvm_unreachable("Unexpected DeducedTemplate"); } } 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(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()) { - if (UsingShadowDecl *USD = dyn_cast(TemplateOrUsing)) - return cast(USD->getTargetDecl()); - - assert(isa(TemplateOrUsing)); - return cast(TemplateOrUsing); - } +TemplateDecl *TemplateName::getAsTemplateDecl(bool IgnoreDeduced) const { + TemplateName Name = *this; + while (std::optional 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(Name.Storage.dyn_cast()); +} - if (UsingShadowDecl *USD = getAsUsingShadowDecl()) - return cast(USD->getTargetDecl()); +std::pair +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 UnderlyingOrNone = + Name.desugar(/*IgnoreDeduced=*/false)) { + Name = *UnderlyingOrNone; + continue; + } + return {cast_if_present(Name.Storage.dyn_cast()), {}}; + } +} - return nullptr; +std::optional TemplateName::desugar(bool IgnoreDeduced) const { + if (Decl *D = Storage.dyn_cast()) { + if (auto *USD = dyn_cast(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()) + 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(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 5ba9523504258..65928e6c9a497 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 fdaab8e434593..a051e240b1565 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4295,7 +4295,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(this + 1); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ffec3ef9d2269..03ee0f12d911c 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1614,7 +1614,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 1cca8ac9b9343..6d49ffcfd0c31 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4396,8 +4396,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD, for (auto const &Base : ClassDecl->bases()) { auto BaseTemplate = Base.getType()->getAs(); - 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(); @@ -11419,8 +11420,8 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, if (auto RetTST = TSI->getTypeLoc().getAsAdjusted()) { 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 87b1f98bbe5ac..40aa890adc0ee 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3284,8 +3284,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 @@ -3296,10 +3296,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(Template) || isa(Template) || isa(Template)) { // We might have a substituted template template parameter pack. If so, @@ -3317,8 +3318,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. SmallVector SugaredConverted, CanonicalConverted; - if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, - SugaredConverted, CanonicalConverted, + if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, + DefaultArgs, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return QualType(); @@ -3988,7 +3990,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -4155,8 +4158,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList( Template, TemplateNameLoc, - const_cast(TemplateArgs), false, - SugaredConverted, CanonicalConverted, + const_cast(TemplateArgs), + /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -4350,6 +4353,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, if (CheckTemplateArgumentList( NamedConcept, ConceptNameInfo.getLoc(), const_cast(*TemplateArgs), + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/false)) return ExprError(); @@ -5274,7 +5278,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 &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied, @@ -5302,9 +5307,29 @@ bool Sema::CheckTemplateArgumentList( SmallVector 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 Expansions = getExpandedPackSize(*Param)) { @@ -5518,6 +5543,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 @@ -7101,7 +7127,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?"); @@ -7152,7 +7178,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 @@ -8196,7 +8222,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, + /*PartialTemplateArgs=*/false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -9494,7 +9522,8 @@ DeclResult Sema::ActOnExplicitInstantiation( // template. SmallVector 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 612c23acffcbf..9bf318d939480 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -133,11 +133,16 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { return X == Y; } +/// What kind of PartialOrdering we're performing template argument deduction +/// for (C++0x [temp.deduct.partial]). +enum class PartialOrderingKind { None, NonCall, Call }; + static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Sema &S, TemplateParameterList *TemplateParams, QualType Param, QualType Arg, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool DeducedFromArrayBound, bool *HasDeducedAnyParam); + PartialOrderingKind POK, bool DeducedFromArrayBound, + bool *HasDeducedAnyParam); enum class PackFold { ParameterToArgument, ArgumentToParameter }; static TemplateDeductionResult @@ -146,8 +151,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool NumberOfArgumentsMustMatch, PackFold PackFold, - bool *HasDeducedAnyParam); + bool NumberOfArgumentsMustMatch, bool PartialOrdering, + PackFold PackFold, bool *HasDeducedAnyParam); static void MarkUsedTemplateParameters(ASTContext &Ctx, const TemplateArgument &TemplateArg, @@ -400,6 +405,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, const DeducedTemplateArgument &NewDeduced, QualType ValueType, TemplateDeductionInfo &Info, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { assert(NTTP->getDepth() == Info.getDeducedDepth() && @@ -444,7 +450,9 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ParamType, ValueType, Info, Deduced, - TDF_SkipNonDependent, /*PartialOrdering=*/false, + TDF_SkipNonDependent, + PartialOrdering ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound(), HasDeducedAnyParam); } @@ -454,13 +462,13 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(S.Context, Value, ValueType, DeducedFromArrayBound), - ValueType, Info, Deduced, HasDeducedAnyParam); + ValueType, Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -469,6 +477,7 @@ static TemplateDeductionResult DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, QualType NullPtrType, TemplateDeductionInfo &Info, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { Expr *Value = S.ImpCastExprToType( @@ -480,7 +489,7 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, .get(); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(Value), Value->getType(), - Info, Deduced, HasDeducedAnyParam); + Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -490,12 +499,12 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, Expr *Value, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(Value), Value->getType(), - Info, Deduced, HasDeducedAnyParam); + Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -506,77 +515,22 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T, TemplateDeductionInfo &Info, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { D = D ? cast(D->getCanonicalDecl()) : nullptr; TemplateArgument New(D, T); - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DeducedTemplateArgument(New), T, Info, - Deduced, HasDeducedAnyParam); -} - -/// 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(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(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(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"); - } + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, + PartialOrdering, Deduced, HasDeducedAnyParam); } -static TemplateDeductionResult -DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - TemplateName Param, TemplateName Arg, - TemplateDeductionInfo &Info, - ArrayRef DefaultArguments, - SmallVectorImpl &Deduced, - bool *HasDeducedAnyParam) { +static TemplateDeductionResult DeduceTemplateArguments( + Sema &S, TemplateParameterList *TemplateParams, TemplateName Param, + TemplateName Arg, TemplateDeductionInfo &Info, + ArrayRef DefaultArguments, bool PartialOrdering, + SmallVectorImpl &Deduced, + bool *HasDeducedAnyParam) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { // The parameter type is dependent and is not a template template parameter, @@ -589,42 +543,30 @@ 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( - Arg.getAsTemplateDecl())) { - assert(!TempArg->isExpandedParameterPack()); - - TemplateParameterList *As = TempArg->getTemplateParameters(); - if (DefaultArguments.size() != 0) { - assert(DefaultArguments.size() <= As->size()); - SmallVector 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 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 = + PartialOrdering + ? TemplateArgument(S.Context.getDeducedTemplateName( + Arg, {StartPos, DefaultArguments.drop_front(StartPos)})) + : Arg; + + DeducedTemplateArgument Result = checkDeducedTemplateArguments( + S.Context, Deduced[TempParam->getIndex()], NewDeduced); if (Result.isNull()) { Info.Param = TempParam; Info.FirstArg = Deduced[TempParam->getIndex()]; @@ -639,7 +581,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. @@ -681,7 +624,7 @@ static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) { static TemplateDeductionResult DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, const QualType P, QualType A, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { QualType UP = P; @@ -730,9 +673,10 @@ 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, HasDeducedAnyParam); + if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, + /*DefaultArguments=*/AResolved, + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -741,8 +685,8 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // filled in by default arguments. return DeduceTemplateArguments( S, TemplateParams, PResolved, AResolved, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false, PackFold::ParameterToArgument, - HasDeducedAnyParam); + /*NumberOfArgumentsMustMatch=*/false, PartialOrdering, + PackFold::ParameterToArgument, HasDeducedAnyParam); } // If the argument type is a class template specialization, we @@ -763,9 +707,10 @@ 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, HasDeducedAnyParam); + if (auto Result = DeduceTemplateArguments( + S, TemplateParams, TNP, TNA, Info, + /*DefaultArguments=*/SA->getTemplateArgs().asArray(), PartialOrdering, + Deduced, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -773,7 +718,7 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, return DeduceTemplateArguments(S, TemplateParams, PResolved, SA->getTemplateArgs().asArray(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/true, - PackFold::ParameterToArgument, + PartialOrdering, PackFold::ParameterToArgument, HasDeducedAnyParam); } @@ -1188,7 +1133,7 @@ static TemplateDeductionResult DeduceForEachType( Sema &S, TemplateParameterList *TemplateParams, const QualType *Params, unsigned NumParams, const QualType *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, bool PartialOrdering, + SmallVectorImpl &Deduced, PartialOrderingKind POK, bool FinishingDeduction, T &&DeductFunc) { // C++0x [temp.deduct.type]p10: // Similarly, if P has a form that contains (T), then each parameter type @@ -1218,8 +1163,7 @@ static TemplateDeductionResult DeduceForEachType( if (TemplateDeductionResult Result = DeductFunc(S, TemplateParams, ParamIdx, ArgIdx, Params[ParamIdx].getUnqualifiedType(), - Args[ArgIdx].getUnqualifiedType(), Info, Deduced, - PartialOrdering); + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, POK); Result != TemplateDeductionResult::Success) return Result; @@ -1247,7 +1191,7 @@ static TemplateDeductionResult DeduceForEachType( if (TemplateDeductionResult Result = DeductFunc( S, TemplateParams, ParamIdx, ArgIdx, Pattern.getUnqualifiedType(), Args[ArgIdx].getUnqualifiedType(), - Info, Deduced, PartialOrdering); + Info, Deduced, POK); Result != TemplateDeductionResult::Success) return Result; PackScope.nextPackElement(); @@ -1291,7 +1235,7 @@ static TemplateDeductionResult DeduceForEachType( // During partial ordering, if Ai was originally a function parameter pack: // - if P does not contain a function parameter type corresponding to Ai then // Ai is ignored; - if (PartialOrdering && ArgIdx + 1 == NumArgs && + if (POK == PartialOrderingKind::Call && ArgIdx + 1 == NumArgs && isa(Args[ArgIdx])) return TemplateDeductionResult::Success; @@ -1337,18 +1281,18 @@ static TemplateDeductionResult DeduceTemplateArguments( unsigned NumParams, const QualType *Args, unsigned NumArgs, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool *HasDeducedAnyParam, + PartialOrderingKind POK, bool *HasDeducedAnyParam, llvm::SmallBitVector *HasDeducedParam) { return ::DeduceForEachType( - S, TemplateParams, Params, NumParams, Args, NumArgs, Info, Deduced, - PartialOrdering, /*FinishingDeduction=*/false, + S, TemplateParams, Params, NumParams, Args, NumArgs, Info, Deduced, POK, + /*FinishingDeduction=*/false, [&](Sema &S, TemplateParameterList *TemplateParams, int ParamIdx, int ArgIdx, QualType P, QualType A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool PartialOrdering) { + PartialOrderingKind POK) { bool HasDeducedAnyParamCopy = false; TemplateDeductionResult TDR = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, P, A, Info, Deduced, TDF, PartialOrdering, + S, TemplateParams, P, A, Info, Deduced, TDF, POK, /*DeducedFromArrayBound=*/false, &HasDeducedAnyParamCopy); if (HasDeducedAnyParam && HasDeducedAnyParamCopy) *HasDeducedAnyParam = true; @@ -1457,7 +1401,7 @@ static CXXRecordDecl *getCanonicalRD(QualType T) { static TemplateDeductionResult DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, TemplateParameterList *TemplateParams, QualType P, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { // C++14 [temp.deduct.call] p4b3: @@ -1508,9 +1452,9 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, Deduced.end()); TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); bool HasDeducedAnyParamCopy = false; - TemplateDeductionResult BaseResult = - DeduceTemplateSpecArguments(S, TemplateParams, P, NextT, BaseInfo, - DeducedCopy, &HasDeducedAnyParamCopy); + TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments( + S, TemplateParams, P, NextT, BaseInfo, PartialOrdering, DeducedCopy, + &HasDeducedAnyParamCopy); // If this was a successful deduction, add it to the list of matches, // otherwise we need to continue searching its bases. @@ -1584,7 +1528,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool DeducedFromArrayBound, + PartialOrderingKind POK, bool DeducedFromArrayBound, bool *HasDeducedAnyParam) { // If the argument type is a pack expansion, look at its pattern. @@ -1593,7 +1537,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( A = AExp->getPattern(); assert(!isa(A.getCanonicalType())); - if (PartialOrdering) { + if (POK == PartialOrderingKind::Call) { // C++11 [temp.deduct.partial]p5: // Before the partial ordering is done, certain transformations are // performed on the types used for partial ordering: @@ -1867,7 +1811,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CP->getElementType(), CA->getElementType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1878,7 +1824,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PA->getValueType(), AA->getValueType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1896,8 +1844,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, P->castAs()->getPointeeType(), PointeeType, Info, Deduced, TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass), - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } // T & @@ -1909,7 +1858,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1922,7 +1873,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1937,7 +1890,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, IAP->getElementType(), IAA->getElementType(), Info, - Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false, + Deduced, TDF & TDF_IgnoreQualifiers, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1951,7 +1906,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info, - Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false, + Deduced, TDF & TDF_IgnoreQualifiers, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1967,7 +1924,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, DAP->getElementType(), AA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers, - /*PartialOrdering=*/false, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -1986,13 +1944,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( llvm::APSInt Size(CAA->getSize()); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, Size, S.Context.getSizeType(), - /*ArrayBound=*/true, Info, Deduced, HasDeducedAnyParam); + /*ArrayBound=*/true, Info, POK != PartialOrderingKind::None, + Deduced, HasDeducedAnyParam); } if (const auto *DAA = dyn_cast(AA)) if (DAA->getSizeExpr()) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DAA->getSizeExpr(), Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); // Incomplete type does not match a dependently-sized array type return TemplateDeductionResult::NonDeducedMismatch; @@ -2016,7 +1975,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(), Info, Deduced, 0, - /*PartialOrdering=*/false, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2025,8 +1985,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArguments( S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(), FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced, - TDF & TDF_TopLevelParameterTypeList, PartialOrdering, - HasDeducedAnyParam, /*HasDeducedParam=*/nullptr); + TDF & TDF_TopLevelParameterTypeList, POK, HasDeducedAnyParam, + /*HasDeducedParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -2054,14 +2014,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // FIXME: Should we? return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy, - /*DeducedFromArrayBound=*/true, Info, Deduced, - HasDeducedAnyParam); + /*DeducedFromArrayBound=*/true, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); case CT_Dependent: if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr()) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - ArgNoexceptExpr, Info, Deduced, - HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgNoexceptExpr, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); // Can't deduce anything from throw(T...). break; } @@ -2088,13 +2048,15 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // arguments from the template-id. if (!(TDF & TDF_DerivedClass) || !A->isRecordType()) return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); SmallVector DeducedOrig(Deduced.begin(), Deduced.end()); - auto Result = DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, - Deduced, HasDeducedAnyParam); + auto Result = DeduceTemplateSpecArguments( + S, TemplateParams, P, A, Info, POK != PartialOrderingKind::None, + Deduced, HasDeducedAnyParam); if (Result == TemplateDeductionResult::Success) return Result; @@ -2111,9 +2073,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Deduced = DeducedOrig; // Check bases according to C++14 [temp.deduct.call] p4b3: - auto BaseResult = - DeduceTemplateBases(S, getCanonicalRD(A), TemplateParams, P, Info, - Deduced, HasDeducedAnyParam); + auto BaseResult = DeduceTemplateBases( + S, getCanonicalRD(A), TemplateParams, P, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); return BaseResult != TemplateDeductionResult::Invalid ? BaseResult : Result; } @@ -2145,15 +2107,17 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( unsigned SubTDF = TDF & TDF_IgnoreQualifiers; if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PPT, APT, Info, Deduced, SubTDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, QualType(MPP->getClass(), 0), QualType(MPA->getClass(), 0), Info, Deduced, SubTDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } // (clang extension) @@ -2168,7 +2132,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -2194,8 +2160,10 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced, - TDF, /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } case Type::DependentVector: { @@ -2205,7 +2173,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2221,16 +2191,19 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, - S.Context.UnsignedIntTy, true, - Info, Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgSize, S.Context.UnsignedIntTy, true, + Info, POK != PartialOrderingKind::None, Deduced, + HasDeducedAnyParam); } if (const auto *VA = A->getAs()) { // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2241,9 +2214,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!NTTP) return TemplateDeductionResult::Success; - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VA->getSizeExpr(), Info, Deduced, - HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, VA->getSizeExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } return TemplateDeductionResult::NonDeducedMismatch; @@ -2259,7 +2232,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2275,16 +2250,18 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, - S.Context.IntTy, true, Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } if (const auto *VA = A->getAs()) { // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2295,9 +2272,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!NTTP) return TemplateDeductionResult::Success; - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VA->getSizeExpr(), Info, Deduced, - HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, VA->getSizeExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } return TemplateDeductionResult::NonDeducedMismatch; @@ -2321,7 +2298,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on element types. return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, MP->getElementType(), MA->getElementType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -2334,14 +2313,16 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check the element type of the matrixes. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, MP->getElementType(), MA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; // Try to deduce a matrix dimension. auto DeduceMatrixArg = - [&S, &Info, &Deduced, &TemplateParams, &HasDeducedAnyParam]( + [&S, &Info, &Deduced, &TemplateParams, &HasDeducedAnyParam, POK]( Expr *ParamExpr, const MatrixType *A, unsigned (ConstantMatrixType::*GetArgDimension)() const, Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) { @@ -2378,12 +2359,13 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( ArgConst = (ACM->*GetArgDimension)(); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(), - /*ArrayBound=*/true, Info, Deduced, HasDeducedAnyParam); + /*ArrayBound=*/true, Info, POK != PartialOrderingKind::None, + Deduced, HasDeducedAnyParam); } return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, (ADM->*GetArgDimensionExpr)(), Info, - Deduced, HasDeducedAnyParam); + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); }; if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA, @@ -2407,7 +2389,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the pointer type. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2418,9 +2402,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!NTTP) return TemplateDeductionResult::Success; - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - ASA->getAddrSpaceExpr(), Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } if (isTargetAddressSpace(A.getAddressSpace())) { @@ -2432,8 +2416,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ASP->getPointeeType(), S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2445,7 +2430,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgAddressSpace, S.Context.IntTy, true, - Info, Deduced, HasDeducedAnyParam); + Info, POK != PartialOrderingKind::None, Deduced, + HasDeducedAnyParam); } return TemplateDeductionResult::NonDeducedMismatch; @@ -2465,9 +2451,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); ArgSize = IA->getNumBits(); - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, - S.Context.IntTy, true, Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } if (const auto *IA = A->getAs()) { @@ -2498,8 +2484,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (PIT->hasSelectedType()) { return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PIT->getSelectedType(), A, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + POK != PartialOrderingKind::None ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } return TemplateDeductionResult::IncompletePack; } @@ -2511,7 +2498,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &P, TemplateArgument A, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { // If the template argument is a pack expansion, perform template argument @@ -2528,17 +2515,21 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (A.getKind() == TemplateArgument::Type) return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + PartialOrdering ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Info.FirstArg = P; Info.SecondArg = A; return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::Template: + // PartialOrdering does not matter here, since template specializations are + // not being deduced. if (A.getKind() == TemplateArgument::Template) return DeduceTemplateArguments( S, TemplateParams, P.getAsTemplate(), A.getAsTemplate(), Info, - /*DefaultArguments=*/{}, Deduced, HasDeducedAnyParam); + /*DefaultArguments=*/{}, /*PartialOrdering=*/false, Deduced, + HasDeducedAnyParam); Info.FirstArg = P; Info.SecondArg = A; return TemplateDeductionResult::NonDeducedMismatch; @@ -2589,20 +2580,20 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, case TemplateArgument::Integral: case TemplateArgument::Expression: case TemplateArgument::StructuralValue: - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DeducedTemplateArgument(A), - A.getNonTypeTemplateArgumentType(), - Info, Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DeducedTemplateArgument(A), + A.getNonTypeTemplateArgumentType(), Info, PartialOrdering, Deduced, + HasDeducedAnyParam); case TemplateArgument::NullPtr: - return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP, - A.getNullPtrType(), Info, Deduced, - HasDeducedAnyParam); + return DeduceNullPtrTemplateArgument( + S, TemplateParams, NTTP, A.getNullPtrType(), Info, PartialOrdering, + Deduced, HasDeducedAnyParam); case TemplateArgument::Declaration: return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(), - Info, Deduced, HasDeducedAnyParam); + Info, PartialOrdering, Deduced, HasDeducedAnyParam); case TemplateArgument::Null: case TemplateArgument::Type: @@ -2674,8 +2665,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool NumberOfArgumentsMustMatch, PackFold PackFold, - bool *HasDeducedAnyParam) { + bool NumberOfArgumentsMustMatch, bool PartialOrdering, + PackFold PackFold, bool *HasDeducedAnyParam) { if (PackFold == PackFold::ArgumentToParameter) std::swap(Ps, As); // C++0x [temp.deduct.type]p9: @@ -2712,7 +2703,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (PackFold == PackFold::ArgumentToParameter) std::swap(Pi, Ai); if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, - Deduced, HasDeducedAnyParam); + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2744,7 +2736,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, std::swap(Pi, Ai); // Deduce template arguments from the pattern. if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, - Deduced, HasDeducedAnyParam); + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2768,7 +2761,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( bool NumberOfArgumentsMustMatch) { return ::DeduceTemplateArguments( *this, TemplateParams, Ps, As, Info, Deduced, NumberOfArgumentsMustMatch, - PackFold::ParameterToArgument, /*HasDeducedAnyParam=*/nullptr); + /*PartialOrdering=*/false, PackFold::ParameterToArgument, + /*HasDeducedAnyParam=*/nullptr); } /// Determine whether two template arguments are the same. @@ -3292,7 +3286,7 @@ FinishTemplateArgumentDeduction( SmallVector SugaredConvertedInstArgs, CanonicalConvertedInstArgs; if (S.CheckTemplateArgumentList( - Template, Partial->getLocation(), InstArgs, false, + Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false, SugaredConvertedInstArgs, CanonicalConvertedInstArgs, /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) return ConstraintsNotSatisfied @@ -3439,7 +3433,8 @@ DeduceTemplateArguments(Sema &S, T *Partial, if (TemplateDeductionResult Result = ::DeduceTemplateArguments( S, Partial->getTemplateParameters(), Partial->getTemplateArgs().asArray(), TemplateArgs, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false, PackFold::ParameterToArgument, + /*NumberOfArgumentsMustMatch=*/false, /*PartialOrdering=*/true, + PackFold::ParameterToArgument, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -3591,8 +3586,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(); @@ -4245,7 +4240,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, TemplateDeductionInfo Info(Ovl->getNameLoc()); TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); if (Result != TemplateDeductionResult::Success) continue; @@ -4432,7 +4427,7 @@ static TemplateDeductionResult DeduceFromInitializerList( llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits()); if (auto Result = DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, llvm::APSInt(Size), T, - /*ArrayBound=*/true, Info, Deduced, + /*ArrayBound=*/true, Info, /*PartialOrdering=*/false, Deduced, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -4478,7 +4473,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType)); return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); } @@ -4803,7 +4798,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( // Deduce template arguments from the function type. if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( *this, TemplateParams, FunctionType, ArgFunctionType, Info, Deduced, - TDF, /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + TDF, PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -4985,7 +4980,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( *this, TemplateParams, P, A, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -5123,9 +5118,9 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); llvm::SmallVector 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); @@ -5276,7 +5271,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, TemplArg, Init->getType(), Init->Classify(getASTContext()), Init, Info, Deduced, - OriginalCallArgs, /*Decomposed=*/true, + OriginalCallArgs, + /*Decomposed=*/true, /*ArgIdx=*/0, /*TDF=*/0); TDK != TemplateDeductionResult::Success) { if (TDK == TemplateDeductionResult::Inconsistent) { @@ -5304,8 +5300,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, FuncParam, Init->getType(), Init->Classify(getASTContext()), Init, Info, Deduced, - OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, - FailedTSC); + OriginalCallArgs, + /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, FailedTSC); TDK != TemplateDeductionResult::Success) return DeductionFailed(TDK); } @@ -5644,7 +5640,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, llvm::SmallBitVector HasDeducedParam(Args2.size()); if (DeduceTemplateArguments( S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), - Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true, + Args1.size(), Info, Deduced, TDF_None, PartialOrderingKind::Call, /*HasDeducedAnyParam=*/nullptr, &HasDeducedParam) != TemplateDeductionResult::Success) return false; @@ -5666,13 +5662,13 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, ArrayRef DeducedArgs) { return ::DeduceForEachType( S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), - Args1.size(), Info, Deduced, - /*PartialOrdering=*/true, /*FinishingDeduction=*/true, + Args1.size(), Info, Deduced, PartialOrderingKind::Call, + /*FinishingDeduction=*/true, [&](Sema &S, TemplateParameterList *, int ParamIdx, int ArgIdx, QualType P, QualType A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool) { + PartialOrderingKind) { // As a provisional fix for a core issue that does not // exist yet, only check the consistency of parameters // which participated in deduction. We still try to @@ -5692,8 +5688,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, // of the conversion function templates are used. if (DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(), - Info, Deduced, TDF_None, - /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false, + Info, Deduced, TDF_None, PartialOrderingKind::Call, + /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success) return false; @@ -5727,8 +5723,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, // is used. if (DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced, - TDF_AllowCompatibleFunctionType, - /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false, + TDF_AllowCompatibleFunctionType, PartialOrderingKind::Call, + /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success) return false; @@ -5758,12 +5754,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, Proto2->getParamTypes().size(), Proto1->getParamTypes().data(), Proto1->getParamTypes().size(), Info, Deduced, - /*PartialOrdering=*/true, /*FinishingDeduction=*/true, + PartialOrderingKind::Call, /*FinishingDeduction=*/true, [&](Sema &S, TemplateParameterList *, int ParamIdx, int ArgIdx, QualType P, QualType A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool) { + PartialOrderingKind) { return ::CheckDeductionConsistency( S, FTD, ArgIdx, P, A, DeducedArgs, /*CheckConsistency=*/true); @@ -6212,7 +6208,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, Deduced.resize(P2->getTemplateParameters()->size()); if (DeduceTemplateArgumentsByTypeMatch( S, P2->getTemplateParameters(), T2, T1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::Call, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success) return false; @@ -6471,8 +6467,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 @@ -6520,8 +6516,9 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // If the rewrite produces an invalid type, then P is not at least as // specialized as A. SmallVector 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()) @@ -6546,6 +6543,7 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // currently implemented as a special case elsewhere. if (::DeduceTemplateArguments(*this, A, AArgs, PArgs, Info, Deduced, /*NumberOfArgumentsMustMatch=*/false, + /*PartialOrdering=*/true, IsDeduced ? PackFold::ArgumentToParameter : PackFold::ParameterToArgument, /*HasDeducedAnyParam=*/nullptr) != diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a12d2eff1d2c8..b1872333ff0a1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3879,10 +3879,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Check that the template argument list is well-formed for this // class template. SmallVector 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 @@ -3987,10 +3987,10 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector 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. @@ -4255,6 +4255,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( SmallVector SugaredConverted, CanonicalConverted; if (SemaRef.CheckTemplateArgumentList( ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; @@ -4366,9 +4367,10 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // Check that the template argument list is well-formed for this // class template. SmallVector 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/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp index 6fe1bd3d4f165..1d9747276fbe0 100644 --- a/clang/test/SemaTemplate/cwg2398.cpp +++ b/clang/test/SemaTemplate/cwg2398.cpp @@ -65,26 +65,20 @@ namespace class_template { template struct B; template