Skip to content

Commit 55ffa56

Browse files
committed
[FOLD] use most recent declaration when getting instantiation pattern
1 parent a3cc13e commit 55ffa56

File tree

8 files changed

+200
-77
lines changed

8 files changed

+200
-77
lines changed

clang/include/clang/AST/DeclTemplate.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,7 +1955,13 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
19551955
/// specialization which was specialized by this.
19561956
llvm::PointerUnion<ClassTemplateDecl *,
19571957
ClassTemplatePartialSpecializationDecl *>
1958-
getSpecializedTemplateOrPartial() const;
1958+
getSpecializedTemplateOrPartial() const {
1959+
if (const auto *PartialSpec =
1960+
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
1961+
return PartialSpec->PartialSpecialization;
1962+
1963+
return SpecializedTemplate.get<ClassTemplateDecl*>();
1964+
}
19591965

19601966
/// Retrieve the set of template arguments that should be used
19611967
/// to instantiate members of the class template or class template partial
@@ -2707,7 +2713,13 @@ class VarTemplateSpecializationDecl : public VarDecl,
27072713
/// Retrieve the variable template or variable template partial
27082714
/// specialization which was specialized by this.
27092715
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
2710-
getSpecializedTemplateOrPartial() const;
2716+
getSpecializedTemplateOrPartial() const {
2717+
if (const auto *PartialSpec =
2718+
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
2719+
return PartialSpec->PartialSpecialization;
2720+
2721+
return SpecializedTemplate.get<VarTemplateDecl *>();
2722+
}
27112723

27122724
/// Retrieve the set of template arguments that should be used
27132725
/// to instantiate the initializer of the variable template or variable

clang/lib/AST/Decl.cpp

Lines changed: 31 additions & 20 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());
@@ -4159,7 +4170,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
41594170
if (FunctionTemplateSpecializationInfo *Info
41604171
= TemplateOrSpecialization
41614172
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
4162-
return Info->getTemplate()->getMostRecentDecl();
4173+
return Info->getTemplate();
41634174
}
41644175
return nullptr;
41654176
}

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
}

clang/lib/AST/DeclTemplate.cpp

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -997,23 +997,12 @@ void ClassTemplateSpecializationDecl::getNameForDiagnostic(
997997
}
998998
}
999999

1000-
llvm::PointerUnion<ClassTemplateDecl *,
1001-
ClassTemplatePartialSpecializationDecl *>
1002-
ClassTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const {
1003-
if (const auto *PartialSpec =
1004-
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
1005-
return PartialSpec->PartialSpecialization->getMostRecentDecl();
1006-
1007-
return SpecializedTemplate.get<ClassTemplateDecl *>()->getMostRecentDecl();
1008-
}
1009-
10101000
ClassTemplateDecl *
10111001
ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
10121002
if (const auto *PartialSpec =
10131003
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
1014-
return PartialSpec->PartialSpecialization->getSpecializedTemplate()
1015-
->getMostRecentDecl();
1016-
return SpecializedTemplate.get<ClassTemplateDecl *>()->getMostRecentDecl();
1004+
return PartialSpec->PartialSpecialization->getSpecializedTemplate();
1005+
return SpecializedTemplate.get<ClassTemplateDecl*>();
10171006
}
10181007

10191008
SourceRange
@@ -1421,21 +1410,11 @@ void VarTemplateSpecializationDecl::getNameForDiagnostic(
14211410
}
14221411
}
14231412

1424-
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
1425-
VarTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const {
1426-
if (const auto *PartialSpec =
1427-
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
1428-
return PartialSpec->PartialSpecialization->getMostRecentDecl();
1429-
1430-
return SpecializedTemplate.get<VarTemplateDecl *>()->getMostRecentDecl();
1431-
}
1432-
14331413
VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
14341414
if (const auto *PartialSpec =
14351415
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
1436-
return PartialSpec->PartialSpecialization->getSpecializedTemplate()
1437-
->getMostRecentDecl();
1438-
return SpecializedTemplate.get<VarTemplateDecl *>()->getMostRecentDecl();
1416+
return PartialSpec->PartialSpecialization->getSpecializedTemplate();
1417+
return SpecializedTemplate.get<VarTemplateDecl *>();
14391418
}
14401419

14411420
SourceRange VarTemplateSpecializationDecl::getSourceRange() const {

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4112,31 +4112,31 @@ getPatternForClassTemplateSpecialization(
41124112

41134113
CXXRecordDecl *Pattern = nullptr;
41144114
Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial();
4115-
if (auto *PartialSpec =
4116-
Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
4117-
// Instantiate using the best class template partial specialization.
4118-
while (PartialSpec->getInstantiatedFromMember()) {
4119-
// If we've found an explicit specialization of this class template,
4120-
// stop here and use that as the pattern.
4121-
if (PartialSpec->isMemberSpecialization())
4115+
if (auto *CTD = Specialized.dyn_cast<ClassTemplateDecl *>()) {
4116+
while (true) {
4117+
CTD = CTD->getMostRecentDecl();
4118+
if (CTD->isMemberSpecialization())
4119+
break;
4120+
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
4121+
CTD = NewCTD;
4122+
else
41224123
break;
4123-
4124-
PartialSpec = PartialSpec->getInstantiatedFromMember();
41254124
}
4126-
Pattern = PartialSpec;
4127-
} else {
4128-
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
4129-
while (Template->getInstantiatedFromMemberTemplate()) {
4130-
// If we've found an explicit specialization of this class template,
4131-
// stop here and use that as the pattern.
4132-
if (Template->isMemberSpecialization())
4125+
Pattern = CTD->getTemplatedDecl();
4126+
} else if (auto *CTPSD =
4127+
Specialized
4128+
.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
4129+
while (true) {
4130+
CTPSD = CTPSD->getMostRecentDecl();
4131+
if (CTPSD->isMemberSpecialization())
4132+
break;
4133+
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
4134+
CTPSD = NewCTPSD;
4135+
else
41334136
break;
4134-
4135-
Template = Template->getInstantiatedFromMemberTemplate();
41364137
}
4137-
Pattern = Template->getTemplatedDecl();
4138+
Pattern = CTPSD;
41384139
}
4139-
41404140
return Pattern;
41414141
}
41424142

clang/test/AST/ast-dump-decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ namespace testCanonicalTemplate {
530530
// CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} parent 0x{{.+}} <col:5, col:40> col:40 friend_undeclared TestClassTemplate{{$}}
531531
// CHECK-NEXT: | |-TemplateTypeParmDecl 0x{{.+}} <col:14, col:23> col:23 typename depth 1 index 0 T2{{$}}
532532
// CHECK-NEXT: | `-CXXRecordDecl 0x{{.+}} parent 0x{{.+}} <col:34, col:40> col:40 class TestClassTemplate{{$}}
533-
// CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <col:5, col:40> line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}}
533+
// CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-19]]:3, line:[[@LINE-17]]:3> line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}}
534534
// CHECK-NEXT: |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init{{$}}
535535
// CHECK-NEXT: | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr{{$}}
536536
// CHECK-NEXT: | |-CopyConstructor simple trivial has_const_param implicit_has_const_param{{$}}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
2+
3+
namespace Undefined {
4+
template<typename T>
5+
struct A {
6+
template<typename U>
7+
static constexpr int f(); // expected-note {{declared here}}
8+
9+
template<typename U>
10+
static const int x; // expected-note {{declared here}}
11+
12+
template<typename U>
13+
struct B; // expected-note {{template is declared here}}
14+
};
15+
16+
template<>
17+
template<typename U>
18+
constexpr int A<short>::f() {
19+
return A<long>::f<U>();
20+
}
21+
22+
template<>
23+
template<typename U>
24+
constexpr int A<short>::x = A<long>::x<U>;
25+
26+
template<>
27+
template<typename U>
28+
struct A<short>::B {
29+
static constexpr int y = A<long>::B<U>::y;
30+
};
31+
32+
template<>
33+
template<typename U>
34+
constexpr int A<long>::f() {
35+
return 1;
36+
}
37+
38+
template<>
39+
template<typename U>
40+
constexpr int A<long>::x = 1;
41+
42+
template<>
43+
template<typename U>
44+
struct A<long>::B {
45+
static constexpr int y = 1;
46+
};
47+
48+
static_assert(A<int>::f<int>() == 0); // expected-error {{static assertion expression is not an integral constant expression}}
49+
// expected-note@-1 {{undefined function 'f<int>' cannot be used in a constant expression}}
50+
static_assert(A<int>::x<int> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
51+
// expected-note@-1 {{initializer of 'x<int>' is unknown}}
52+
static_assert(A<int>::B<int>::y == 0); // expected-error {{implicit instantiation of undefined template 'Undefined::A<int>::B<int>'}}
53+
54+
static_assert(A<short>::f<int>() == 1);
55+
static_assert(A<short>::x<int> == 1);
56+
static_assert(A<short>::B<int>::y == 1);
57+
} // namespace Undefined
58+
59+
namespace Defined {
60+
template<typename T>
61+
struct A {
62+
template<typename U>
63+
static constexpr int f() {
64+
return 0;
65+
}
66+
67+
template<typename U>
68+
static constexpr int x = 0;
69+
70+
template<typename U>
71+
struct B {
72+
static constexpr int y = 0;
73+
};
74+
};
75+
76+
template<>
77+
template<typename U>
78+
constexpr int A<short>::f() {
79+
return A<long>::f<U>();
80+
}
81+
82+
template<>
83+
template<typename U>
84+
constexpr int A<short>::x = A<long>::x<U>;
85+
86+
template<>
87+
template<typename U>
88+
struct A<short>::B {
89+
static constexpr int y = A<long>::B<U>::y;
90+
};
91+
92+
template<>
93+
template<typename U>
94+
constexpr int A<long>::f() {
95+
return 1;
96+
}
97+
98+
template<>
99+
template<typename U>
100+
constexpr int A<long>::x = 1;
101+
102+
template<>
103+
template<typename U>
104+
struct A<long>::B {
105+
static constexpr int y = 1;
106+
};
107+
108+
static_assert(A<int>::f<int>() == 0);
109+
static_assert(A<int>::x<int> == 0);
110+
static_assert(A<int>::B<int>::y == 0);
111+
112+
static_assert(A<short>::f<int>() == 1);
113+
static_assert(A<short>::x<int> == 1);
114+
static_assert(A<short>::B<int>::y == 1);
115+
} // namespace Defined

clang/test/Modules/cxx-templates.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,7 @@ namespace hidden_specializations {
190190
cls<char*> uk4; // expected-error 1+{{partial specialization of 'cls<T *>' must be imported}} expected-error 1+{{definition of}}
191191
cls<void>::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}}
192192
cls<void>::nested_cls_t<int> unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
193-
// [email protected]:29 {{explicit specialization of 'nested_cls_t' must be imported}}
194-
// expected-note@-2 {{in evaluation of exception specification}}
195-
cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}}
193+
cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
196194

197195
// For enums, uses that would trigger instantiations of definitions are not
198196
// allowed.

0 commit comments

Comments
 (0)