Skip to content

Commit 11e6d82

Browse files
committed
[Clang][Sema] Always use latest declaration of primary template
1 parent 7d1e283 commit 11e6d82

File tree

8 files changed

+133
-65
lines changed

8 files changed

+133
-65
lines changed

clang/include/clang/AST/DeclTemplate.h

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -857,16 +857,6 @@ class RedeclarableTemplateDecl : public TemplateDecl,
857857
/// \endcode
858858
bool isMemberSpecialization() const { return Common.getInt(); }
859859

860-
/// Determines whether any redeclaration of this template was
861-
/// a specialization of a member template.
862-
bool hasMemberSpecialization() const {
863-
for (const auto *D : redecls()) {
864-
if (D->isMemberSpecialization())
865-
return true;
866-
}
867-
return false;
868-
}
869-
870860
/// Note that this member template is a specialization.
871861
void setMemberSpecialization() {
872862
assert(!isMemberSpecialization() && "already a member specialization");
@@ -1965,13 +1955,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
19651955
/// specialization which was specialized by this.
19661956
llvm::PointerUnion<ClassTemplateDecl *,
19671957
ClassTemplatePartialSpecializationDecl *>
1968-
getSpecializedTemplateOrPartial() const {
1969-
if (const auto *PartialSpec =
1970-
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
1971-
return PartialSpec->PartialSpecialization;
1972-
1973-
return SpecializedTemplate.get<ClassTemplateDecl*>();
1974-
}
1958+
getSpecializedTemplateOrPartial() const;
19751959

19761960
/// Retrieve the set of template arguments that should be used
19771961
/// to instantiate members of the class template or class template partial
@@ -2208,17 +2192,6 @@ class ClassTemplatePartialSpecializationDecl
22082192
return InstantiatedFromMember.getInt();
22092193
}
22102194

2211-
/// Determines whether any redeclaration of this this class template partial
2212-
/// specialization was a specialization of a member partial specialization.
2213-
bool hasMemberSpecialization() const {
2214-
for (const auto *D : redecls()) {
2215-
if (cast<ClassTemplatePartialSpecializationDecl>(D)
2216-
->isMemberSpecialization())
2217-
return true;
2218-
}
2219-
return false;
2220-
}
2221-
22222195
/// Note that this member template is a specialization.
22232196
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
22242197

@@ -2740,13 +2713,7 @@ class VarTemplateSpecializationDecl : public VarDecl,
27402713
/// Retrieve the variable template or variable template partial
27412714
/// specialization which was specialized by this.
27422715
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
2743-
getSpecializedTemplateOrPartial() const {
2744-
if (const auto *PartialSpec =
2745-
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
2746-
return PartialSpec->PartialSpecialization;
2747-
2748-
return SpecializedTemplate.get<VarTemplateDecl *>();
2749-
}
2716+
getSpecializedTemplateOrPartial() const;
27502717

27512718
/// Retrieve the set of template arguments that should be used
27522719
/// to instantiate the initializer of the variable template or variable
@@ -2980,18 +2947,6 @@ class VarTemplatePartialSpecializationDecl
29802947
return InstantiatedFromMember.getInt();
29812948
}
29822949

2983-
/// Determines whether any redeclaration of this this variable template
2984-
/// partial specialization was a specialization of a member partial
2985-
/// specialization.
2986-
bool hasMemberSpecialization() const {
2987-
for (const auto *D : redecls()) {
2988-
if (cast<VarTemplatePartialSpecializationDecl>(D)
2989-
->isMemberSpecialization())
2990-
return true;
2991-
}
2992-
return false;
2993-
}
2994-
29952950
/// Note that this member template is a specialization.
29962951
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
29972952

clang/lib/AST/Decl.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2708,7 +2708,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
27082708
if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
27092709
auto From = VDTemplSpec->getInstantiatedFrom();
27102710
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
2711-
while (!VTD->hasMemberSpecialization()) {
2711+
while (!VTD->isMemberSpecialization()) {
27122712
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
27132713
VTD = NewVTD;
27142714
else
@@ -2718,7 +2718,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
27182718
}
27192719
if (auto *VTPSD =
27202720
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
2721-
while (!VTPSD->hasMemberSpecialization()) {
2721+
while (!VTPSD->isMemberSpecialization()) {
27222722
if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
27232723
VTPSD = NewVTPSD;
27242724
else
@@ -2732,7 +2732,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
27322732
// If this is the pattern of a variable template, find where it was
27332733
// instantiated from. FIXME: Is this necessary?
27342734
if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
2735-
while (!VTD->hasMemberSpecialization()) {
2735+
while (!VTD->isMemberSpecialization()) {
27362736
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
27372737
VTD = NewVTD;
27382738
else
@@ -4153,7 +4153,7 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
41534153
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
41544154
// If we hit a point where the user provided a specialization of this
41554155
// template, we're done looking.
4156-
while (!ForDefinition || !Primary->hasMemberSpecialization()) {
4156+
while (!ForDefinition || !Primary->isMemberSpecialization()) {
41574157
if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
41584158
Primary = NewPrimary;
41594159
else
@@ -4170,7 +4170,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
41704170
if (FunctionTemplateSpecializationInfo *Info
41714171
= TemplateOrSpecialization
41724172
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
4173-
return Info->getTemplate();
4173+
return Info->getTemplate()->getMostRecentDecl();
41744174
}
41754175
return nullptr;
41764176
}

clang/lib/AST/DeclCXX.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,7 +2030,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
20302030
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
20312031
auto From = TD->getInstantiatedFrom();
20322032
if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
2033-
while (!CTD->hasMemberSpecialization()) {
2033+
while (!CTD->isMemberSpecialization()) {
20342034
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
20352035
CTD = NewCTD;
20362036
else
@@ -2040,7 +2040,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
20402040
}
20412041
if (auto *CTPSD =
20422042
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
2043-
while (!CTPSD->hasMemberSpecialization()) {
2043+
while (!CTPSD->isMemberSpecialization()) {
20442044
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
20452045
CTPSD = NewCTPSD;
20462046
else

clang/lib/AST/DeclTemplate.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,17 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
993993
if (const auto *PartialSpec =
994994
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
995995
return PartialSpec->PartialSpecialization->getSpecializedTemplate();
996-
return SpecializedTemplate.get<ClassTemplateDecl*>();
996+
return SpecializedTemplate.get<ClassTemplateDecl *>()->getMostRecentDecl();
997+
}
998+
999+
llvm::PointerUnion<ClassTemplateDecl *,
1000+
ClassTemplatePartialSpecializationDecl *>
1001+
ClassTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const {
1002+
if (const auto *PartialSpec =
1003+
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
1004+
return PartialSpec->PartialSpecialization->getMostRecentDecl();
1005+
1006+
return SpecializedTemplate.get<ClassTemplateDecl *>()->getMostRecentDecl();
9971007
}
9981008

9991009
SourceRange
@@ -1405,7 +1415,16 @@ VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
14051415
if (const auto *PartialSpec =
14061416
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
14071417
return PartialSpec->PartialSpecialization->getSpecializedTemplate();
1408-
return SpecializedTemplate.get<VarTemplateDecl *>();
1418+
return SpecializedTemplate.get<VarTemplateDecl *>()->getMostRecentDecl();
1419+
}
1420+
1421+
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
1422+
VarTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const {
1423+
if (const auto *PartialSpec =
1424+
SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
1425+
return PartialSpec->PartialSpecialization->getMostRecentDecl();
1426+
1427+
return SpecializedTemplate.get<VarTemplateDecl *>()->getMostRecentDecl();
14091428
}
14101429

14111430
SourceRange VarTemplateSpecializationDecl::getSourceRange() const {

clang/lib/Sema/SemaInit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9954,7 +9954,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
99549954
auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
99559955
auto *Pattern = Template;
99569956
while (Pattern->getInstantiatedFromMemberTemplate()) {
9957-
if (Pattern->hasMemberSpecialization())
9957+
if (Pattern->isMemberSpecialization())
99589958
break;
99599959
Pattern = Pattern->getInstantiatedFromMemberTemplate();
99609960
}

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ struct TemplateInstantiationArgumentCollecter
343343
// If this function was instantiated from a specialized member that is
344344
// a function template, we're done.
345345
assert(FD->getPrimaryTemplate() && "No function template?");
346-
if (FD->getPrimaryTemplate()->hasMemberSpecialization())
346+
if (FD->getPrimaryTemplate()->isMemberSpecialization())
347347
return Done();
348348

349349
// If this function is a generic lambda specialization, we are done.
@@ -442,11 +442,11 @@ struct TemplateInstantiationArgumentCollecter
442442
Specialized = CTSD->getSpecializedTemplateOrPartial();
443443
if (auto *CTPSD =
444444
Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
445-
if (CTPSD->hasMemberSpecialization())
445+
if (CTPSD->isMemberSpecialization())
446446
return Done();
447447
} else {
448448
auto *CTD = Specialized.get<ClassTemplateDecl *>();
449-
if (CTD->hasMemberSpecialization())
449+
if (CTD->isMemberSpecialization())
450450
return Done();
451451
}
452452
return UseNextDecl(CTSD);
@@ -478,11 +478,11 @@ struct TemplateInstantiationArgumentCollecter
478478
Specialized = VTSD->getSpecializedTemplateOrPartial();
479479
if (auto *VTPSD =
480480
Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
481-
if (VTPSD->hasMemberSpecialization())
481+
if (VTPSD->isMemberSpecialization())
482482
return Done();
483483
} else {
484484
auto *VTD = Specialized.get<VarTemplateDecl *>();
485-
if (VTD->hasMemberSpecialization())
485+
if (VTD->isMemberSpecialization())
486486
return Done();
487487
}
488488
return UseNextDecl(VTSD);
@@ -4141,7 +4141,7 @@ getPatternForClassTemplateSpecialization(
41414141
CXXRecordDecl *Pattern = nullptr;
41424142
Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial();
41434143
if (auto *CTD = Specialized.dyn_cast<ClassTemplateDecl *>()) {
4144-
while (!CTD->hasMemberSpecialization()) {
4144+
while (!CTD->isMemberSpecialization()) {
41454145
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
41464146
CTD = NewCTD;
41474147
else
@@ -4151,7 +4151,7 @@ getPatternForClassTemplateSpecialization(
41514151
} else if (auto *CTPSD =
41524152
Specialized
41534153
.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
4154-
while (!CTPSD->hasMemberSpecialization()) {
4154+
while (!CTPSD->isMemberSpecialization()) {
41554155
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
41564156
CTPSD = NewCTPSD;
41574157
else

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{{.+}} <line:[[@LINE-19]]:3, line:[[@LINE-17]]:3> line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}}
533+
// CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <col:5, col:40> 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{{$}}

clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,100 @@ namespace Defined {
177177
static_assert(A<short>::B<int*>::y == 2);
178178
} // namespace Defined
179179

180+
namespace Constrained {
181+
template<typename T>
182+
struct A {
183+
template<typename U, bool V> requires V
184+
static constexpr int f(); // expected-note {{declared here}}
185+
186+
template<typename U, bool V> requires V
187+
static const int x; // expected-note {{declared here}}
188+
189+
template<typename U, bool V> requires V
190+
static const int x<U*, V>; // expected-note 2{{declared here}}
191+
192+
template<typename U, bool V> requires V
193+
struct B; // expected-note {{template is declared here}}
194+
195+
template<typename U, bool V> requires V
196+
struct B<U*, V>; // expected-note {{template is declared here}}
197+
// expected-note@-1 {{partial specialization matches [with U = int, V = true]}}
198+
};
199+
200+
template<>
201+
template<typename U, bool V> requires V
202+
constexpr int A<short>::f() {
203+
return A<long>::f<U, V>();
204+
}
205+
206+
template<>
207+
template<typename U, bool V> requires V
208+
constexpr int A<short>::x = A<long>::x<U, V>;
209+
210+
template<>
211+
template<typename U, bool V> requires V
212+
constexpr int A<short>::x<U*, V> = A<long>::x<U*, V>; // expected-error {{constexpr variable 'x<int *, true>' must be initialized by a constant expression}}
213+
// expected-note@-1 {{initializer of 'x<int *, true>' is unknown}}
214+
// expected-note@-2 {{declared here}}
215+
216+
template<>
217+
template<typename U, bool V> requires V
218+
struct A<short>::B<U*, V> { // expected-note {{partial specialization matches [with U = int, V = true]}}
219+
static constexpr int y = A<long>::B<U*, V>::y;
220+
};
221+
222+
template<>
223+
template<typename U, bool V> requires V
224+
struct A<short>::B {
225+
static constexpr int y = A<long>::B<U, V>::y;
226+
};
227+
228+
template<>
229+
template<typename U, bool V> requires V
230+
constexpr int A<long>::f() {
231+
return 1;
232+
}
233+
234+
template<>
235+
template<typename U, bool V> requires V
236+
constexpr int A<long>::x = 1;
237+
238+
template<>
239+
template<typename U, bool V> requires V
240+
constexpr int A<long>::x<U*, V> = 2;
241+
242+
template<>
243+
template<typename U, bool V> requires V
244+
struct A<long>::B {
245+
static constexpr int y = 1;
246+
};
247+
248+
template<>
249+
template<typename U, bool V> requires V
250+
struct A<long>::B<U*, V> {
251+
static constexpr int y = 2;
252+
};
253+
254+
static_assert(A<int>::f<int, true>() == 0); // expected-error {{static assertion expression is not an integral constant expression}}
255+
// expected-note@-1 {{undefined function 'f<int, true>' cannot be used in a constant expression}}
256+
static_assert(A<int>::x<int, true> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
257+
// expected-note@-1 {{initializer of 'x<int, true>' is unknown}}
258+
static_assert(A<int>::x<int*, true> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
259+
// expected-note@-1 {{initializer of 'x<int *, true>' is unknown}}
260+
static_assert(A<int>::B<int, true>::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A<int>::B<int, true>'}}
261+
static_assert(A<int>::B<int*, true>::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A<int>::B<int *, true>'}}
262+
263+
static_assert(A<short>::f<int, true>() == 1);
264+
static_assert(A<short>::x<int, true> == 1);
265+
// FIXME: This is valid!
266+
static_assert(A<short>::x<int*, true> == 2); // expected-note {{in instantiation of}}
267+
// expected-error@-1 {{static assertion expression is not an integral constant expression}}
268+
// expected-note@-2 {{initializer of 'x<int *, true>' is not a constant expression}}
269+
static_assert(A<short>::B<int, true>::y == 1);
270+
// FIXME: This is valid!
271+
static_assert(A<short>::B<int*, true>::y == 2); // expected-error {{ambiguous partial specializations of 'B<int *, true>'}}
272+
} // namespace Constrained
273+
180274
namespace Dependent {
181275
template<int I>
182276
struct A {

0 commit comments

Comments
 (0)