diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 88621809bad7e25..d60d88920c6d0fa 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -569,9 +569,6 @@ Bug Fixes to C++ Support in certain friend declarations. (#GH93099) - Clang now instantiates the correct lambda call operator when a lambda's class type is merged across modules. (#GH110401) -- Clang now uses the correct set of template argument lists when comparing the constraints of - out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of - a class template. (#GH102320) - Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460) - Fixed an assertion failure when invoking recovery call expressions with explicit attributes and undeclared templates. (#GH107047), (#GH49093) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index a572e3380f16550..e4bf54c3d77b7f8 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -787,11 +787,15 @@ class RedeclarableTemplateDecl : public TemplateDecl, EntryType *Entry, void *InsertPos); struct CommonBase { - CommonBase() {} + CommonBase() : InstantiatedFromMember(nullptr, false) {} /// The template from which this was most /// directly instantiated (or null). - RedeclarableTemplateDecl *InstantiatedFromMember = nullptr; + /// + /// The boolean value indicates whether this template + /// was explicitly specialized. + llvm::PointerIntPair + InstantiatedFromMember; /// If non-null, points to an array of specializations (including /// partial specializations) known only by their external declaration IDs. @@ -802,19 +806,14 @@ class RedeclarableTemplateDecl : public TemplateDecl, }; /// Pointer to the common data shared by all declarations of this - /// template, and a flag indicating if the template is a member - /// specialization. - mutable llvm::PointerIntPair Common; - - CommonBase *getCommonPtrInternal() const { return Common.getPointer(); } + /// template. + mutable CommonBase *Common = nullptr; /// Retrieves the "common" pointer shared by all (re-)declarations of /// the same template. Calling this routine may implicitly allocate memory /// for the common pointer. CommonBase *getCommonPtr() const; - void setCommonPtr(CommonBase *C) const { Common.setPointer(C); } - virtual CommonBase *newCommon(ASTContext &C) const = 0; // Construct a template decl with name, parameters, and templated element. @@ -855,22 +854,15 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// template<> template /// struct X::Inner { /* ... */ }; /// \endcode - bool isMemberSpecialization() const { return Common.getInt(); } - - /// Determines whether any redeclaration of this template was - /// a specialization of a member template. - bool hasMemberSpecialization() const { - for (const auto *D : redecls()) { - if (D->isMemberSpecialization()) - return true; - } - return false; + bool isMemberSpecialization() const { + return getCommonPtr()->InstantiatedFromMember.getInt(); } /// Note that this member template is a specialization. void setMemberSpecialization() { - assert(!isMemberSpecialization() && "already a member specialization"); - Common.setInt(true); + assert(getCommonPtr()->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + getCommonPtr()->InstantiatedFromMember.setInt(true); } /// Retrieve the member template from which this template was @@ -910,12 +902,12 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// void X::f(T, U); /// \endcode RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const { - return getCommonPtr()->InstantiatedFromMember; + return getCommonPtr()->InstantiatedFromMember.getPointer(); } void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) { - assert(!getCommonPtr()->InstantiatedFromMember); - getCommonPtr()->InstantiatedFromMember = TD; + assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); + getCommonPtr()->InstantiatedFromMember.setPointer(TD); } /// Retrieve the "injected" template arguments that correspond to the @@ -1997,8 +1989,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// template arguments have been deduced. void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { - assert(!isa(this) && - "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Already set to a class template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); @@ -2010,8 +2000,6 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// Note that this class template specialization is an instantiation /// of the given class template. void setInstantiationOf(ClassTemplateDecl *TemplDecl) { - assert(!isa(this) && - "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Previously set to a class template partial specialization!"); SpecializedTemplate = TemplDecl; @@ -2205,22 +2193,18 @@ class ClassTemplatePartialSpecializationDecl /// struct X::Inner { /* ... */ }; /// \endcode bool isMemberSpecialization() const { - return InstantiatedFromMember.getInt(); - } - - /// Determines whether any redeclaration of this this class template partial - /// specialization was a specialization of a member partial specialization. - bool hasMemberSpecialization() const { - for (const auto *D : redecls()) { - if (cast(D) - ->isMemberSpecialization()) - return true; - } - return false; + const auto *First = + cast(getFirstDecl()); + return First->InstantiatedFromMember.getInt(); } /// Note that this member template is a specialization. - void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } + void setMemberSpecialization() { + auto *First = cast(getFirstDecl()); + assert(First->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + return First->InstantiatedFromMember.setInt(true); + } /// Retrieves the injected specialization type for this partial /// specialization. This is not the same as the type-decl-type for @@ -2290,6 +2274,8 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { return static_cast(RedeclarableTemplateDecl::getCommonPtr()); } + void setCommonPtr(Common *C) { RedeclarableTemplateDecl::Common = C; } + public: friend class ASTDeclReader; @@ -2772,8 +2758,6 @@ class VarTemplateSpecializationDecl : public VarDecl, /// template arguments have been deduced. void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { - assert(!isa(this) && - "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Already set to a variable template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); @@ -2785,8 +2769,6 @@ class VarTemplateSpecializationDecl : public VarDecl, /// Note that this variable template specialization is an instantiation /// of the given variable template. void setInstantiationOf(VarTemplateDecl *TemplDecl) { - assert(!isa(this) && - "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is() && "Previously set to a variable template partial specialization!"); SpecializedTemplate = TemplDecl; @@ -2977,23 +2959,18 @@ class VarTemplatePartialSpecializationDecl /// U* X::Inner = (T*)(0) + 1; /// \endcode bool isMemberSpecialization() const { - return InstantiatedFromMember.getInt(); - } - - /// Determines whether any redeclaration of this this variable template - /// partial specialization was a specialization of a member partial - /// specialization. - bool hasMemberSpecialization() const { - for (const auto *D : redecls()) { - if (cast(D) - ->isMemberSpecialization()) - return true; - } - return false; + const auto *First = + cast(getFirstDecl()); + return First->InstantiatedFromMember.getInt(); } /// Note that this member template is a specialization. - void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } + void setMemberSpecialization() { + auto *First = cast(getFirstDecl()); + assert(First->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + return First->InstantiatedFromMember.setInt(true); + } SourceRange getSourceRange() const override LLVM_READONLY; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 93d98e1cbb9c811..aa2f5ff3ef7207f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11328,9 +11328,9 @@ class Sema final : public SemaBase { CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, - SourceLocation FriendLoc, - ArrayRef OuterTemplateParamLists, - bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr); + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, + TemplateParameterList **OuterTemplateParamLists, + SkipBodyInfo *SkipBody = nullptr); /// Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. @@ -11369,8 +11369,7 @@ class Sema final : public SemaBase { DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, - StorageClass SC, bool IsPartialSpecialization, - bool IsMemberSpecialization); + StorageClass SC, bool IsPartialSpecialization); /// Get the specialization of the given variable template corresponding to /// the specified argument list, or a null-but-valid result if the arguments @@ -13012,14 +13011,28 @@ class Sema final : public SemaBase { /// dealing with a specialization. This is only relevant for function /// template specializations. /// + /// \param Pattern If non-NULL, indicates the pattern from which we will be + /// instantiating the definition of the given declaration, \p ND. This is + /// used to determine the proper set of template instantiation arguments for + /// friend function template specializations. + /// /// \param ForConstraintInstantiation when collecting arguments, /// ForConstraintInstantiation indicates we should continue looking when /// encountering a lambda generic call operator, and continue looking for /// arguments on an enclosing class template. + /// + /// \param SkipForSpecialization when specified, any template specializations + /// in a traversal would be ignored. + /// \param ForDefaultArgumentSubstitution indicates we should continue looking + /// when encountering a specialized member function template, rather than + /// returning immediately. MultiLevelTemplateArgumentList getTemplateInstantiationArgs( const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false, std::optional> Innermost = std::nullopt, - bool RelativeToPrimary = false, bool ForConstraintInstantiation = false); + bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, + bool ForConstraintInstantiation = false, + bool SkipForSpecialization = false, + bool ForDefaultArgumentSubstitution = false); /// RAII object to handle the state changes required to synthesize /// a function body. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 86913763ef9ff59..8204e3509dd5635 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2708,21 +2708,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) { auto From = VDTemplSpec->getInstantiatedFrom(); if (auto *VTD = From.dyn_cast()) { - while (!VTD->hasMemberSpecialization()) { - if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) - VTD = NewVTD; - else + while (!VTD->isMemberSpecialization()) { + auto *NewVTD = VTD->getInstantiatedFromMemberTemplate(); + if (!NewVTD) break; + VTD = NewVTD; } return getDefinitionOrSelf(VTD->getTemplatedDecl()); } if (auto *VTPSD = From.dyn_cast()) { - while (!VTPSD->hasMemberSpecialization()) { - if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) - VTPSD = NewVTPSD; - else + while (!VTPSD->isMemberSpecialization()) { + auto *NewVTPSD = VTPSD->getInstantiatedFromMember(); + if (!NewVTPSD) break; + VTPSD = NewVTPSD; } return getDefinitionOrSelf(VTPSD); } @@ -2731,14 +2731,15 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { // If this is the pattern of a variable template, find where it was // instantiated from. FIXME: Is this necessary? - if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) { - while (!VTD->hasMemberSpecialization()) { - if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) - VTD = NewVTD; - else + if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) { + while (!VarTemplate->isMemberSpecialization()) { + auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate(); + if (!NewVT) break; + VarTemplate = NewVT; } - return getDefinitionOrSelf(VTD->getTemplatedDecl()); + + return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); } if (VD == this) @@ -4153,11 +4154,11 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const { if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { // If we hit a point where the user provided a specialization of this // template, we're done looking. - while (!ForDefinition || !Primary->hasMemberSpecialization()) { - if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate()) - Primary = NewPrimary; - else + while (!ForDefinition || !Primary->isMemberSpecialization()) { + auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate(); + if (!NewPrimary) break; + Primary = NewPrimary; } return getDefinitionOrSelf(Primary->getTemplatedDecl()); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index db0ea62a2323eb0..4394a0724b3c17c 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2030,21 +2030,19 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (!CTD->hasMemberSpecialization()) { - if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) - CTD = NewCTD; - else + while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { + if (NewCTD->isMemberSpecialization()) break; + CTD = NewCTD; } return GetDefinitionOrSelf(CTD->getTemplatedDecl()); } if (auto *CTPSD = From.dyn_cast()) { - while (!CTPSD->hasMemberSpecialization()) { - if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate()) - CTPSD = NewCTPSD; - else + while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { + if (NewCTPSD->isMemberSpecialization()) break; + CTPSD = NewCTPSD; } return GetDefinitionOrSelf(CTPSD); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 755ec72f00bf771..a221d619672b388 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -320,16 +320,16 @@ bool TemplateDecl::isTypeAlias() const { void RedeclarableTemplateDecl::anchor() {} RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const { - if (CommonBase *C = getCommonPtrInternal()) - return C; + if (Common) + return Common; // Walk the previous-declaration chain until we either find a declaration // with a common pointer or we run out of previous declarations. SmallVector PrevDecls; for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { - if (CommonBase *C = Prev->getCommonPtrInternal()) { - setCommonPtr(C); + if (Prev->Common) { + Common = Prev->Common; break; } @@ -337,18 +337,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c } // If we never found a common pointer, allocate one now. - if (!getCommonPtrInternal()) { + if (!Common) { // FIXME: If any of the declarations is from an AST file, we probably // need an update record to add the common data. - setCommonPtr(newCommon(getASTContext())); + Common = newCommon(getASTContext()); } // Update any previous declarations we saw with the common pointer. for (const RedeclarableTemplateDecl *Prev : PrevDecls) - Prev->setCommonPtr(getCommonPtrInternal()); + Prev->Common = Common; - return getCommonPtrInternal(); + return Common; } void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { @@ -458,17 +458,19 @@ void FunctionTemplateDecl::addSpecialization( } void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { + using Base = RedeclarableTemplateDecl; + // If we haven't created a common pointer yet, then it can just be created // with the usual method. - if (!getCommonPtrInternal()) + if (!Base::Common) return; - Common *ThisCommon = static_cast(getCommonPtrInternal()); + Common *ThisCommon = static_cast(Base::Common); Common *PrevCommon = nullptr; SmallVector PreviousDecls; for (; Prev; Prev = Prev->getPreviousDecl()) { - if (CommonBase *C = Prev->getCommonPtrInternal()) { - PrevCommon = static_cast(C); + if (Prev->Base::Common) { + PrevCommon = static_cast(Prev->Base::Common); break; } PreviousDecls.push_back(Prev); @@ -478,7 +480,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { // use this common pointer. if (!PrevCommon) { for (auto *D : PreviousDecls) - D->setCommonPtr(ThisCommon); + D->Base::Common = ThisCommon; return; } @@ -486,7 +488,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { assert(ThisCommon->Specializations.size() == 0 && "Can't merge incompatible declarations!"); - setCommonPtr(PrevCommon); + Base::Common = PrevCommon; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index bc988001ea7e467..0f373da6275e7ed 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -585,7 +585,7 @@ static bool CheckConstraintSatisfaction( ArrayRef TemplateArgs = TemplateArgsLists.getNumSubstitutedLevels() > 0 - ? TemplateArgsLists.getInnermost() + ? TemplateArgsLists.getOutermost() : ArrayRef{}; Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), Sema::InstantiatingTemplate::ConstraintsCheck{}, @@ -834,6 +834,7 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope( getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) return std::nullopt; @@ -909,13 +910,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, // Figure out the to-translation-unit depth for this function declaration for // the purpose of seeing if they differ by constraints. This isn't the same as // getTemplateDepth, because it includes already instantiated parents. -static unsigned CalculateTemplateDepthForConstraints(Sema &S, - const NamedDecl *ND) { +static unsigned +CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, + bool SkipForSpecialization = false) { MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( ND, ND->getLexicalDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, - /*ForConstraintInstantiation=*/true); + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true, SkipForSpecialization); return MLTAL.getNumLevels(); } @@ -954,7 +957,8 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, - /*ForConstraintInstantiation=*/true); + /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true, + /*SkipForSpecialization*/ false); if (MLTAL.getNumSubstitutedLevels() == 0) return ConstrExpr; @@ -1064,16 +1068,16 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old, bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) { assert(FD->getFriendObjectKind() && "Must be a friend!"); - FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate(); // The logic for non-templates is handled in ASTContext::isSameEntity, so we // don't have to bother checking 'DependsOnEnclosingTemplate' for a // non-function-template. - assert(FTD && "Non-function templates don't need to be checked"); + assert(FD->getDescribedFunctionTemplate() && + "Non-function templates don't need to be checked"); SmallVector ACs; - FTD->getAssociatedConstraints(ACs); + FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs); - unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth(); + unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD); for (const Expr *Constraint : ACs) if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth, Constraint)) @@ -1520,6 +1524,7 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(), /*Final=*/false, CSE->getTemplateArguments(), /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL, @@ -1800,8 +1805,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, return false; } - unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1); - unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2); + unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true); + unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true); for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) { if (Depth2 > Depth1) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 39be3f889b0bcb1..cc0019eaf4f0214 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4511,10 +4511,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { adjustDeclContextForDeclaratorDecl(New, Old); // Ensure the template parameters are compatible. - if (NewTemplate && !TemplateParameterListsAreEqual( - NewTemplate, NewTemplate->getTemplateParameters(), - OldTemplate, OldTemplate->getTemplateParameters(), - /*Complain=*/true, TPL_TemplateMatch)) + if (NewTemplate && + !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), + OldTemplate->getTemplateParameters(), + /*Complain=*/true, TPL_TemplateMatch)) return New->setInvalidDecl(); // C++ [class.mem]p1: @@ -7676,7 +7676,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( : SourceLocation(); DeclResult Res = ActOnVarTemplateSpecialization( S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC, - IsPartialSpecialization, IsMemberSpecialization); + IsPartialSpecialization); if (Res.isInvalid()) return nullptr; NewVD = cast(Res.get()); @@ -7695,10 +7695,6 @@ NamedDecl *Sema::ActOnVariableDeclarator( VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, TemplateParams, NewVD); NewVD->setDescribedVarTemplate(NewTemplate); - // If we are providing an explicit specialization of a static variable - // template, make a note of that. - if (IsMemberSpecialization) - NewTemplate->setMemberSpecialization(); } // If this decl has an auto type in need of deduction, make a note of the @@ -8079,6 +8075,12 @@ NamedDecl *Sema::ActOnVariableDeclarator( ? TPC_ClassTemplateMember : TPC_VarTemplate)) NewVD->setInvalidDecl(); + + // If we are providing an explicit specialization of a static variable + // template, make a note of that. + if (PrevVarTemplate && + PrevVarTemplate->getInstantiatedFromMemberTemplate()) + PrevVarTemplate->setMemberSpecialization(); } } @@ -9885,8 +9887,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD); FunctionTemplate->setLexicalDeclContext(CurContext); NewFD->setDescribedFunctionTemplate(FunctionTemplate); - if (isMemberSpecialization) - FunctionTemplate->setMemberSpecialization(); // For source fidelity, store the other template param lists. if (TemplateParamLists.size() > 1) { @@ -12044,7 +12044,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // If this is an explicit specialization of a member that is a function // template, mark it as a member specialization. - if (IsMemberSpecialization) { + if (IsMemberSpecialization && + NewTemplateDecl->getInstantiatedFromMemberTemplate()) { + NewTemplateDecl->setMemberSpecialization(); + assert(OldTemplateDecl->isMemberSpecialization()); // Explicit specializations of a member template do not inherit deleted // status from the parent member template that they are specializing. if (OldFD->isDeleted()) { @@ -17118,8 +17121,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, DeclResult Result = CheckClassTemplate( S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, AS, ModulePrivateLoc, - /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(), - isMemberSpecialization, SkipBody); + /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, + TemplateParameterLists.data(), SkipBody); return Result.get(); } else { // The "template<>" header is extraneous. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1a691c0e1689d67..8d76a35b2d25577 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17410,8 +17410,8 @@ DeclResult Sema::ActOnTemplatedFriendTag( return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS, Name, NameLoc, Attr, TemplateParams, AS_public, /*ModulePrivateLoc=*/SourceLocation(), - FriendLoc, TempParamLists.drop_back(), - IsMemberSpecialization) + FriendLoc, TempParamLists.size() - 1, + TempParamLists.data()) .get(); } else { // The "template<>" header is extraneous. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index cba66d82406cddc..f13355bb93cbebc 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -9957,7 +9957,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) { auto *Pattern = Template; while (Pattern->getInstantiatedFromMemberTemplate()) { - if (Pattern->hasMemberSpecialization()) + if (Pattern->isMemberSpecialization()) break; Pattern = Pattern->getInstantiatedFromMemberTemplate(); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4503e60cff8c2f0..852721944e2fa0e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1795,9 +1795,8 @@ DeclResult Sema::CheckClassTemplate( CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, - SourceLocation FriendLoc, - ArrayRef OuterTemplateParamLists, - bool IsMemberSpecialization, SkipBodyInfo *SkipBody) { + SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, + TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) { assert(TemplateParams && TemplateParams->size() > 0 && "No template parameters"); assert(TUK != TagUseKind::Reference && @@ -1985,6 +1984,19 @@ DeclResult Sema::CheckClassTemplate( } if (PrevClassTemplate) { + // Ensure that the template parameter lists are compatible. Skip this check + // for a friend in a dependent context: the template parameter list itself + // could be dependent. + if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && + !TemplateParameterListsAreEqual( + TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext + : CurContext, + CurContext, KWLoc), + TemplateParams, PrevClassTemplate, + PrevClassTemplate->getTemplateParameters(), /*Complain=*/true, + TPL_TemplateMatch)) + return true; + // C++ [temp.class]p4: // In a redeclaration, partial specialization, explicit // specialization or explicit instantiation of a class template, @@ -1999,6 +2011,30 @@ DeclResult Sema::CheckClassTemplate( Diag(PrevRecordDecl->getLocation(), diag::note_previous_use); Kind = PrevRecordDecl->getTagKind(); } + + // Check for redefinition of this class template. + if (TUK == TagUseKind::Definition) { + if (TagDecl *Def = PrevRecordDecl->getDefinition()) { + // If we have a prior definition that is not visible, treat this as + // simply making that previous definition visible. + NamedDecl *Hidden = nullptr; + if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { + SkipBody->ShouldSkip = true; + SkipBody->Previous = Def; + auto *Tmpl = cast(Hidden)->getDescribedClassTemplate(); + assert(Tmpl && "original definition of a class template is not a " + "class template?"); + makeMergedDefinitionVisible(Hidden); + makeMergedDefinitionVisible(Tmpl); + } else { + Diag(NameLoc, diag::err_redefinition) << Name; + Diag(Def->getLocation(), diag::note_previous_definition); + // FIXME: Would it make sense to try to "forget" the previous + // definition, as part of error recovery? + return true; + } + } + } } else if (PrevDecl) { // C++ [temp]p5: // A class template shall not have the same name as any other @@ -2010,6 +2046,23 @@ DeclResult Sema::CheckClassTemplate( return true; } + // Check the template parameter list of this declaration, possibly + // merging in the template parameter list from the previous class + // template declaration. Skip this check for a friend in a dependent + // context, because the template parameter list might be dependent. + if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && + CheckTemplateParameterList( + TemplateParams, + PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate) + : nullptr, + (SS.isSet() && SemanticContext && SemanticContext->isRecord() && + SemanticContext->isDependentContext()) + ? TPC_ClassTemplateMember + : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate + : TPC_ClassTemplate, + SkipBody)) + Invalid = true; + if (SS.isSet()) { // If the name of the template was qualified, we must be defining the // template out-of-line. @@ -2036,8 +2089,10 @@ DeclResult Sema::CheckClassTemplate( PrevClassTemplate->getTemplatedDecl() : nullptr, /*DelayTypeCreation=*/true); SetNestedNameSpecifier(*this, NewClass, SS); - if (!OuterTemplateParamLists.empty()) - NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists); + if (NumOuterTemplateParamLists > 0) + NewClass->setTemplateParameterListsInfo( + Context, + llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists)); // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. @@ -2050,10 +2105,7 @@ DeclResult Sema::CheckClassTemplate( = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, NewClass); - // If we are providing an explicit specialization of a member that is a - // class template, make a note of that. - if (IsMemberSpecialization) - NewTemplate->setMemberSpecialization(); + if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); @@ -2068,6 +2120,12 @@ DeclResult Sema::CheckClassTemplate( assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; + // If we are providing an explicit specialization of a member that is a + // class template, make a note of that. + if (PrevClassTemplate && + PrevClassTemplate->getInstantiatedFromMemberTemplate()) + PrevClassTemplate->setMemberSpecialization(); + // Set the access specifier. if (!Invalid && TUK != TagUseKind::Friend && NewTemplate->getDeclContext()->isRecord()) @@ -2077,62 +2135,8 @@ DeclResult Sema::CheckClassTemplate( NewClass->setLexicalDeclContext(CurContext); NewTemplate->setLexicalDeclContext(CurContext); - // Ensure that the template parameter lists are compatible. Skip this check - // for a friend in a dependent context: the template parameter list itself - // could be dependent. - if (ShouldAddRedecl && PrevClassTemplate && - !TemplateParameterListsAreEqual( - NewTemplate, TemplateParams, PrevClassTemplate, - PrevClassTemplate->getTemplateParameters(), - /*Complain=*/true, TPL_TemplateMatch)) - return true; - - // Check the template parameter list of this declaration, possibly - // merging in the template parameter list from the previous class - // template declaration. Skip this check for a friend in a dependent - // context, because the template parameter list might be dependent. - if (ShouldAddRedecl && - CheckTemplateParameterList( - TemplateParams, - PrevClassTemplate ? PrevClassTemplate->getTemplateParameters() - : nullptr, - (SS.isSet() && SemanticContext && SemanticContext->isRecord() && - SemanticContext->isDependentContext()) - ? TPC_ClassTemplateMember - : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate - : TPC_ClassTemplate, - SkipBody)) - Invalid = true; - - if (TUK == TagUseKind::Definition) { - if (PrevClassTemplate) { - // Check for redefinition of this class template. - if (TagDecl *Def = - PrevClassTemplate->getTemplatedDecl()->getDefinition()) { - // If we have a prior definition that is not visible, treat this as - // simply making that previous definition visible. - NamedDecl *Hidden = nullptr; - if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { - SkipBody->ShouldSkip = true; - SkipBody->Previous = Def; - auto *Tmpl = cast(Hidden)->getDescribedClassTemplate(); - assert(Tmpl && "original definition of a class template is not a " - "class template?"); - makeMergedDefinitionVisible(Hidden); - makeMergedDefinitionVisible(Tmpl); - } else { - Diag(NameLoc, diag::err_redefinition) << Name; - Diag(Def->getLocation(), diag::note_previous_definition); - // FIXME: Would it make sense to try to "forget" the previous - // definition, as part of error recovery? - return true; - } - } - } - - if (!SkipBody || !SkipBody->ShouldSkip) - NewClass->startDefinition(); - } + if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) + NewClass->startDefinition(); ProcessDeclAttributeList(S, NewClass, Attr); ProcessAPINotes(NewClass); @@ -4129,8 +4133,7 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) { DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, - StorageClass SC, bool IsPartialSpecialization, - bool IsMemberSpecialization) { + StorageClass SC, bool IsPartialSpecialization) { // D must be variable template id. assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId && "Variable template specialization is declared with a template id."); @@ -4248,16 +4251,17 @@ DeclResult Sema::ActOnVarTemplateSpecialization( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, CanonicalConverted); - // If we are providing an explicit specialization of a member variable - // template specialization, make a note of that. - if (IsMemberSpecialization) - Partial->setMemberSpecialization(); Partial->setTemplateArgsAsWritten(TemplateArgs); if (!PrevPartial) VarTemplate->AddPartialSpecialization(Partial, InsertPos); Specialization = Partial; + // If we are providing an explicit specialization of a member variable + // template specialization, make a note of that. + if (PrevPartial && PrevPartial->getInstantiatedFromMember()) + PrevPartial->setMemberSpecialization(); + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for @@ -5784,7 +5788,9 @@ bool Sema::CheckTemplateArgumentList( MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( Template, NewContext, /*Final=*/false, CanonicalConverted, - /*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true); + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConceptInstantiation=*/true); if (EnsureTemplateArgumentListConstraints( Template, MLTAL, SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { @@ -8484,8 +8490,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), TemplateNameLoc, Attr, TemplateParams, AS_none, /*ModulePrivateLoc=*/SourceLocation(), - /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(), - isMemberSpecialization); + /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, + TemplateParameterLists.data()); } // Create a new class template partial specialization declaration node. @@ -8495,11 +8501,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplatePartialSpecializationDecl::Create( Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted, CanonType, PrevPartial); - - // If we are providing an explicit specialization of a member class - // template specialization, make a note of that. - if (isMemberSpecialization) - Partial->setMemberSpecialization(); Partial->setTemplateArgsAsWritten(TemplateArgs); SetNestedNameSpecifier(*this, Partial, SS); if (TemplateParameterLists.size() > 1 && SS.isSet()) { @@ -8511,6 +8512,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplate->AddPartialSpecialization(Partial, InsertPos); Specialization = Partial; + // If we are providing an explicit specialization of a member class + // template specialization, make a note of that. + if (PrevPartial && PrevPartial->getInstantiatedFromMember()) + PrevPartial->setMemberSpecialization(); + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for @@ -9110,8 +9116,8 @@ bool Sema::CheckFunctionTemplateSpecialization( TemplateDeductionInfo Info(FailedCandidates.getLocation()); FunctionDecl *Specialization = nullptr; if (TemplateDeductionResult TDK = DeduceTemplateArguments( - FunTmpl, ExplicitTemplateArgs ? &Args : nullptr, FT, - Specialization, Info); + cast(FunTmpl->getFirstDecl()), + ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info); TDK != TemplateDeductionResult::Success) { // Template argument deduction failed; record why it failed, so // that we can provide nifty diagnostics. @@ -11309,8 +11315,8 @@ class ExplicitSpecializationVisibilityChecker { template void checkTemplate(TemplDecl *TD) { - if (TD->getMostRecentDecl()->isMemberSpecialization()) { - if (!CheckMemberSpecialization(TD->getMostRecentDecl())) + if (TD->isMemberSpecialization()) { + if (!CheckMemberSpecialization(TD)) diagnose(TD->getMostRecentDecl(), false); } } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b45f30fed49a647..2946d8102f98971 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3139,6 +3139,20 @@ template<> struct IsPartialSpecialization { static constexpr bool value = true; }; +template +static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) { + return false; +} +template <> +bool DeducedArgsNeedReplacement( + VarTemplatePartialSpecializationDecl *Spec) { + return !Spec->isClassScopeExplicitSpecialization(); +} +template <> +bool DeducedArgsNeedReplacement( + ClassTemplatePartialSpecializationDecl *Spec) { + return !Spec->isClassScopeExplicitSpecialization(); +} template static TemplateDeductionResult @@ -3149,10 +3163,23 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, llvm::SmallVector AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); + std::optional> Innermost; + // If we don't need to replace the deduced template arguments, + // we can add them immediately as the inner-most argument list. + if (!DeducedArgsNeedReplacement(Template)) + Innermost = CanonicalDeducedArgs; + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( - Template, Template->getDeclContext(), /*Final=*/false, - /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true, - /*ForConstraintInstantiation=*/true); + Template, Template->getDeclContext(), /*Final=*/false, Innermost, + /*RelativeToPrimary=*/true, /*Pattern=*/ + nullptr, /*ForConstraintInstantiation=*/true); + + // getTemplateInstantiationArgs picks up the non-deduced version of the + // template args when this is a variable template partial specialization and + // not class-scope explicit specialization, so replace with Deduced Args + // instead of adding to inner-most. + if (!Innermost) + MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs); if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, Info.getLocation(), diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 698e0760d808fe6..e422ef04e20d909 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -765,7 +765,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, } // Template arguments used to transform the template arguments in // DeducedResults. - SmallVector InnerArgsForBuildingRC( + SmallVector TemplateArgsForBuildingRC( F->getTemplateParameters()->size()); // Transform the transformed template args MultiLevelTemplateArgumentList Args; @@ -778,30 +778,33 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, NamedDecl *TP = F->getTemplateParameters()->getParam(Index); MultiLevelTemplateArgumentList Args; Args.setKind(TemplateSubstitutionKind::Rewrite); - Args.addOuterTemplateArguments(InnerArgsForBuildingRC); + Args.addOuterTemplateArguments(TemplateArgsForBuildingRC); // Rebuild the template parameter with updated depth and index. NamedDecl *NewParam = transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args, /*NewIndex=*/FirstUndeducedParamIdx, getDepthAndIndex(TP).first + AdjustDepth); FirstUndeducedParamIdx += 1; - assert(InnerArgsForBuildingRC[Index].isNull()); - InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam); + assert(TemplateArgsForBuildingRC[Index].isNull()); + TemplateArgsForBuildingRC[Index] = + Context.getInjectedTemplateArg(NewParam); continue; } TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{}); TemplateArgumentLoc Output; if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) { - assert(InnerArgsForBuildingRC[Index].isNull() && + assert(TemplateArgsForBuildingRC[Index].isNull() && "InstantiatedArgs must be null before setting"); - InnerArgsForBuildingRC[Index] = Output.getArgument(); + TemplateArgsForBuildingRC[Index] = Output.getArgument(); } } - // A list of template arguments for transforming the require-clause using - // the transformed template arguments as the template argument list of F. - // + // A list of template arguments for transforming the require-clause of F. + // It must contain the entire set of template argument lists. + MultiLevelTemplateArgumentList ArgsForBuildingRC; + ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite); + ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC); // For 2), if the underlying deduction guide F is nested in a class template, // we need the entire template argument list, as the constraint AST in the // require-clause of F remains completely uninstantiated. @@ -824,15 +827,25 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, // - The occurrence of U in the function parameter is [depth:0, index:0] // - The template parameter of U is [depth:0, index:0] // + // We add the outer template arguments which is [int] to the multi-level arg + // list to ensure that the occurrence U in `C` will be replaced with int + // during the substitution. + // // NOTE: The underlying deduction guide F is instantiated -- either from an // explicitly-written deduction guide member, or from a constructor. - MultiLevelTemplateArgumentList ArgsForBuildingRC = - SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(), - /*Final=*/false, - /*Innermost=*/InnerArgsForBuildingRC, - /*RelativeToPrimary=*/true, - /*ForConstraintInstantiation=*/true); - ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite); + // getInstantiatedFromMemberTemplate() can only handle the former case, so we + // check the DeclContext kind. + if (F->getLexicalDeclContext()->getDeclKind() == + clang::Decl::ClassTemplateSpecialization) { + auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs( + F, F->getLexicalDeclContext(), + /*Final=*/false, /*Innermost=*/std::nullopt, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + for (auto It : OuterLevelArgs) + ArgsForBuildingRC.addOuterTemplateArguments(It.Args); + } ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC); if (E.isInvalid()) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index c5921287a3afb2b..b3ae96582180a59 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -52,6 +52,38 @@ using namespace sema; //===----------------------------------------------------------------------===/ namespace { +namespace TemplateInstArgsHelpers { +struct Response { + const Decl *NextDecl = nullptr; + bool IsDone = false; + bool ClearRelativeToPrimary = true; + static Response Done() { + Response R; + R.IsDone = true; + return R; + } + static Response ChangeDecl(const Decl *ND) { + Response R; + R.NextDecl = ND; + return R; + } + static Response ChangeDecl(const DeclContext *Ctx) { + Response R; + R.NextDecl = Decl::castFromDeclContext(Ctx); + return R; + } + + static Response UseNextDecl(const Decl *CurDecl) { + return ChangeDecl(CurDecl->getDeclContext()); + } + + static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) { + Response R = Response::UseNextDecl(CurDecl); + R.ClearRelativeToPrimary = false; + return R; + } +}; + // Retrieve the primary template for a lambda call operator. It's // unfortunate that we only have the mappings of call operators rather // than lambda classes. @@ -139,396 +171,379 @@ bool isLambdaEnclosedByTypeAliasDecl( .TraverseType(Underlying); } -struct TemplateInstantiationArgumentCollecter - : DeclVisitor { - Sema &S; - MultiLevelTemplateArgumentList &Result; - std::optional> Innermost; - bool RelativeToPrimary; - bool ForConstraintInstantiation; - - TemplateInstantiationArgumentCollecter( - Sema &S, MultiLevelTemplateArgumentList &Result, - std::optional> Innermost, - bool RelativeToPrimary, bool ForConstraintInstantiation) - : S(S), Result(Result), Innermost(Innermost), - RelativeToPrimary(RelativeToPrimary), - ForConstraintInstantiation(ForConstraintInstantiation) {} - - Decl *Done() { return nullptr; } - - Decl *ChangeDecl(const Decl *D) { - RelativeToPrimary = false; - return const_cast(D); - } - - Decl *ChangeDecl(const DeclContext *DC) { - return ChangeDecl(Decl::castFromDeclContext(DC)); - } - - Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); } - - void AddInnermostTemplateArguments(const Decl *D) { - assert(Innermost); - Result.addOuterTemplateArguments(const_cast(D), *Innermost, - /*Final=*/false); - Innermost.reset(); - } - - void AddOuterTemplateArguments(const Decl *D, ArrayRef Args, - bool Final) { - Result.addOuterTemplateArguments(const_cast(D), Args, Final); +// Add template arguments from a variable template instantiation. +Response +HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec, + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { + // For a class-scope explicit specialization, there are no template arguments + // at this level, but there may be enclosing template arguments. + if (VarTemplSpec->isClassScopeExplicitSpecialization()) + return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); + + // We're done when we hit an explicit specialization. + if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa(VarTemplSpec)) + return Response::Done(); + + // If this variable template specialization was instantiated from a + // specialized member that is a variable template, we're done. + assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?"); + llvm::PointerUnion + Specialized = VarTemplSpec->getSpecializedTemplateOrPartial(); + if (VarTemplatePartialSpecializationDecl *Partial = + Specialized.dyn_cast()) { + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + if (Partial->isMemberSpecialization()) + return Response::Done(); + } else { + VarTemplateDecl *Tmpl = Specialized.get(); + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + if (Tmpl->isMemberSpecialization()) + return Response::Done(); } + return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); +} - Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) { - if (Innermost) - AddInnermostTemplateArguments(TTPD); - else if (ForConstraintInstantiation) - AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false); - - for (unsigned Depth = TTPD->getDepth() + 1; Depth--;) - AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false); - - return Done(); - } +// If we have a template template parameter with translation unit context, +// then we're performing substitution into a default template argument of +// this template template parameter before we've constructed the template +// that will own this template template parameter. In this case, we +// use empty template parameter lists for all of the outer templates +// to avoid performing any substitutions. +Response +HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, + MultiLevelTemplateArgumentList &Result) { + for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) + Result.addOuterTemplateArguments(std::nullopt); + return Response::Done(); +} - Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) { - assert( - (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "outer template not instantiated?"); +Response HandlePartialClassTemplateSpec( + const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec, + MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { + if (!SkipForSpecialization) + Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth()); + return Response::Done(); +} - if (Innermost) - AddInnermostTemplateArguments(FTD); - else if (ForConstraintInstantiation) - AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(S.Context), - /*Final=*/false); +// Add template arguments from a class template instantiation. +Response +HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { + if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { + // We're done when we hit an explicit specialization. + if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa(ClassTemplSpec)) + return Response::Done(); - if (FTD->isMemberSpecialization()) - return Done(); + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + const_cast(ClassTemplSpec), + ClassTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); - if (FTD->getFriendObjectKind()) - return ChangeDecl(FTD->getLexicalDeclContext()); - return UseNextDecl(FTD); + // If this class template specialization was instantiated from a + // specialized member that is a class template, we're done. + assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); + if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) + return Response::Done(); + + // If this was instantiated from a partial template specialization, we need + // to get the next level of declaration context from the partial + // specialization, as the ClassTemplateSpecializationDecl's + // DeclContext/LexicalDeclContext will be for the primary template. + if (auto *InstFromPartialTempl = + ClassTemplSpec->getSpecializedTemplateOrPartial() + .dyn_cast()) + return Response::ChangeDecl( + InstFromPartialTempl->getLexicalDeclContext()); } + return Response::UseNextDecl(ClassTemplSpec); +} - Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) { - assert( - (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "outer template not instantiated?"); - - if (Innermost) - AddInnermostTemplateArguments(VTD); - else if (ForConstraintInstantiation) - AddOuterTemplateArguments(VTD, VTD->getInjectedTemplateArgs(S.Context), - /*Final=*/false); - - if (VTD->isMemberSpecialization()) - return Done(); - - return UseNextDecl(VTD); - } +Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function, + MultiLevelTemplateArgumentList &Result, + const FunctionDecl *Pattern, bool RelativeToPrimary, + bool ForConstraintInstantiation, + bool ForDefaultArgumentSubstitution) { + // Add template arguments from a function template specialization. + if (!RelativeToPrimary && + Function->getTemplateSpecializationKindForInstantiation() == + TSK_ExplicitSpecialization) + return Response::Done(); + + if (!RelativeToPrimary && + Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { + // This is an implicit instantiation of an explicit specialization. We + // don't get any template arguments from this function but might get + // some from an enclosing template. + return Response::UseNextDecl(Function); + } else if (const TemplateArgumentList *TemplateArgs = + Function->getTemplateSpecializationArgs()) { + // Add the template arguments for this specialization. + Result.addOuterTemplateArguments(const_cast(Function), + TemplateArgs->asArray(), + /*Final=*/false); - Decl *VisitVarTemplatePartialSpecializationDecl( - VarTemplatePartialSpecializationDecl *VTPSD) { + if (RelativeToPrimary && + (Function->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization || + (Function->getFriendObjectKind() && + !Function->getPrimaryTemplate()->getFriendObjectKind()))) + return Response::UseNextDecl(Function); + + // If this function was instantiated from a specialized member that is + // a function template, we're done. + assert(Function->getPrimaryTemplate() && "No function template?"); + if (!ForDefaultArgumentSubstitution && + Function->getPrimaryTemplate()->isMemberSpecialization()) + return Response::Done(); + + // If this function is a generic lambda specialization, we are done. + if (!ForConstraintInstantiation && + isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) + return Response::Done(); + + } else if (Function->getDescribedFunctionTemplate()) { assert( (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "outer template not instantiated?"); - - if (Innermost) - AddInnermostTemplateArguments(VTPSD); - else if (ForConstraintInstantiation) - AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(), - /*Final=*/false); - - if (VTPSD->isMemberSpecialization()) - return Done(); - - return UseNextDecl(VTPSD); + "Outer template not instantiated?"); } - - Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) { - assert( - (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "outer template not instantiated?"); - - if (Innermost) - AddInnermostTemplateArguments(CTD); - else if (ForConstraintInstantiation) - AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(S.Context), - /*Final=*/false); - - if (CTD->isMemberSpecialization()) - return Done(); - - if (CTD->getFriendObjectKind()) - return ChangeDecl(CTD->getLexicalDeclContext()); - return UseNextDecl(CTD); + // If this is a friend or local declaration and it declares an entity at + // namespace scope, take arguments from its lexical parent + // instead of its semantic parent, unless of course the pattern we're + // instantiating actually comes from the file's context! + if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) && + Function->getNonTransparentDeclContext()->isFileContext() && + (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { + return Response::ChangeDecl(Function->getLexicalDeclContext()); } - Decl *VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *CTPSD) { - assert( - (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "outer template not instantiated?"); - - if (Innermost) - AddInnermostTemplateArguments(CTPSD); - else if (ForConstraintInstantiation) - AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(), - /*Final=*/false); + if (ForConstraintInstantiation && Function->getFriendObjectKind()) + return Response::ChangeDecl(Function->getLexicalDeclContext()); + return Response::UseNextDecl(Function); +} - if (CTPSD->isMemberSpecialization()) - return Done(); +Response HandleFunctionTemplateDecl(Sema &SemaRef, + const FunctionTemplateDecl *FTD, + MultiLevelTemplateArgumentList &Result) { + if (!isa(FTD->getDeclContext())) { + Result.addOuterTemplateArguments( + const_cast(FTD), + const_cast(FTD)->getInjectedTemplateArgs( + SemaRef.Context), + /*Final=*/false); + + NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); + + while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { + if (NNS->isInstantiationDependent()) { + if (const auto *TSTy = Ty->getAs()) { + ArrayRef Arguments = TSTy->template_arguments(); + // Prefer template arguments from the injected-class-type if possible. + // For example, + // ```cpp + // template struct S { + // template void foo(); + // }; + // template template + // ^^^^^^^^^^^^^ InjectedTemplateArgs + // They're of kind TemplateArgument::Pack, not of + // TemplateArgument::Type. + // void S::foo() {} + // ^^^^^^^ + // TSTy->template_arguments() (which are of PackExpansionType) + // ``` + // This meets the contract in + // TreeTransform::TryExpandParameterPacks that the template arguments + // for unexpanded parameters should be of a Pack kind. + if (TSTy->isCurrentInstantiation()) { + auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl(); + if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) + Arguments = CTD->getInjectedTemplateArgs(SemaRef.Context); + else if (auto *Specialization = + dyn_cast(RD)) + Arguments = + Specialization->getTemplateInstantiationArgs().asArray(); + } + Result.addOuterTemplateArguments( + TSTy->getTemplateName().getAsTemplateDecl(), Arguments, + /*Final=*/false); + } + } - return UseNextDecl(CTPSD); + NNS = NNS->getPrefix(); + } } - Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) { - assert( - (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "outer template not instantiated?"); - if (Innermost) - AddInnermostTemplateArguments(TATD); - else if (ForConstraintInstantiation) - AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(S.Context), - /*Final=*/false); - - return UseNextDecl(TATD); - } + return Response::ChangeDecl(FTD->getLexicalDeclContext()); +} - Decl *VisitConceptDecl(ConceptDecl *CD) { +Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec, + MultiLevelTemplateArgumentList &Result, + ASTContext &Context, + bool ForConstraintInstantiation) { + if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { assert( (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && - "outer template not instantiated?"); - if (Innermost) - AddInnermostTemplateArguments(CD); - - return UseNextDecl(CD); + "Outer template not instantiated?"); + if (ClassTemplate->isMemberSpecialization()) + return Response::Done(); + if (ForConstraintInstantiation) + Result.addOuterTemplateArguments( + const_cast(Rec), + ClassTemplate->getInjectedTemplateArgs(SemaRef.Context), + /*Final=*/false); } - Decl *VisitFunctionDecl(FunctionDecl *FD) { - assert(!FD->getDescribedFunctionTemplate() && - "not for templated declarations"); - - if (!RelativeToPrimary) { - // Add template arguments from a function template specialization. - if (const MemberSpecializationInfo *MSI = - FD->getMemberSpecializationInfo(); - MSI && - MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - return Done(); - - // This is an implicit instantiation of an explicit specialization. We - // don't get any template arguments from this function but might get - // some from an enclosing template. - if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - return UseNextDecl(FD); - } - - if (const TemplateArgumentList *TemplateArgs = - FD->getTemplateSpecializationArgs()) { - // Add the template arguments for this specialization. - if (Innermost) - AddInnermostTemplateArguments(FD); - else - AddOuterTemplateArguments(FD, TemplateArgs->asArray(), /*Final=*/false); - - if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization || - (FD->getFriendObjectKind() && - !FD->getPrimaryTemplate()->getFriendObjectKind())) - return UseNextDecl(FD); - - // If this function was instantiated from a specialized member that is - // a function template, we're done. - assert(FD->getPrimaryTemplate() && "No function template?"); - if (FD->getPrimaryTemplate()->hasMemberSpecialization()) - return Done(); - - // If this function is a generic lambda specialization, we are done. - if (!ForConstraintInstantiation && - isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) - return Done(); - } - - // If this is a friend or local declaration and it declares an entity at - // namespace scope, take arguments from its lexical parent - // instead of its semantic parent, unless of course the pattern we're - // instantiating actually comes from the file's context! - if ((FD->getFriendObjectKind() || FD->isLocalExternDecl()) && - FD->getNonTransparentDeclContext()->isFileContext()) { - return ChangeDecl(FD->getLexicalDeclContext()); - } - - if (ForConstraintInstantiation && FD->getFriendObjectKind()) - return ChangeDecl(FD->getLexicalDeclContext()); - return UseNextDecl(FD); + if (const MemberSpecializationInfo *MSInfo = + Rec->getMemberSpecializationInfo()) + if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return Response::Done(); + + bool IsFriend = Rec->getFriendObjectKind() || + (Rec->getDescribedClassTemplate() && + Rec->getDescribedClassTemplate()->getFriendObjectKind()); + if (ForConstraintInstantiation && IsFriend && + Rec->getNonTransparentDeclContext()->isFileContext()) { + return Response::ChangeDecl(Rec->getLexicalDeclContext()); } - Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) { - assert(!RD->getDescribedClassTemplate() && - "not for templated declarations"); - - if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo(); - MSI && - MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - return Done(); - - if (ForConstraintInstantiation && RD->getFriendObjectKind() && - RD->getNonTransparentDeclContext()->isFileContext()) { - return ChangeDecl(RD->getLexicalDeclContext()); - } - - // This is to make sure we pick up the VarTemplateSpecializationDecl or the - // TypeAliasTemplateDecl that this lambda is defined inside of. - if (RD->isLambda()) { - if (Decl *LCD = RD->getLambdaContextDecl()) - return ChangeDecl(LCD); - // Retrieve the template arguments for a using alias declaration. - // This is necessary for constraint checking, since we always keep - // constraints relative to the primary template. - if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S); - ForConstraintInstantiation && TypeAlias) { - if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(), - TypeAlias.PrimaryTypeAliasDecl)) { - AddOuterTemplateArguments(TypeAlias.Template, - TypeAlias.AssociatedTemplateArguments, - /*Final=*/false); - // Visit the parent of the current type alias declaration rather than - // the lambda thereof. - // E.g., in the following example: - // struct S { - // template using T = decltype([] {} ()); - // }; - // void foo() { - // S::T var; - // } - // The instantiated lambda expression (which we're visiting at 'var') - // has a function DeclContext 'foo' rather than the Record DeclContext - // S. This seems to be an oversight to me that we may want to set a - // Sema Context from the CXXScopeSpec before substituting into T. - return ChangeDecl(TypeAlias.Template->getDeclContext()); - } + // This is to make sure we pick up the VarTemplateSpecializationDecl or the + // TypeAliasTemplateDecl that this lambda is defined inside of. + if (Rec->isLambda()) { + if (const Decl *LCD = Rec->getLambdaContextDecl()) + return Response::ChangeDecl(LCD); + // Retrieve the template arguments for a using alias declaration. + // This is necessary for constraint checking, since we always keep + // constraints relative to the primary template. + if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef); + ForConstraintInstantiation && TypeAlias) { + if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(), + TypeAlias.PrimaryTypeAliasDecl)) { + Result.addOuterTemplateArguments(TypeAlias.Template, + TypeAlias.AssociatedTemplateArguments, + /*Final=*/false); + // Visit the parent of the current type alias declaration rather than + // the lambda thereof. + // E.g., in the following example: + // struct S { + // template using T = decltype([] {} ()); + // }; + // void foo() { + // S::T var; + // } + // The instantiated lambda expression (which we're visiting at 'var') + // has a function DeclContext 'foo' rather than the Record DeclContext + // S. This seems to be an oversight to me that we may want to set a + // Sema Context from the CXXScopeSpec before substituting into T. + return Response::ChangeDecl(TypeAlias.Template->getDeclContext()); } } - - return UseNextDecl(RD); - } - - Decl * - VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) { - // For a class-scope explicit specialization, there are no template - // arguments at this level, but there may be enclosing template arguments. - if (CTSD->isClassScopeExplicitSpecialization()) - return UseNextDecl(CTSD); - - // We're done when we hit an explicit specialization. - if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization) - return Done(); - - if (Innermost) - AddInnermostTemplateArguments(CTSD); - else - AddOuterTemplateArguments(CTSD, - CTSD->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); - - // If this class template specialization was instantiated from a - // specialized member that is a class template, we're done. - assert(CTSD->getSpecializedTemplate() && "No class template?"); - llvm::PointerUnion - Specialized = CTSD->getSpecializedTemplateOrPartial(); - if (auto *CTPSD = - Specialized.dyn_cast()) { - if (CTPSD->hasMemberSpecialization()) - return Done(); - } else { - auto *CTD = Specialized.get(); - if (CTD->hasMemberSpecialization()) - return Done(); - } - return UseNextDecl(CTSD); - } - - Decl * - VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) { - // For a class-scope explicit specialization, there are no template - // arguments at this level, but there may be enclosing template arguments. - if (VTSD->isClassScopeExplicitSpecialization()) - return UseNextDecl(VTSD); - - // We're done when we hit an explicit specialization. - if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization) - return Done(); - - if (Innermost) - AddInnermostTemplateArguments(VTSD); - else - AddOuterTemplateArguments(VTSD, - VTSD->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); - - // If this variable template specialization was instantiated from a - // specialized member that is a variable template, we're done. - assert(VTSD->getSpecializedTemplate() && "No variable template?"); - llvm::PointerUnion - Specialized = VTSD->getSpecializedTemplateOrPartial(); - if (auto *VTPSD = - Specialized.dyn_cast()) { - if (VTPSD->hasMemberSpecialization()) - return Done(); - } else { - auto *VTD = Specialized.get(); - if (VTD->hasMemberSpecialization()) - return Done(); - } - return UseNextDecl(VTSD); } - Decl *VisitImplicitConceptSpecializationDecl( - ImplicitConceptSpecializationDecl *ICSD) { - AddOuterTemplateArguments(ICSD, ICSD->getTemplateArguments(), - /*Final=*/false); - return UseNextDecl(ICSD); - } - - Decl *VisitDecl(Decl *D) { - if (D->isFileContextDecl()) - return Done(); - - if (isa(D)) - RelativeToPrimary = false; - - return UseNextDecl(D); - } + return Response::UseNextDecl(Rec); +} - Decl *Visit(Decl *D) { - if (TemplateDecl *TD = D->getDescribedTemplate()) - D = TD; - return DeclVisitor::Visit(D); - } -}; +Response HandleImplicitConceptSpecializationDecl( + const ImplicitConceptSpecializationDecl *CSD, + MultiLevelTemplateArgumentList &Result) { + Result.addOuterTemplateArguments( + const_cast(CSD), + CSD->getTemplateArguments(), + /*Final=*/false); + return Response::UseNextDecl(CSD); +} +Response HandleGenericDeclContext(const Decl *CurDecl) { + return Response::UseNextDecl(CurDecl); +} +} // namespace TemplateInstArgsHelpers } // namespace MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( const NamedDecl *ND, const DeclContext *DC, bool Final, std::optional> Innermost, bool RelativeToPrimary, - bool ForConstraintInstantiation) { + const FunctionDecl *Pattern, bool ForConstraintInstantiation, + bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) { assert((ND || DC) && "Can't find arguments for a decl if one isn't provided"); // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; + + using namespace TemplateInstArgsHelpers; const Decl *CurDecl = ND; if (!CurDecl) CurDecl = Decl::castFromDeclContext(DC); - TemplateInstantiationArgumentCollecter Collecter( - *this, Result, Innermost, RelativeToPrimary, ForConstraintInstantiation); - do { - CurDecl = Collecter.Visit(const_cast(CurDecl)); - } while (CurDecl); + if (Innermost) { + Result.addOuterTemplateArguments(const_cast(ND), *Innermost, + Final); + // Populate placeholder template arguments for TemplateTemplateParmDecls. + // This is essential for the case e.g. + // + // template concept Concept = false; + // template