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/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 8bce4812f0d482..8818314de93644 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -262,6 +262,8 @@ class ASTContext : public RefCountedBase { mutable llvm::ContextualFoldingSet SubstTemplateTemplateParmPacks; + mutable llvm::ContextualFoldingSet + DeducedTemplates; mutable llvm::ContextualFoldingSet ArrayParameterTypes; @@ -2247,6 +2249,9 @@ class ASTContext : public RefCountedBase { unsigned Index, bool Final) const; + TemplateName getDeducedTemplateName(TemplateName Underlying, + DefaultArguments DefaultArgs) const; + enum GetBuiltinTypeError { /// No error GE_None, @@ -2726,7 +2731,8 @@ 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. diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index 4ffd9138465757..7b890bdf492fa1 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -485,6 +485,11 @@ class TypeSourceInfo; /// the declarations it contains. [[nodiscard]] llvm::Error ImportDefinition(Decl *From); + llvm::Error + ImportTemplateArguments(ArrayRef FromArgs, + SmallVectorImpl &ToArgs); + Expected Import(const TemplateArgument &From); + /// Cope with a name conflict when importing a declaration into the /// given context. /// diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index 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 6df1d93a7ba2eb..bd0b316a4958ae 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -750,6 +750,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,13 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage, unsigned Index, bool Final); }; +struct DefaultArguments { + 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 @@ -245,6 +260,10 @@ class TemplateName { /// A template name that refers to a template declaration found through a /// specific using shadow declaration. UsingTemplate, + + /// A template name that refers to another TemplateName with deduced default + /// arguments. + DeducedTemplate, }; TemplateName() = default; @@ -256,6 +275,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; @@ -272,6 +292,12 @@ class TemplateName { /// set of function templates, returns NULL. TemplateDecl *getAsTemplateDecl() 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. /// @@ -312,6 +338,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; @@ -409,6 +440,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, ASTContext &Context); + + static void Profile(llvm::FoldingSetNodeID &ID, 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 4d4579fcfd456b..ce7066a76eaecd 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9210,6 +9210,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: @@ -9219,7 +9222,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, @@ -9718,8 +9722,8 @@ class Sema final : public SemaBase { sema::TemplateDeductionInfo &Info); bool isTemplateTemplateParameterAtLeastAsSpecializedAs( - TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc, - bool IsDeduced); + TemplateParameterList *PParam, TemplateDecl *AArg, + const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced); void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cd76b8aa271dab..9c8f92cd60b7b7 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -880,8 +880,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()), DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()), - ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()), - SourceMgr(SM), LangOpts(LOpts), + DeducedTemplates(this_()), ArrayParameterTypes(this_()), + CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, @@ -5043,7 +5043,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); @@ -6327,16 +6332,22 @@ 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 { +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)) @@ -6356,12 +6367,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(); @@ -6371,6 +6376,70 @@ 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(); + + bool NonCanonical = false; + TemplateName CanonUnderlying = + getCanonicalTemplateName(Underlying, /*IgnoreDeduced=*/true); + NonCanonical |= CanonUnderlying != Underlying; + auto CanonArgs = + getCanonicalTemplateArguments(*this, DefArgs.Args, NonCanonical); + { + unsigned NumArgs = CanonArgs.size() - 1; + auto handleParamDefArg = [&](const TemplateArgument &ParamDefArg, + unsigned I) { + auto CanonParamDefArg = getCanonicalTemplateArgument(ParamDefArg); + TemplateArgument &CanonDefArg = CanonArgs[I]; + if (CanonDefArg.structurallyEquals(CanonParamDefArg)) + return; + if (I == NumArgs) + CanonArgs.pop_back(); + NonCanonical = true; + }; + auto handleParam = [&](auto *TP, int I) -> bool { + if (!TP->hasDefaultArgument()) + return true; + handleParamDefArg(TP->getDefaultArgument().getArgument(), I); + return false; + }; + + ArrayRef Params = CanonUnderlying.getAsTemplateDecl() + ->getTemplateParameters() + ->asArray(); + assert(CanonArgs.size() <= Params.size()); + for (int I = NumArgs; I >= 0; --I) { + switch (auto *Param = Params[I]; Param->getKind()) { + case NamedDecl::TemplateTypeParm: + if (handleParam(cast(Param), I)) + break; + continue; + case NamedDecl::NonTypeTemplateParm: + if (handleParam(cast(Param), I)) + break; + continue; + case NamedDecl::TemplateTemplateParm: + if (handleParam(cast(Param), I)) + break; + continue; + default: + llvm_unreachable("Unexpected template parameter kind"); + } + break; + } + } + 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!"); @@ -6868,7 +6937,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()), @@ -6880,8 +6949,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; } } @@ -9434,6 +9505,32 @@ 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; + + auto &Self = const_cast(*this); + llvm::FoldingSetNodeID ID; + DeducedTemplateStorage::Profile(ID, Self, 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. diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 0680ff5e3a3851..18463d72514b13 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; @@ -1427,20 +1427,22 @@ 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()) == + Context.getCanonicalTemplateName(ToTST->getTemplateName()); } /// 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 +1457,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 +2125,7 @@ class TemplateDiff { return; // Different base templates. - if (!hasSameTemplate(FromOrigTST, ToOrigTST)) { + if (!hasSameTemplate(Context, FromOrigTST, ToOrigTST)) { return; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 3b9080e09b3313..55d259340ef639 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -420,13 +420,8 @@ namespace clang { Error ImportDefinition( ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind = IDK_Default); - Error ImportDefinition( - ObjCProtocolDecl *From, ObjCProtocolDecl *To, - ImportDefinitionKind Kind = IDK_Default); - Error ImportTemplateArguments(ArrayRef FromArgs, - SmallVectorImpl &ToArgs); - Expected - ImportTemplateArgument(const TemplateArgument &From); + Error ImportDefinition(ObjCProtocolDecl *From, ObjCProtocolDecl *To, + ImportDefinitionKind Kind = IDK_Default); template Error ImportTemplateArgumentListInfo( @@ -746,8 +741,8 @@ ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization( return std::move(Err); // Import template arguments. - if (Error Err = ImportTemplateArguments(FTSInfo->TemplateArguments->asArray(), - std::get<1>(Result))) + if (Error Err = Importer.ImportTemplateArguments( + FTSInfo->TemplateArguments->asArray(), std::get<1>(Result))) return std::move(Err); return Result; @@ -783,15 +778,13 @@ ASTNodeImporter::import(TemplateParameterList *From) { *ToRequiresClause); } -template <> -Expected -ASTNodeImporter::import(const TemplateArgument &From) { +Expected ASTImporter::Import(const TemplateArgument &From) { switch (From.getKind()) { case TemplateArgument::Null: return TemplateArgument(); case TemplateArgument::Type: { - ExpectedType ToTypeOrErr = import(From.getAsType()); + ExpectedType ToTypeOrErr = Import(From.getAsType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(*ToTypeOrErr, /*isNullPtr*/ false, @@ -799,17 +792,17 @@ ASTNodeImporter::import(const TemplateArgument &From) { } case TemplateArgument::Integral: { - ExpectedType ToTypeOrErr = import(From.getIntegralType()); + ExpectedType ToTypeOrErr = Import(From.getIntegralType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(From, *ToTypeOrErr); } case TemplateArgument::Declaration: { - Expected ToOrErr = import(From.getAsDecl()); + Expected ToOrErr = Import(From.getAsDecl()); if (!ToOrErr) return ToOrErr.takeError(); - ExpectedType ToTypeOrErr = import(From.getParamTypeForDecl()); + ExpectedType ToTypeOrErr = Import(From.getParamTypeForDecl()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(dyn_cast((*ToOrErr)->getCanonicalDecl()), @@ -817,7 +810,7 @@ ASTNodeImporter::import(const TemplateArgument &From) { } case TemplateArgument::NullPtr: { - ExpectedType ToTypeOrErr = import(From.getNullPtrType()); + ExpectedType ToTypeOrErr = Import(From.getNullPtrType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(*ToTypeOrErr, /*isNullPtr*/ true, @@ -825,18 +818,17 @@ ASTNodeImporter::import(const TemplateArgument &From) { } case TemplateArgument::StructuralValue: { - ExpectedType ToTypeOrErr = import(From.getStructuralValueType()); + ExpectedType ToTypeOrErr = Import(From.getStructuralValueType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); - Expected ToValueOrErr = import(From.getAsStructuralValue()); + Expected ToValueOrErr = Import(From.getAsStructuralValue()); if (!ToValueOrErr) return ToValueOrErr.takeError(); - return TemplateArgument(Importer.getToContext(), *ToTypeOrErr, - *ToValueOrErr); + return TemplateArgument(getToContext(), *ToTypeOrErr, *ToValueOrErr); } case TemplateArgument::Template: { - Expected ToTemplateOrErr = import(From.getAsTemplate()); + Expected ToTemplateOrErr = Import(From.getAsTemplate()); if (!ToTemplateOrErr) return ToTemplateOrErr.takeError(); @@ -845,7 +837,7 @@ ASTNodeImporter::import(const TemplateArgument &From) { case TemplateArgument::TemplateExpansion: { Expected ToTemplateOrErr = - import(From.getAsTemplateOrTemplatePattern()); + Import(From.getAsTemplateOrTemplatePattern()); if (!ToTemplateOrErr) return ToTemplateOrErr.takeError(); @@ -854,7 +846,7 @@ ASTNodeImporter::import(const TemplateArgument &From) { } case TemplateArgument::Expression: - if (ExpectedExpr ToExpr = import(From.getAsExpr())) + if (ExpectedExpr ToExpr = Import(From.getAsExpr())) return TemplateArgument(*ToExpr, From.getIsDefaulted()); else return ToExpr.takeError(); @@ -865,8 +857,7 @@ ASTNodeImporter::import(const TemplateArgument &From) { if (Error Err = ImportTemplateArguments(From.pack_elements(), ToPack)) return std::move(Err); - return TemplateArgument( - llvm::ArrayRef(ToPack).copy(Importer.getToContext())); + return TemplateArgument(llvm::ArrayRef(ToPack).copy(getToContext())); } } @@ -1472,8 +1463,8 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) { return ToTypeConstraintConcept.takeError(); SmallVector ToTemplateArgs; - if (Error Err = ImportTemplateArguments(T->getTypeConstraintArguments(), - ToTemplateArgs)) + if (Error Err = Importer.ImportTemplateArguments( + T->getTypeConstraintArguments(), ToTemplateArgs)) return std::move(Err); return Importer.getToContext().getAutoType( @@ -1605,8 +1596,8 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( return ToTemplateOrErr.takeError(); SmallVector ToTemplateArgs; - if (Error Err = - ImportTemplateArguments(T->template_arguments(), ToTemplateArgs)) + if (Error Err = Importer.ImportTemplateArguments(T->template_arguments(), + ToTemplateArgs)) return std::move(Err); QualType ToCanonType; @@ -1664,7 +1655,8 @@ ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType( SmallVector ToPack; ToPack.reserve(T->template_arguments().size()); - if (Error Err = ImportTemplateArguments(T->template_arguments(), ToPack)) + if (Error Err = + Importer.ImportTemplateArguments(T->template_arguments(), ToPack)) return std::move(Err); return Importer.getToContext().getDependentTemplateSpecializationType( @@ -2386,11 +2378,11 @@ Error ASTNodeImporter::ImportDefinition( return Error::success(); } -Error ASTNodeImporter::ImportTemplateArguments( +Error ASTImporter::ImportTemplateArguments( ArrayRef FromArgs, SmallVectorImpl &ToArgs) { for (const auto &Arg : FromArgs) { - if (auto ToOrErr = import(Arg)) + if (auto ToOrErr = Import(Arg)) ToArgs.push_back(*ToOrErr); else return ToOrErr.takeError(); @@ -2399,12 +2391,6 @@ Error ASTNodeImporter::ImportTemplateArguments( return Error::success(); } -// FIXME: Do not forget to remove this and use only 'import'. -Expected -ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { - return import(From); -} - template Error ASTNodeImporter::ImportTemplateArgumentListInfo( const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo) { @@ -6147,8 +6133,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Import template arguments. SmallVector TemplateArgs; - if (Error Err = - ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs)) + if (Error Err = Importer.ImportTemplateArguments( + D->getTemplateArgs().asArray(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments and // template parameter list. @@ -6484,8 +6470,8 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( // Import template arguments. SmallVector TemplateArgs; - if (Error Err = - ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs)) + if (Error Err = Importer.ImportTemplateArguments( + D->getTemplateArgs().asArray(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments. @@ -8225,8 +8211,8 @@ ExpectedStmt ASTNodeImporter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { SmallVector ToPartialArguments; if (E->isPartiallySubstituted()) { - if (Error Err = ImportTemplateArguments(E->getPartialArguments(), - ToPartialArguments)) + if (Error Err = Importer.ImportTemplateArguments(E->getPartialArguments(), + ToPartialArguments)) return std::move(Err); } @@ -9868,8 +9854,7 @@ Expected ASTImporter::Import(TemplateName From) { SubstTemplateTemplateParmPackStorage *SubstPack = From.getAsSubstTemplateTemplateParmPack(); ASTNodeImporter Importer(*this); - auto ArgPackOrErr = - Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); + auto ArgPackOrErr = Import(SubstPack->getArgumentPack()); if (!ArgPackOrErr) return ArgPackOrErr.takeError(); @@ -9887,6 +9872,19 @@ Expected ASTImporter::Import(TemplateName From) { return UsingOrError.takeError(); return TemplateName(cast(*UsingOrError)); } + case TemplateName::DeducedTemplate: { + DeducedTemplateStorage *S = From.getAsDeducedTemplateName(); + auto UnderlyingOrError = Import(S->getUnderlying()); + if (!UnderlyingOrError) + return UnderlyingOrError.takeError(); + + DefaultArguments FromDefArgs = S->getDefaultArguments(); + SmallVector ToTemplateArgs; + if (Error Err = ImportTemplateArguments(FromDefArgs.Args, ToTemplateArgs)) + return std::move(Err); + return ToContext.getDeducedTemplateName( + *UnderlyingOrError, {FromDefArgs.StartPos, ToTemplateArgs}); + } } llvm_unreachable("Invalid template name kind"); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index d56bf21b459e03..8f651f29a0d3fb 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -636,6 +636,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/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index ed9e6eeb36c75d..ae9bd194fecb09 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2385,6 +2385,16 @@ void CXXNameMangler::mangleType(TemplateName TN) { Out << "_SUBSTPACK_"; break; } + case TemplateName::DeducedTemplate: { + DeducedTemplateStorage *S = TN.getAsDeducedTemplateName(); + mangleType(S->getUnderlying()); + auto [StartPos, Args] = S->getDefaultArguments(); + mangleNumber(StartPos); + Out << 'I'; + for (unsigned I = 0; I != Args.size(); ++I) + mangleTemplateArg(Args[I], /*NeedExactType=*/true); + Out << 'E'; + } } addSubstitution(TN); @@ -2502,6 +2512,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case TemplateName::OverloadedTemplate: case TemplateName::AssumedTemplate: case TemplateName::DependentTemplate: + case TemplateName::DeducedTemplate: llvm_unreachable("invalid base for a template specialization type"); case TemplateName::SubstTemplateTemplateParm: { diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 1249531eab09fc..2366cd5a441a60 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -161,6 +161,7 @@ void ODRHash::AddTemplateName(TemplateName Name) { case TemplateName::SubstTemplateTemplateParm: case TemplateName::SubstTemplateTemplateParmPack: case TemplateName::UsingTemplate: + case TemplateName::DeducedTemplate: break; } } diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 11544dbb56e31d..071043725f7829 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, + ASTContext &Context) { + Profile(ID, Context, Underlying, getDefaultArguments()); +} + +void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID, + 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,61 @@ 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()); + TemplateName Name = *this; + while (std::optional UnderlyingOrNone = + Name.desugar(/*IgnoreDeduced=*/false)) + Name = *UnderlyingOrNone; - assert(isa(TemplateOrUsing)); + if (Decl *TemplateOrUsing = Name.Storage.dyn_cast()) return cast(TemplateOrUsing); + return nullptr; +} + +std::pair +TemplateName::getTemplateDeclAndDefaultArgs() const { + DefaultArguments DefArgs; + for (TemplateName Name = *this; /**/; /**/) { + if (!DefArgs && Name.getKind() == TemplateName::DeducedTemplate) { + DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName(); + Name = DTS->getUnderlying(); + DefArgs = DTS->getDefaultArguments(); + continue; + } + if (std::optional UnderlyingOrNone = + Name.desugar(/*IgnoreDeduced=*/DefArgs)) { + Name = *UnderlyingOrNone; + continue; + } + TemplateDecl *TD = Name.getAsTemplateDecl(); + if (TD && DefArgs != 0) + assert(DefArgs.StartPos + DefArgs.Args.size() <= + TD->getTemplateParameters()->size()); + return {TD, DefArgs}; } +} +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().getAsTemplateDecl(); - - if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm()) - return sub->getReplacement().getAsTemplateDecl(); - - if (UsingShadowDecl *USD = getAsUsingShadowDecl()) - return cast(USD->getTargetDecl()); - - return nullptr; + 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 +273,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 +299,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 { @@ -340,6 +424,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 1076dcd40a694a..1dff7964494213 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 33acae2cbafacf..7efa89b4625e2a 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4289,7 +4289,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/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 40a759ea330de4..fab43e7a1c0a63 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4580,8 +4580,8 @@ Sema::findFailedBooleanCondition(Expr *Cond) { QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { - DependentTemplateName *DTN - = Name.getUnderlying().getAsDependentTemplateName(); + DependentTemplateName *DTN = + Name.getUnderlying().getAsDependentTemplateName(); if (DTN && DTN->isIdentifier()) // When building a template-id where the template-name is dependent, // assume the template is a type template. Either our assumption is @@ -4592,10 +4592,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TemplateArgs.arguments()); if (Name.getAsAssumedTemplateName() && - resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) + resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc)) return QualType(); - TemplateDecl *Template = Name.getAsTemplateDecl(); + auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); + if (!Template || isa(Template) || isa(Template) || isa(Template)) { // We might have a substituted template template parameter pack. If so, @@ -4613,8 +4614,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. SmallVector SugaredConverted, CanonicalConverted; - if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, - SugaredConverted, CanonicalConverted, + if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, + DefaultArgs, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return QualType(); @@ -5280,7 +5282,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -5447,8 +5450,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList( Template, TemplateNameLoc, - const_cast(TemplateArgs), false, - SugaredConverted, CanonicalConverted, + const_cast(TemplateArgs), + /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -5642,6 +5645,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, if (CheckTemplateArgumentList( NamedConcept, ConceptNameInfo.getLoc(), const_cast(*TemplateArgs), + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/false)) return ExprError(); @@ -6610,7 +6614,8 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, /// for specializing the given template. bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, + TemplateArgumentListInfo &TemplateArgs, const DefaultArguments &DefaultArgs, + bool PartialTemplateArgs, SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied, @@ -6638,9 +6643,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)) { @@ -6854,6 +6879,7 @@ bool Sema::CheckTemplateArgumentList( CTAK_Specified)) return true; + SugaredConverted.back().setIsDefaulted(true); CanonicalConverted.back().setIsDefaulted(true); // Core issue 150 (assumed resolution): if this is a template template @@ -8454,7 +8480,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateArgumentLoc &Arg, bool IsDeduced) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); - TemplateDecl *Template = Name.getAsTemplateDecl(); + auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); if (!Template) { // Any dependent template name is fine. assert(Name.isDependent() && "Non-dependent template isn't a declaration?"); @@ -8505,7 +8531,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, return false; if (isTemplateTemplateParameterAtLeastAsSpecializedAs( - Params, Template, Arg.getLocation(), IsDeduced)) { + Params, Template, DefaultArgs, Arg.getLocation(), IsDeduced)) { // P2113 // C++20[temp.func.order]p2 // [...] If both deductions succeed, the partial ordering selects the @@ -9591,7 +9617,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, + /*PartialTemplateArgs=*/false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -10963,7 +10991,8 @@ DeclResult Sema::ActOnExplicitInstantiation( // template. SmallVector 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 befeb38e1fe5bc..bda9872f36e54c 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -509,61 +509,6 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced); } -/// Create a shallow copy of a given template parameter declaration, with -/// empty source locations and using the given TemplateArgument as it's -/// default argument. -/// -/// \returns The new template parameter declaration. -static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A, - TemplateArgument Default) { - switch (A->getKind()) { - case Decl::TemplateTypeParm: { - auto *T = cast(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"); - } -} - static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, TemplateName Param, TemplateName Arg, @@ -582,42 +527,28 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (TempParam->getDepth() != Info.getDeducedDepth()) return TemplateDeductionResult::Success; - auto NewDeduced = DeducedTemplateArgument(Arg); - // Provisional resolution for CWG2398: If Arg is also a template template - // param, and it names a template specialization, then we deduce a - // synthesized template template parameter based on A, but using the TS's - // arguments as defaults. - if (auto *TempArg = dyn_cast_or_null( - 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 = + TemplateArgument(S.Context.getDeducedTemplateName( + Arg, {StartPos, DefaultArguments.drop_front(StartPos)})); + + DeducedTemplateArgument Result = checkDeducedTemplateArguments( + S.Context, Deduced[TempParam->getIndex()], NewDeduced); if (Result.isNull()) { Info.Param = TempParam; Info.FirstArg = Deduced[TempParam->getIndex()]; @@ -3194,7 +3125,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 @@ -3516,8 +3447,8 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( return TemplateDeductionResult::InstantiationDepth; if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), - ExplicitTemplateArgs, true, SugaredBuilder, - CanonicalBuilder, + ExplicitTemplateArgs, /*DefaultArgs=*/{}, true, + SugaredBuilder, CanonicalBuilder, /*UpdateArgsWithConversions=*/false) || Trap.hasErrorOccurred()) { unsigned Index = SugaredBuilder.size(); @@ -5127,9 +5058,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); @@ -6361,8 +6292,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 @@ -6410,8 +6341,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()) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 0681520764d9a0..26b2fa793b48ac 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3878,10 +3878,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Check that the template argument list is well-formed for this // class template. SmallVector SugaredConverted, CanonicalConverted; - if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, D->getLocation(), - InstTemplateArgs, false, - SugaredConverted, CanonicalConverted, - /*UpdateArgsWithConversions=*/true)) + if (SemaRef.CheckTemplateArgumentList( + InstClassTemplate, D->getLocation(), InstTemplateArgs, + /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return nullptr; // Figure out where to insert this class template explicit specialization @@ -3986,10 +3986,10 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector SugaredConverted, CanonicalConverted; - if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), - VarTemplateArgsInfo, false, - SugaredConverted, CanonicalConverted, - /*UpdateArgsWithConversions=*/true)) + if (SemaRef.CheckTemplateArgumentList( + InstVarTemplate, D->getLocation(), VarTemplateArgsInfo, + /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return nullptr; // Check whether we've already seen a declaration of this specialization. @@ -4254,6 +4254,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( SmallVector SugaredConverted, CanonicalConverted; if (SemaRef.CheckTemplateArgumentList( ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; @@ -4365,9 +4366,10 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // Check that the template argument list is well-formed for this // class template. SmallVector SugaredConverted, CanonicalConverted; - if (SemaRef.CheckTemplateArgumentList( - VarTemplate, PartialSpec->getLocation(), InstTemplateArgs, - /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) + if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(), + InstTemplateArgs, /*DefaultArgs=*/{}, + /*PartialTemplateArgs=*/false, + SugaredConverted, CanonicalConverted)) return nullptr; // Check these arguments are valid for a template partial specialization. diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp index a5b39fe5c51f70..bc39431253880c 100644 --- a/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp @@ -28,13 +28,14 @@ namespace StdExample { { /* ... */ } template class TT> - void f(TT); // expected-note {{candidate template ignored}} + void f(TT); template class TT> void g(TT>); int h() { - f(v); // expected-error {{no matching function for call to 'f'}} + f(v); // OK: TT = vector, Alloc is used as the default argument for the + // second parameter. g(v); // OK: TT = vector } diff --git a/clang/test/CodeGenCXX/mangle-cwg2398.cpp b/clang/test/CodeGenCXX/mangle-cwg2398.cpp new file mode 100644 index 00000000000000..a8a0aed17c70f6 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-cwg2398.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-pc -emit-llvm -o - %s | FileCheck %s + +template struct A {}; + +template class TT> void f(TT); + +// CHECK-LABEL: define{{.*}} void @_Z1zv( +void z() { + f(A()); + // CHECK: call void @_Z1fITtTyE1A1IdEEvT_IiE() +} diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp index 7675d4287cb88a..3548a8f26f024c 100644 --- a/clang/test/SemaTemplate/cwg2398.cpp +++ b/clang/test/SemaTemplate/cwg2398.cpp @@ -4,12 +4,11 @@ namespace issue1 { template class B {}; template class P, class T> void f(P); - // new-note@-1 {{deduced type 'B<[...], (default) int>' of 1st parameter does not match adjusted type 'B<[...], float>' of argument [with P = B, T = int]}} - // old-note@-2 2{{template template argument has different template parameters}} + // old-note@-1 2{{template template argument has different template parameters}} void g() { f(B()); // old-error {{no matching function for call}} - f(B()); // expected-error {{no matching function for call}} + f(B()); // old-error {{no matching function for call}} } } // namespace issue1 @@ -65,13 +64,10 @@ namespace class_template { template struct B; template