Skip to content

Commit 4da8ac3

Browse files
authored
Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (llvm#106585)" (llvm#111173)
Reapplies llvm#106585, fixing an issue where non-dependent names of member templates appearing prior to that member template being explicitly specialized for an implicitly instantiated class template specialization would incorrectly use the definition of the explicitly specialized member template.
1 parent 148a8fe commit 4da8ac3

20 files changed

+1005
-702
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,9 @@ Bug Fixes to C++ Support
481481
in certain friend declarations. (#GH93099)
482482
- Clang now instantiates the correct lambda call operator when a lambda's class type is
483483
merged across modules. (#GH110401)
484+
- Clang now uses the correct set of template argument lists when comparing the constraints of
485+
out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of
486+
a class template. (#GH102320)
484487

485488
Bug Fixes to AST Handling
486489
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/DeclTemplate.h

Lines changed: 27 additions & 39 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,12 @@ 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();
862-
}
861+
bool isMemberSpecialization() const { return Common.getInt(); }
863862

864863
/// Note that this member template is a specialization.
865864
void setMemberSpecialization() {
866-
assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
867-
"Only member templates can be member template specializations");
868-
getCommonPtr()->InstantiatedFromMember.setInt(true);
865+
assert(!isMemberSpecialization() && "already a member specialization");
866+
Common.setInt(true);
869867
}
870868

871869
/// Retrieve the member template from which this template was
@@ -905,12 +903,12 @@ class RedeclarableTemplateDecl : public TemplateDecl,
905903
/// void X<T>::f(T, U);
906904
/// \endcode
907905
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
908-
return getCommonPtr()->InstantiatedFromMember.getPointer();
906+
return getCommonPtr()->InstantiatedFromMember;
909907
}
910908

911909
void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
912-
assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
913-
getCommonPtr()->InstantiatedFromMember.setPointer(TD);
910+
assert(!getCommonPtr()->InstantiatedFromMember);
911+
getCommonPtr()->InstantiatedFromMember = TD;
914912
}
915913

916914
/// Retrieve the "injected" template arguments that correspond to the
@@ -1989,6 +1987,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
19891987
/// template arguments have been deduced.
19901988
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
19911989
const TemplateArgumentList *TemplateArgs) {
1990+
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
1991+
"A partial specialization cannot be instantiated from a template");
19921992
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
19931993
"Already set to a class template partial specialization!");
19941994
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2000,6 +2000,8 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
20002000
/// Note that this class template specialization is an instantiation
20012001
/// of the given class template.
20022002
void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
2003+
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
2004+
"A partial specialization cannot be instantiated from a template");
20032005
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
20042006
"Previously set to a class template partial specialization!");
20052007
SpecializedTemplate = TemplDecl;
@@ -2187,18 +2189,11 @@ class ClassTemplatePartialSpecializationDecl
21872189
/// struct X<int>::Inner<T*> { /* ... */ };
21882190
/// \endcode
21892191
bool isMemberSpecialization() const {
2190-
const auto *First =
2191-
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
2192-
return First->InstantiatedFromMember.getInt();
2192+
return InstantiatedFromMember.getInt();
21932193
}
21942194

21952195
/// 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);
2201-
}
2196+
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
22022197

22032198
/// Retrieves the injected specialization type for this partial
22042199
/// specialization. This is not the same as the type-decl-type for
@@ -2268,10 +2263,6 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
22682263
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
22692264
}
22702265

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

22772268
friend class ASTDeclReader;
@@ -2754,6 +2745,8 @@ class VarTemplateSpecializationDecl : public VarDecl,
27542745
/// template arguments have been deduced.
27552746
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
27562747
const TemplateArgumentList *TemplateArgs) {
2748+
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
2749+
"A partial specialization cannot be instantiated from a template");
27572750
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
27582751
"Already set to a variable template partial specialization!");
27592752
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
@@ -2765,6 +2758,8 @@ class VarTemplateSpecializationDecl : public VarDecl,
27652758
/// Note that this variable template specialization is an instantiation
27662759
/// of the given variable template.
27672760
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
2761+
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
2762+
"A partial specialization cannot be instantiated from a template");
27682763
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
27692764
"Previously set to a variable template partial specialization!");
27702765
SpecializedTemplate = TemplDecl;
@@ -2949,18 +2944,11 @@ class VarTemplatePartialSpecializationDecl
29492944
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
29502945
/// \endcode
29512946
bool isMemberSpecialization() const {
2952-
const auto *First =
2953-
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
2954-
return First->InstantiatedFromMember.getInt();
2947+
return InstantiatedFromMember.getInt();
29552948
}
29562949

29572950
/// 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);
2963-
}
2951+
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
29642952

29652953
SourceRange getSourceRange() const override LLVM_READONLY;
29662954

clang/include/clang/Sema/Sema.h

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

1133211332
/// Translates template arguments as provided by the parser
1133311333
/// into template arguments used by semantic analysis.
@@ -11366,7 +11366,8 @@ class Sema final : public SemaBase {
1136611366
DeclResult ActOnVarTemplateSpecialization(
1136711367
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
1136811368
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
11369-
StorageClass SC, bool IsPartialSpecialization);
11369+
StorageClass SC, bool IsPartialSpecialization,
11370+
bool IsMemberSpecialization);
1137011371

1137111372
/// Get the specialization of the given variable template corresponding to
1137211373
/// the specified argument list, or a null-but-valid result if the arguments
@@ -13017,28 +13018,14 @@ class Sema final : public SemaBase {
1301713018
/// dealing with a specialization. This is only relevant for function
1301813019
/// template specializations.
1301913020
///
13020-
/// \param Pattern If non-NULL, indicates the pattern from which we will be
13021-
/// instantiating the definition of the given declaration, \p ND. This is
13022-
/// used to determine the proper set of template instantiation arguments for
13023-
/// friend function template specializations.
13024-
///
1302513021
/// \param ForConstraintInstantiation when collecting arguments,
1302613022
/// ForConstraintInstantiation indicates we should continue looking when
1302713023
/// encountering a lambda generic call operator, and continue looking for
1302813024
/// arguments on an enclosing class template.
13029-
///
13030-
/// \param SkipForSpecialization when specified, any template specializations
13031-
/// in a traversal would be ignored.
13032-
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
13033-
/// when encountering a specialized member function template, rather than
13034-
/// returning immediately.
1303513025
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
1303613026
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
1303713027
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
13038-
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
13039-
bool ForConstraintInstantiation = false,
13040-
bool SkipForSpecialization = false,
13041-
bool ForDefaultArgumentSubstitution = false);
13028+
bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
1304213029

1304313030
/// RAII object to handle the state changes required to synthesize
1304413031
/// a function body.

clang/lib/AST/Decl.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,21 +2696,27 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
26962696
if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
26972697
auto From = VDTemplSpec->getInstantiatedFrom();
26982698
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
2699-
while (!VTD->isMemberSpecialization()) {
2700-
auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
2701-
if (!NewVTD)
2699+
while (true) {
2700+
VTD = VTD->getMostRecentDecl();
2701+
if (VTD->isMemberSpecialization())
2702+
break;
2703+
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
2704+
VTD = NewVTD;
2705+
else
27022706
break;
2703-
VTD = NewVTD;
27042707
}
27052708
return getDefinitionOrSelf(VTD->getTemplatedDecl());
27062709
}
27072710
if (auto *VTPSD =
27082711
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
2709-
while (!VTPSD->isMemberSpecialization()) {
2710-
auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
2711-
if (!NewVTPSD)
2712+
while (true) {
2713+
VTPSD = VTPSD->getMostRecentDecl();
2714+
if (VTPSD->isMemberSpecialization())
2715+
break;
2716+
if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
2717+
VTPSD = NewVTPSD;
2718+
else
27122719
break;
2713-
VTPSD = NewVTPSD;
27142720
}
27152721
return getDefinitionOrSelf<VarDecl>(VTPSD);
27162722
}
@@ -2719,15 +2725,17 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
27192725

27202726
// If this is the pattern of a variable template, find where it was
27212727
// instantiated from. FIXME: Is this necessary?
2722-
if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
2723-
while (!VarTemplate->isMemberSpecialization()) {
2724-
auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
2725-
if (!NewVT)
2728+
if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
2729+
while (true) {
2730+
VTD = VTD->getMostRecentDecl();
2731+
if (VTD->isMemberSpecialization())
2732+
break;
2733+
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
2734+
VTD = NewVTD;
2735+
else
27262736
break;
2727-
VarTemplate = NewVT;
27282737
}
2729-
2730-
return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
2738+
return getDefinitionOrSelf(VTD->getTemplatedDecl());
27312739
}
27322740

27332741
if (VD == this)
@@ -4142,11 +4150,14 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
41424150
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
41434151
// If we hit a point where the user provided a specialization of this
41444152
// template, we're done looking.
4145-
while (!ForDefinition || !Primary->isMemberSpecialization()) {
4146-
auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
4147-
if (!NewPrimary)
4153+
while (true) {
4154+
Primary = Primary->getMostRecentDecl();
4155+
if (ForDefinition && Primary->isMemberSpecialization())
4156+
break;
4157+
if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
4158+
Primary = NewPrimary;
4159+
else
41484160
break;
4149-
Primary = NewPrimary;
41504161
}
41514162

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

clang/lib/AST/DeclCXX.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,19 +2023,27 @@ 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 (true) {
2027+
CTD = CTD->getMostRecentDecl();
2028+
if (CTD->isMemberSpecialization())
2029+
break;
2030+
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
2031+
CTD = NewCTD;
2032+
else
20282033
break;
2029-
CTD = NewCTD;
20302034
}
20312035
return GetDefinitionOrSelf(CTD->getTemplatedDecl());
20322036
}
20332037
if (auto *CTPSD =
20342038
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
2035-
while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
2036-
if (NewCTPSD->isMemberSpecialization())
2039+
while (true) {
2040+
CTPSD = CTPSD->getMostRecentDecl();
2041+
if (CTPSD->isMemberSpecialization())
2042+
break;
2043+
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
2044+
CTPSD = NewCTPSD;
2045+
else
20372046
break;
2038-
CTPSD = NewCTPSD;
20392047
}
20402048
return GetDefinitionOrSelf(CTPSD);
20412049
}

0 commit comments

Comments
 (0)