diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp index 9a525efb938e8d..e605f82e91fe41 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 a366f1331c2d3d..e6d16af2495fec 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 684484ccd298fb..f4e54a0470d862 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -160,6 +160,9 @@ Resolutions to C++ Defect Reports - Allow ``void{}`` as a prvalue of type ``void``. (`CWG2351: void{} `_). +- Clang now has improved resolution to CWG2398, allowing class templates to have + default arguments deduced when partial ordering. + - Clang now allows comparing unequal object pointers that have been cast to ``void *`` in constant expressions. These comparisons always worked in non-constant expressions. (`CWG2749: Treatment of "pointer to void" for relational comparisons `_). diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 89bb5768dbd40d..168bdca3c880b2 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -265,6 +265,8 @@ class ASTContext : public RefCountedBase { mutable llvm::ContextualFoldingSet SubstTemplateTemplateParmPacks; + mutable llvm::ContextualFoldingSet + DeducedTemplates; mutable llvm::ContextualFoldingSet ArrayParameterTypes; @@ -2304,6 +2306,15 @@ class ASTContext : public RefCountedBase { unsigned Index, bool Final) const; + /// Represents a TemplateName which had some of its default arguments + /// deduced. This both represents this default argument deduction as sugar, + /// and provides the support for it's equivalences through canonicalization. + /// For example DeducedTemplateNames which have the same set of default + /// arguments are equivalent, and are also equivalent to the underlying + /// template when the deduced template arguments are the same. + TemplateName getDeducedTemplateName(TemplateName Underlying, + DefaultArguments DefaultArgs) const; + enum GetBuiltinTypeError { /// No error GE_None, @@ -2787,11 +2798,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 f851decd0965ce..088a2bd0fdd407 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -484,6 +484,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 3b3c1afb096add..bdcaabc143cc40 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 5f7d6195187623..9b934b20cf2559 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 0358259945c796..68c782a15c6f1b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11733,6 +11733,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: @@ -11742,7 +11745,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, @@ -12479,8 +12483,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 341ea98a1b1490..fa9cc38efc4662 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, @@ -5411,7 +5411,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()) @@ -5446,7 +5446,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); @@ -6753,16 +6758,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)) @@ -6782,12 +6812,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(); @@ -6797,15 +6821,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 any argument differs, 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 { @@ -7294,7 +7361,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()), @@ -7306,8 +7373,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; } } @@ -9864,6 +9933,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. @@ -13020,22 +13113,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; } @@ -13522,7 +13617,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: { @@ -13751,8 +13847,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 0680ff5e3a3851..15c3efe4212719 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 e854dbfb7bf2e5..c2fb7dddcfc637 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9935,6 +9935,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 0b791700aa48dd..f13ca2d08d769f 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 1a07125815832e..a14b1b33d35efc 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 1a47caac5a503c..7d638befcbd3f1 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); @@ -2502,6 +2504,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: { @@ -5936,7 +5939,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; diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index b748093831e3f5..1929314363817a 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 d4e8a8971a971a..044a1a92469aca 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 c6b1b44206b24d..3c51c746471829 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 b976d1a0ee60ae..a55e6c8bf02611 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4303,7 +4303,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 3bef9370e621ce..add6a5d10d61f7 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1635,7 +1635,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 f90f16c2923d03..6b6fa98bf394ca 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(); @@ -11459,8 +11460,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 bf6b53700d90eb..513f83146fb59e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3302,8 +3302,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 @@ -3314,10 +3314,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, @@ -3335,8 +3336,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(); @@ -4012,7 +4014,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -4179,8 +4182,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; @@ -4374,6 +4377,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, if (CheckTemplateArgumentList( NamedConcept, ConceptNameInfo.getLoc(), const_cast(*TemplateArgs), + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/false)) return ExprError(); @@ -5299,7 +5303,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, @@ -5327,9 +5332,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)) { @@ -5543,6 +5568,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 @@ -7126,7 +7152,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?"); @@ -7177,7 +7203,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 @@ -8231,7 +8257,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; @@ -9603,7 +9631,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 01f18e5a325197..4c88159ea4cedf 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -134,11 +134,16 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { return X == Y; } +/// The kind of PartialOrdering we're performing template argument deduction +/// for (C++11 [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 @@ -147,8 +152,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, @@ -401,6 +406,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() && @@ -445,7 +451,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); } @@ -455,13 +463,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 @@ -470,6 +478,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( @@ -481,7 +490,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 @@ -491,12 +500,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 @@ -507,76 +516,21 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T, TemplateDeductionInfo &Info, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { 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); } @@ -1189,7 +1134,7 @@ template static TemplateDeductionResult DeduceForEachType( Sema &S, TemplateParameterList *TemplateParams, ArrayRef Params, ArrayRef Args, 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 @@ -1219,8 +1164,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; @@ -1248,7 +1192,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(); @@ -1292,7 +1236,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 == Args.size() && + if (POK == PartialOrderingKind::Call && ArgIdx + 1 == Args.size() && isa(Args[ArgIdx])) return TemplateDeductionResult::Success; @@ -1339,18 +1283,18 @@ static TemplateDeductionResult DeduceTemplateArguments( Sema &S, TemplateParameterList *TemplateParams, ArrayRef Params, ArrayRef Args, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool *HasDeducedAnyParam, + PartialOrderingKind POK, bool *HasDeducedAnyParam, llvm::SmallBitVector *HasDeducedParam) { return ::DeduceForEachType( - S, TemplateParams, Params, Args, Info, Deduced, PartialOrdering, + S, TemplateParams, Params, Args, 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; @@ -1454,7 +1398,7 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { 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: @@ -1507,9 +1451,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. @@ -1555,6 +1499,14 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, return TemplateDeductionResult::Success; } +/// When propagating a partial ordering kind into a NonCall context, +/// this is used to downgrade a 'Call' into a 'NonCall', so that +/// the kind still reflects whether we are in a partial ordering context. +static PartialOrderingKind +degradeCallPartialOrderingKind(PartialOrderingKind POK) { + return std::min(POK, PartialOrderingKind::NonCall); +} + /// Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -1583,7 +1535,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. @@ -1592,7 +1544,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: @@ -1866,7 +1818,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CP->getElementType(), CA->getElementType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1877,7 +1829,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PA->getValueType(), AA->getValueType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1895,8 +1847,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, P->castAs()->getPointeeType(), PointeeType, Info, Deduced, TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass), - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } // T & @@ -1908,7 +1860,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1921,7 +1873,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1936,7 +1888,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, IAP->getElementType(), IAA->getElementType(), Info, - Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false, + Deduced, TDF & TDF_IgnoreQualifiers, + degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1950,7 +1903,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info, - Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false, + Deduced, TDF & TDF_IgnoreQualifiers, + degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1966,7 +1920,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, DAP->getElementType(), AA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers, - /*PartialOrdering=*/false, + degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -1985,13 +1939,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; @@ -2014,8 +1969,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check return types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(), - Info, Deduced, 0, - /*PartialOrdering=*/false, + Info, Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2023,8 +1977,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check parameter types. if (auto Result = DeduceTemplateArguments( S, TemplateParams, FPP->param_types(), FPA->param_types(), Info, - Deduced, TDF & TDF_TopLevelParameterTypeList, PartialOrdering, - HasDeducedAnyParam, /*HasDeducedParam=*/nullptr); + Deduced, TDF & TDF_TopLevelParameterTypeList, POK, + HasDeducedAnyParam, + /*HasDeducedParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -2052,14 +2007,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; } @@ -2086,13 +2041,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,6 +2068,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check bases according to C++14 [temp.deduct.call] p4b3: auto BaseResult = DeduceTemplateBases(S, RD, TemplateParams, P, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); return BaseResult != TemplateDeductionResult::Invalid ? BaseResult : Result; @@ -2143,15 +2101,15 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( unsigned SubTDF = TDF & TDF_IgnoreQualifiers; if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PPT, APT, Info, Deduced, SubTDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*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); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } // (clang extension) @@ -2166,7 +2124,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -2192,8 +2150,8 @@ 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, degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } case Type::DependentVector: { @@ -2203,7 +2161,7 @@ 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, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2219,16 +2177,17 @@ 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, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2239,9 +2198,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; @@ -2257,7 +2216,7 @@ 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, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2273,16 +2232,16 @@ 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, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2293,9 +2252,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; @@ -2319,7 +2278,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on element types. return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, MP->getElementType(), MA->getElementType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -2332,14 +2291,14 @@ 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, degradeCallPartialOrderingKind(POK), /*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) { @@ -2376,12 +2335,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, @@ -2405,7 +2365,7 @@ 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, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2416,9 +2376,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())) { @@ -2430,8 +2390,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ASP->getPointeeType(), S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2443,7 +2403,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; @@ -2463,9 +2424,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()) { @@ -2496,8 +2457,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (PIT->hasSelectedType()) { return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PIT->getSelectedType(), A, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } return TemplateDeductionResult::IncompletePack; } @@ -2509,7 +2470,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 @@ -2526,17 +2487,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; @@ -2587,20 +2552,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: @@ -2672,8 +2637,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: @@ -2710,7 +2675,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; @@ -2742,7 +2708,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; @@ -2766,7 +2733,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. @@ -3291,7 +3259,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 @@ -3443,7 +3411,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; @@ -3593,8 +3562,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(); @@ -4247,7 +4216,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; @@ -4434,7 +4403,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; @@ -4480,7 +4449,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); } @@ -4808,7 +4777,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; @@ -4987,7 +4956,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; @@ -5125,9 +5094,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); @@ -5278,7 +5247,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) { @@ -5306,8 +5276,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); } @@ -5650,8 +5620,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, if (TPOC != TPOC_Call) { if (DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(), - Info, Deduced, TDF_None, - /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false, + Info, Deduced, TDF_None, PartialOrderingKind::Call, + /*DeducedFromArrayBound=*/false, &HasDeducedAnyParamFromReturnType) != TemplateDeductionResult::Success) return false; @@ -5661,7 +5631,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, if (TPOC != TPOC_Conversion) { HasDeducedParam.resize(Args2.size()); if (DeduceTemplateArguments(S, TemplateParams, Args2, Args1, Info, Deduced, - TDF_None, /*PartialOrdering=*/true, + TDF_None, PartialOrderingKind::Call, /*HasDeducedAnyParam=*/nullptr, &HasDeducedParam) != TemplateDeductionResult::Success) @@ -5700,11 +5670,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, return ::DeduceForEachType( S, TemplateParams, Args2, Args1, 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) { + SmallVectorImpl &Deduced, + PartialOrderingKind) { return ::CheckDeductionConsistency( S, FTD, ArgIdx, P, A, DeducedArgs, /*CheckConsistency=*/HasDeducedParam[ParamIdx]); @@ -6151,7 +6122,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; @@ -6408,8 +6379,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 @@ -6457,8 +6428,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()) @@ -6483,6 +6455,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 51109b092d7568..6df412cbb09c83 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3920,10 +3920,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 @@ -4028,10 +4028,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. @@ -4296,6 +4296,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( SmallVector SugaredConverted, CanonicalConverted; if (SemaRef.CheckTemplateArgumentList( ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; @@ -4407,9 +4408,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 6fe1bd3d4f1659..1d9747276fbe00 100644 --- a/clang/test/SemaTemplate/cwg2398.cpp +++ b/clang/test/SemaTemplate/cwg2398.cpp @@ -65,26 +65,20 @@ namespace class_template { template struct B; template