[clang] Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (#106585, #111173)" (PR #111852)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 10 08:04:49 PDT 2024
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
More information about the cfe-commits
mailing list