llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-modules @llvm/pr-subscribers-clang Author: Krystian Stasiowski (sdkrystian) <details> <summary>Changes</summary> This patch reapplies #<!-- -->111173, fixing a bug when instantiating dependent expressions that name a member template that is later explicitly specialized for a class specialization that is implicitly instantiated. The bug is addressed by adding the `hasMemberSpecialization` function, which return `true` if _any_ redeclaration is a member specialization. This is then used when determining the instantiation pattern for a specialization of a template, and when collecting template arguments for a specialization of a template. --- Patch is 105.30 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111852.diff 20 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+3) - (modified) clang/include/clang/AST/DeclTemplate.h (+59-38) - (modified) clang/include/clang/Sema/Sema.h (+6-19) - (modified) clang/lib/AST/Decl.cpp (+18-19) - (modified) clang/lib/AST/DeclCXX.cpp (+8-6) - (modified) clang/lib/AST/DeclTemplate.cpp (+14-16) - (modified) clang/lib/Sema/SemaConcept.cpp (+12-17) - (modified) clang/lib/Sema/SemaDecl.cpp (+14-17) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+2-2) - (modified) clang/lib/Sema/SemaTemplate.cpp (+87-96) - (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+3-30) - (modified) clang/lib/Sema/SemaTemplateDeductionGuide.cpp (+16-29) - (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+364-382) - (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+37-9) - (modified) clang/lib/Serialization/ASTReader.cpp (+2-1) - (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+9-9) - (modified) clang/lib/Serialization/ASTWriterDecl.cpp (+7-10) - (added) clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp (+175) - (added) clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp (+178) - (modified) clang/test/Modules/cxx-templates.cpp (+1-3) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c0019cfe4658d7..14cde29d445434 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -488,6 +488,9 @@ 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 687715a22e9fd3..141f58c4600af0 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -781,15 +781,11 @@ class RedeclarableTemplateDecl : public TemplateDecl, EntryType *Entry, void *InsertPos); struct CommonBase { - CommonBase() : InstantiatedFromMember(nullptr, false) {} + CommonBase() {} /// The template from which this was most /// directly instantiated (or null). - /// - /// The boolean value indicates whether this template - /// was explicitly specialized. - llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool> - InstantiatedFromMember; + RedeclarableTemplateDecl *InstantiatedFromMember = nullptr; /// If non-null, points to an array of specializations (including /// partial specializations) known only by their external declaration IDs. @@ -809,14 +805,19 @@ class RedeclarableTemplateDecl : public TemplateDecl, }; /// Pointer to the common data shared by all declarations of this - /// template. - mutable CommonBase *Common = nullptr; + /// template, and a flag indicating if the template is a member + /// specialization. + mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common; + + CommonBase *getCommonPtrInternal() const { return Common.getPointer(); } /// 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. @@ -857,15 +858,22 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// template<> template<typename T> /// struct X<int>::Inner { /* ... */ }; /// \endcode - bool isMemberSpecialization() const { - return getCommonPtr()->InstantiatedFromMember.getInt(); + 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; } /// Note that this member template is a specialization. void setMemberSpecialization() { - assert(getCommonPtr()->InstantiatedFromMember.getPointer() && - "Only member templates can be member template specializations"); - getCommonPtr()->InstantiatedFromMember.setInt(true); + assert(!isMemberSpecialization() && "already a member specialization"); + Common.setInt(true); } /// Retrieve the member template from which this template was @@ -905,12 +913,12 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// void X<T>::f(T, U); /// \endcode RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const { - return getCommonPtr()->InstantiatedFromMember.getPointer(); + return getCommonPtr()->InstantiatedFromMember; } void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) { - assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); - getCommonPtr()->InstantiatedFromMember.setPointer(TD); + assert(!getCommonPtr()->InstantiatedFromMember); + getCommonPtr()->InstantiatedFromMember = TD; } /// Retrieve the "injected" template arguments that correspond to the @@ -1989,6 +1997,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// template arguments have been deduced. void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { + assert(!isa<ClassTemplatePartialSpecializationDecl>(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() && "Already set to a class template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); @@ -2000,6 +2010,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// Note that this class template specialization is an instantiation /// of the given class template. void setInstantiationOf(ClassTemplateDecl *TemplDecl) { + assert(!isa<ClassTemplatePartialSpecializationDecl>(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() && "Previously set to a class template partial specialization!"); SpecializedTemplate = TemplDecl; @@ -2187,19 +2199,23 @@ class ClassTemplatePartialSpecializationDecl /// struct X<int>::Inner<T*> { /* ... */ }; /// \endcode bool isMemberSpecialization() const { - const auto *First = - cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl()); - return First->InstantiatedFromMember.getInt(); + return InstantiatedFromMember.getInt(); } - /// Note that this member template is a specialization. - void setMemberSpecialization() { - auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl()); - assert(First->InstantiatedFromMember.getPointer() && - "Only member templates can be member template specializations"); - return First->InstantiatedFromMember.setInt(true); + /// 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<ClassTemplatePartialSpecializationDecl>(D) + ->isMemberSpecialization()) + return true; + } + return false; } + /// Note that this member template is a specialization. + void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } + /// Retrieves the injected specialization type for this partial /// specialization. This is not the same as the type-decl-type for /// this partial specialization, which is an InjectedClassNameType. @@ -2268,10 +2284,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); } - void setCommonPtr(Common *C) { - RedeclarableTemplateDecl::Common = C; - } - public: friend class ASTDeclReader; @@ -2754,6 +2766,8 @@ class VarTemplateSpecializationDecl : public VarDecl, /// template arguments have been deduced. void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgumentList *TemplateArgs) { + assert(!isa<VarTemplatePartialSpecializationDecl>(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() && "Already set to a variable template partial specialization!"); auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); @@ -2765,6 +2779,8 @@ class VarTemplateSpecializationDecl : public VarDecl, /// Note that this variable template specialization is an instantiation /// of the given variable template. void setInstantiationOf(VarTemplateDecl *TemplDecl) { + assert(!isa<VarTemplatePartialSpecializationDecl>(this) && + "A partial specialization cannot be instantiated from a template"); assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() && "Previously set to a variable template partial specialization!"); SpecializedTemplate = TemplDecl; @@ -2949,19 +2965,24 @@ class VarTemplatePartialSpecializationDecl /// U* X<int>::Inner<T*> = (T*)(0) + 1; /// \endcode bool isMemberSpecialization() const { - const auto *First = - cast<VarTemplatePartialSpecializationDecl>(getFirstDecl()); - return First->InstantiatedFromMember.getInt(); + return InstantiatedFromMember.getInt(); } - /// Note that this member template is a specialization. - void setMemberSpecialization() { - auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl()); - assert(First->InstantiatedFromMember.getPointer() && - "Only member templates can be member template specializations"); - return First->InstantiatedFromMember.setInt(true); + /// 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<VarTemplatePartialSpecializationDecl>(D) + ->isMemberSpecialization()) + return true; + } + return false; } + /// Note that this member template is a specialization. + void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } + SourceRange getSourceRange() const override LLVM_READONLY; void Profile(llvm::FoldingSetNodeID &ID) const { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ef010fafb1573e..c4d15c776c19c6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11329,9 +11329,9 @@ class Sema final : public SemaBase { CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, - SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, - TemplateParameterList **OuterTemplateParamLists, - SkipBodyInfo *SkipBody = nullptr); + SourceLocation FriendLoc, + ArrayRef<TemplateParameterList *> OuterTemplateParamLists, + bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr); /// Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. @@ -11370,7 +11370,8 @@ class Sema final : public SemaBase { DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, - StorageClass SC, bool IsPartialSpecialization); + StorageClass SC, bool IsPartialSpecialization, + bool IsMemberSpecialization); /// Get the specialization of the given variable template corresponding to /// the specified argument list, or a null-but-valid result if the arguments @@ -13026,28 +13027,14 @@ 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<ArrayRef<TemplateArgument>> Innermost = std::nullopt, - bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, - bool ForConstraintInstantiation = false, - bool SkipForSpecialization = false, - bool ForDefaultArgumentSubstitution = false); + bool RelativeToPrimary = false, bool ForConstraintInstantiation = 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 84ef9f74582ef6..6f1bcf397bba04 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2696,21 +2696,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) { auto From = VDTemplSpec->getInstantiatedFrom(); if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) { - while (!VTD->isMemberSpecialization()) { - auto *NewVTD = VTD->getInstantiatedFromMemberTemplate(); - if (!NewVTD) + while (!VTD->hasMemberSpecialization()) { + if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) + VTD = NewVTD; + else break; - VTD = NewVTD; } return getDefinitionOrSelf(VTD->getTemplatedDecl()); } if (auto *VTPSD = From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { - while (!VTPSD->isMemberSpecialization()) { - auto *NewVTPSD = VTPSD->getInstantiatedFromMember(); - if (!NewVTPSD) + while (!VTPSD->hasMemberSpecialization()) { + if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) + VTPSD = NewVTPSD; + else break; - VTPSD = NewVTPSD; } return getDefinitionOrSelf<VarDecl>(VTPSD); } @@ -2719,15 +2719,14 @@ 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 *VarTemplate = VD->getDescribedVarTemplate()) { - while (!VarTemplate->isMemberSpecialization()) { - auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate(); - if (!NewVT) + if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) { + while (!VTD->hasMemberSpecialization()) { + if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) + VTD = NewVTD; + else break; - VarTemplate = NewVT; } - - return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); + return getDefinitionOrSelf(VTD->getTemplatedDecl()); } if (VD == this) @@ -4142,11 +4141,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->isMemberSpecialization()) { - auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate(); - if (!NewPrimary) + while (!ForDefinition || !Primary->hasMemberSpecialization()) { + if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate()) + Primary = NewPrimary; + else break; - Primary = NewPrimary; } return getDefinitionOrSelf(Primary->getTemplatedDecl()); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 1364ccc745ba01..407ec14bbc00d5 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2023,19 +2023,21 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { - if (NewCTD->isMemberSpecialization()) + while (!CTD->hasMemberSpecialization()) { + if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) + CTD = NewCTD; + else break; - CTD = NewCTD; } return GetDefinitionOrSelf(CTD->getTemplatedDecl()); } if (auto *CTPSD = From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { - if (NewCTPSD->isMemberSpecialization()) + while (!CTPSD->hasMemberSpecialization()) { + if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate()) + CTPSD = NewCTPSD; + else break; - CTPSD = NewCTPSD; } return GetDefinitionOrSelf(CTPSD); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 6fe817c5ef1c6b..d9b67b7bedf5a5 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -309,16 +309,16 @@ bool TemplateDecl::isTypeAlias() const { void RedeclarableTemplateDecl::anchor() {} RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const { - if (Common) - return Common; + if (CommonBase *C = getCommonPtrInternal()) + return C; // Walk the previous-declaration chain until we either find a declaration // with a common pointer or we run out of previous declarations. SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls; for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; Prev = Prev->getPreviousDecl()) { - if (Prev->Common) { - Common = Prev->Common; + if (CommonBase *C = Prev->getCommonPtrInternal()) { + setCommonPtr(C); break; } @@ -326,18 +326,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c } // If we never found a common pointer, allocate one now. - if (!Common) { + if (!getCommonPtrInternal()) { // FIXME: If any of the declarations is from an AST file, we probably // need an update record to add the common data. - Common = newCommon(getASTContext()); + setCommonPtr(newCommon(getASTContext())); } // Update any previous declarations we saw with the common pointer. for (const RedeclarableTemplateDecl *Prev : PrevDecls) - Prev->Common = Common; + Prev->setCommonPtr(getCommonPtrInternal()); - return Common; + return getCommonPtrInternal(); } void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { @@ -463,19 +463,17 @@ 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 (!Base::Common) + if (!getCommonPtrInternal()) return; - Common *ThisCommon = static_cast<Common *>(Base::Common); + Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal()); Common *PrevCommon = nullptr; SmallVector<FunctionTemplateDecl *, 8> PreviousDecls; for (; Prev; Prev = Prev->getPreviousDecl()) { - if (Prev->Base::Common) { - PrevCommon = static_cast<Common *>(Prev->Base::Common); + if (CommonBase *C = Prev->getCommonPtrInternal()) { + PrevCommon = static_cast<Common *>(C); break; } PreviousDecls.push_back(Prev); @@ -485,7 +483,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { // use this common pointer. if (!PrevCommon) { for (auto *D : Previou... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/111852 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits