Skip to content

Commit 2bb3d3a

Browse files
authored
Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (#106585, #111173)" (#111852)
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.
1 parent 48bda00 commit 2bb3d3a

21 files changed

+1066
-704
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,9 @@ Bug Fixes to C++ Support
502502
in certain friend declarations. (#GH93099)
503503
- Clang now instantiates the correct lambda call operator when a lambda's class type is
504504
merged across modules. (#GH110401)
505+
- Clang now uses the correct set of template argument lists when comparing the constraints of
506+
out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of
507+
a class template. (#GH102320)
505508
- Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460)
506509
- Fixed an assertion failure when invoking recovery call expressions with explicit attributes
507510
and undeclared templates. (#GH107047, #GH49093)

clang/include/clang/AST/DeclTemplate.h

Lines changed: 59 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -781,15 +781,11 @@ class RedeclarableTemplateDecl : public TemplateDecl,
781781
EntryType *Entry, void *InsertPos);
782782

783783
struct CommonBase {
784-
CommonBase() : InstantiatedFromMember(nullptr, false) {}
784+
CommonBase() {}
785785

786786
/// The template from which this was most
787787
/// directly instantiated (or null).
788-
///
789-
/// The boolean value indicates whether this template
790-
/// was explicitly specialized.
791-
llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
792-
InstantiatedFromMember;
788+
RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
793789

794790
/// If non-null, points to an array of specializations (including
795791
/// partial specializations) known only by their external declaration IDs.
@@ -809,14 +805,19 @@ class RedeclarableTemplateDecl : public TemplateDecl,
809805
};
810806

811807
/// Pointer to the common data shared by all declarations of this
812-
/// template.
813-
mutable CommonBase *Common = nullptr;
808+
/// template, and a flag indicating if the template is a member
809+
/// specialization.
810+
mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;
811+
812+
CommonBase *getCommonPtrInternal() const { return Common.getPointer(); }
814813

815814
/// Retrieves the "common" pointer shared by all (re-)declarations of
816815
/// the same template. Calling this routine may implicitly allocate memory
817816
/// for the common pointer.
818817
CommonBase *getCommonPtr() const;
819818

819+
void setCommonPtr(CommonBase *C) const { Common.setPointer(C); }
820+
820821
virtual CommonBase *newCommon(ASTContext &C) const = 0;
821822

822823
// Construct a template decl with name, parameters, and templated element.
@@ -857,15 +858,22 @@ class RedeclarableTemplateDecl : public TemplateDecl,
857858
/// template<> template<typename T>
858859
/// struct X<int>::Inner { /* ... */ };
859860
/// \endcode
860-
bool isMemberSpecialization() const {
861-
return getCommonPtr()->InstantiatedFromMember.getInt();
861+
bool isMemberSpecialization() const { return Common.getInt(); }
862+
863+
/// Determines whether any redeclaration of this template was
864+
/// a specialization of a member template.
865+
bool hasMemberSpecialization() const {
866+
for (const auto *D : redecls()) {
867+
if (D->isMemberSpecialization())
868+
return true;
869+
}
870+
return false;
862871
}
863872

864873
/// Note that this member template is a specialization.
865874
void setMemberSpecialization() {
866-
assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
867-
"Only member templates can be member template specializations");
868-
getCommonPtr()->InstantiatedFromMember.setInt(true);
875+
assert(!isMemberSpecialization() && "already a member specialization");
876+
Common.setInt(true);
869877
}
870878

871879
/// Retrieve the member template from which this template was
@@ -905,12 +913,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
905913
/// void X<T>::f(T, U);
906914
/// \endcode
907915
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
908-
return getCommonPtr()->InstantiatedFromMember.getPointer();
916+
return getCommonPtr()->InstantiatedFromMember;
909917
}
910918

911919
void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
912-
assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
913-
getCommonPtr()->InstantiatedFromMember.setPointer(TD);
920+
assert(!getCommonPtr()->InstantiatedFromMember);
921+
getCommonPtr()->InstantiatedFromMember = TD;
914922
}
915923

916924
/// Retrieve the "injected" template arguments that correspond to the
@@ -1989,6 +1997,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
19891997
/// template arguments have been deduced.
19901998
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
19911999
const TemplateArgumentList *TemplateArgs) {
2000+
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
2001+
"A partial specialization cannot be instantiated from a template");
19922002
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
19932003
"Already set to a class template partial specialization!");
19942004
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2000,6 +2010,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
20002010
/// Note that this class template specialization is an instantiation
20012011
/// of the given class template.
20022012
void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
2013+
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
2014+
"A partial specialization cannot be instantiated from a template");
20032015
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
20042016
"Previously set to a class template partial specialization!");
20052017
SpecializedTemplate = TemplDecl;
@@ -2187,19 +2199,23 @@ class ClassTemplatePartialSpecializationDecl
21872199
/// struct X<int>::Inner<T*> { /* ... */ };
21882200
/// \endcode
21892201
bool isMemberSpecialization() const {
2190-
const auto *First =
2191-
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
2192-
return First->InstantiatedFromMember.getInt();
2202+
return InstantiatedFromMember.getInt();
21932203
}
21942204

2195-
/// Note that this member template is a specialization.
2196-
void setMemberSpecialization() {
2197-
auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
2198-
assert(First->InstantiatedFromMember.getPointer() &&
2199-
"Only member templates can be member template specializations");
2200-
return First->InstantiatedFromMember.setInt(true);
2205+
/// Determines whether any redeclaration of this this class template partial
2206+
/// specialization was a specialization of a member partial specialization.
2207+
bool hasMemberSpecialization() const {
2208+
for (const auto *D : redecls()) {
2209+
if (cast<ClassTemplatePartialSpecializationDecl>(D)
2210+
->isMemberSpecialization())
2211+
return true;
2212+
}
2213+
return false;
22012214
}
22022215

2216+
/// Note that this member template is a specialization.
2217+
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
2218+
22032219
/// Retrieves the injected specialization type for this partial
22042220
/// specialization. This is not the same as the type-decl-type for
22052221
/// this partial specialization, which is an InjectedClassNameType.
@@ -2268,10 +2284,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
22682284
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
22692285
}
22702286

2271-
void setCommonPtr(Common *C) {
2272-
RedeclarableTemplateDecl::Common = C;
2273-
}
2274-
22752287
public:
22762288

22772289
friend class ASTDeclReader;
@@ -2754,6 +2766,8 @@ class VarTemplateSpecializationDecl : public VarDecl,
27542766
/// template arguments have been deduced.
27552767
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
27562768
const TemplateArgumentList *TemplateArgs) {
2769+
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
2770+
"A partial specialization cannot be instantiated from a template");
27572771
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
27582772
"Already set to a variable template partial specialization!");
27592773
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2765,6 +2779,8 @@ class VarTemplateSpecializationDecl : public VarDecl,
27652779
/// Note that this variable template specialization is an instantiation
27662780
/// of the given variable template.
27672781
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
2782+
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
2783+
"A partial specialization cannot be instantiated from a template");
27682784
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
27692785
"Previously set to a variable template partial specialization!");
27702786
SpecializedTemplate = TemplDecl;
@@ -2949,19 +2965,24 @@ class VarTemplatePartialSpecializationDecl
29492965
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
29502966
/// \endcode
29512967
bool isMemberSpecialization() const {
2952-
const auto *First =
2953-
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
2954-
return First->InstantiatedFromMember.getInt();
2968+
return InstantiatedFromMember.getInt();
29552969
}
29562970

2957-
/// Note that this member template is a specialization.
2958-
void setMemberSpecialization() {
2959-
auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
2960-
assert(First->InstantiatedFromMember.getPointer() &&
2961-
"Only member templates can be member template specializations");
2962-
return First->InstantiatedFromMember.setInt(true);
2971+
/// Determines whether any redeclaration of this this variable template
2972+
/// partial specialization was a specialization of a member partial
2973+
/// specialization.
2974+
bool hasMemberSpecialization() const {
2975+
for (const auto *D : redecls()) {
2976+
if (cast<VarTemplatePartialSpecializationDecl>(D)
2977+
->isMemberSpecialization())
2978+
return true;
2979+
}
2980+
return false;
29632981
}
29642982

2983+
/// Note that this member template is a specialization.
2984+
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
2985+
29652986
SourceRange getSourceRange() const override LLVM_READONLY;
29662987

29672988
void Profile(llvm::FoldingSetNodeID &ID) const {

clang/include/clang/Sema/Sema.h

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11327,9 +11327,9 @@ class Sema final : public SemaBase {
1132711327
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
1132811328
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
1132911329
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
11330-
SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
11331-
TemplateParameterList **OuterTemplateParamLists,
11332-
SkipBodyInfo *SkipBody = nullptr);
11330+
SourceLocation FriendLoc,
11331+
ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
11332+
bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
1133311333

1133411334
/// Translates template arguments as provided by the parser
1133511335
/// into template arguments used by semantic analysis.
@@ -11368,7 +11368,8 @@ class Sema final : public SemaBase {
1136811368
DeclResult ActOnVarTemplateSpecialization(
1136911369
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
1137011370
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
11371-
StorageClass SC, bool IsPartialSpecialization);
11371+
StorageClass SC, bool IsPartialSpecialization,
11372+
bool IsMemberSpecialization);
1137211373

1137311374
/// Get the specialization of the given variable template corresponding to
1137411375
/// the specified argument list, or a null-but-valid result if the arguments
@@ -13009,28 +13010,14 @@ class Sema final : public SemaBase {
1300913010
/// dealing with a specialization. This is only relevant for function
1301013011
/// template specializations.
1301113012
///
13012-
/// \param Pattern If non-NULL, indicates the pattern from which we will be
13013-
/// instantiating the definition of the given declaration, \p ND. This is
13014-
/// used to determine the proper set of template instantiation arguments for
13015-
/// friend function template specializations.
13016-
///
1301713013
/// \param ForConstraintInstantiation when collecting arguments,
1301813014
/// ForConstraintInstantiation indicates we should continue looking when
1301913015
/// encountering a lambda generic call operator, and continue looking for
1302013016
/// arguments on an enclosing class template.
13021-
///
13022-
/// \param SkipForSpecialization when specified, any template specializations
13023-
/// in a traversal would be ignored.
13024-
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
13025-
/// when encountering a specialized member function template, rather than
13026-
/// returning immediately.
1302713017
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
1302813018
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
1302913019
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
13030-
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
13031-
bool ForConstraintInstantiation = false,
13032-
bool SkipForSpecialization = false,
13033-
bool ForDefaultArgumentSubstitution = false);
13020+
bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
1303413021

1303513022
/// RAII object to handle the state changes required to synthesize
1303613023
/// a function body.

clang/lib/AST/Decl.cpp

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2704,21 +2704,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
27042704
if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
27052705
auto From = VDTemplSpec->getInstantiatedFrom();
27062706
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
2707-
while (!VTD->isMemberSpecialization()) {
2708-
auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
2709-
if (!NewVTD)
2707+
while (!VTD->hasMemberSpecialization()) {
2708+
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
2709+
VTD = NewVTD;
2710+
else
27102711
break;
2711-
VTD = NewVTD;
27122712
}
27132713
return getDefinitionOrSelf(VTD->getTemplatedDecl());
27142714
}
27152715
if (auto *VTPSD =
27162716
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
2717-
while (!VTPSD->isMemberSpecialization()) {
2718-
auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
2719-
if (!NewVTPSD)
2717+
while (!VTPSD->hasMemberSpecialization()) {
2718+
if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
2719+
VTPSD = NewVTPSD;
2720+
else
27202721
break;
2721-
VTPSD = NewVTPSD;
27222722
}
27232723
return getDefinitionOrSelf<VarDecl>(VTPSD);
27242724
}
@@ -2727,15 +2727,14 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
27272727

27282728
// If this is the pattern of a variable template, find where it was
27292729
// instantiated from. FIXME: Is this necessary?
2730-
if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
2731-
while (!VarTemplate->isMemberSpecialization()) {
2732-
auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
2733-
if (!NewVT)
2730+
if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
2731+
while (!VTD->hasMemberSpecialization()) {
2732+
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
2733+
VTD = NewVTD;
2734+
else
27342735
break;
2735-
VarTemplate = NewVT;
27362736
}
2737-
2738-
return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
2737+
return getDefinitionOrSelf(VTD->getTemplatedDecl());
27392738
}
27402739

27412740
if (VD == this)
@@ -4150,11 +4149,11 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
41504149
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
41514150
// If we hit a point where the user provided a specialization of this
41524151
// template, we're done looking.
4153-
while (!ForDefinition || !Primary->isMemberSpecialization()) {
4154-
auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
4155-
if (!NewPrimary)
4152+
while (!ForDefinition || !Primary->hasMemberSpecialization()) {
4153+
if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
4154+
Primary = NewPrimary;
4155+
else
41564156
break;
4157-
Primary = NewPrimary;
41584157
}
41594158

41604159
return getDefinitionOrSelf(Primary->getTemplatedDecl());

clang/lib/AST/DeclCXX.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,19 +2023,21 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
20232023
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
20242024
auto From = TD->getInstantiatedFrom();
20252025
if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
2026-
while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
2027-
if (NewCTD->isMemberSpecialization())
2026+
while (!CTD->hasMemberSpecialization()) {
2027+
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
2028+
CTD = NewCTD;
2029+
else
20282030
break;
2029-
CTD = NewCTD;
20302031
}
20312032
return GetDefinitionOrSelf(CTD->getTemplatedDecl());
20322033
}
20332034
if (auto *CTPSD =
20342035
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
2035-
while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
2036-
if (NewCTPSD->isMemberSpecialization())
2036+
while (!CTPSD->hasMemberSpecialization()) {
2037+
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
2038+
CTPSD = NewCTPSD;
2039+
else
20372040
break;
2038-
CTPSD = NewCTPSD;
20392041
}
20402042
return GetDefinitionOrSelf(CTPSD);
20412043
}

0 commit comments

Comments
 (0)