Skip to content

Commit 14db4ba

Browse files
committed
[Clang][Sema] Rebuild template parameters for out-of-line template definitions and partial specializations
1 parent 8b4d4be commit 14db4ba

File tree

3 files changed

+129
-9
lines changed

3 files changed

+129
-9
lines changed

clang/lib/Sema/SemaDecl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7502,6 +7502,12 @@ NamedDecl *Sema::ActOnVariableDeclarator(
75027502
/*never a friend*/ false, IsMemberSpecialization, Invalid);
75037503

75047504
if (TemplateParams) {
7505+
if (DC->isDependentContext()) {
7506+
ContextRAII SavedContext(*this, DC);
7507+
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
7508+
Invalid = true;
7509+
}
7510+
75057511
if (!TemplateParams->size() &&
75067512
D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
75077513
// There is an extraneous 'template<>' for this variable. Complain

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8089,13 +8089,14 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
80898089
return true;
80908090
}
80918091

8092+
DeclContext *DC = ClassTemplate->getDeclContext();
8093+
80928094
bool isMemberSpecialization = false;
80938095
bool isPartialSpecialization = false;
80948096

80958097
if (SS.isSet()) {
80968098
if (TUK != TagUseKind::Reference && TUK != TagUseKind::Friend &&
8097-
diagnoseQualifiedDeclaration(SS, ClassTemplate->getDeclContext(),
8098-
ClassTemplate->getDeclName(),
8099+
diagnoseQualifiedDeclaration(SS, DC, ClassTemplate->getDeclName(),
80998100
TemplateNameLoc, &TemplateId,
81008101
/*IsMemberSpecialization=*/false))
81018102
return true;
@@ -8117,6 +8118,12 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
81178118
if (TemplateParams && CheckTemplateDeclScope(S, TemplateParams))
81188119
return true;
81198120

8121+
if (TemplateParams && DC->isDependentContext()) {
8122+
ContextRAII SavedContext(*this, DC);
8123+
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
8124+
return true;
8125+
}
8126+
81208127
if (TemplateParams && TemplateParams->size() > 0) {
81218128
isPartialSpecialization = true;
81228129

@@ -8282,9 +8289,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
82828289
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
82838290
ClassTemplatePartialSpecializationDecl *Partial =
82848291
ClassTemplatePartialSpecializationDecl::Create(
8285-
Context, Kind, ClassTemplate->getDeclContext(), KWLoc,
8286-
TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted,
8287-
CanonType, PrevPartial);
8292+
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
8293+
ClassTemplate, CanonicalConverted, CanonType, PrevPartial);
82888294
Partial->setTemplateArgsAsWritten(TemplateArgs);
82898295
SetNestedNameSpecifier(*this, Partial, SS);
82908296
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
@@ -8306,8 +8312,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
83068312
// Create a new class template specialization declaration node for
83078313
// this explicit specialization or friend declaration.
83088314
Specialization = ClassTemplateSpecializationDecl::Create(
8309-
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
8310-
ClassTemplate, CanonicalConverted, PrevDecl);
8315+
Context, Kind, DC, KWLoc, TemplateNameLoc, ClassTemplate,
8316+
CanonicalConverted, PrevDecl);
83118317
Specialization->setTemplateArgsAsWritten(TemplateArgs);
83128318
SetNestedNameSpecifier(*this, Specialization, SS);
83138319
if (TemplateParameterLists.size() > 0) {

clang/test/CXX/temp/temp.decls/temp.mem/p1.cpp

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify %s
2-
// expected-no-diagnostics
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
32

43
template <class T> struct A {
54
static T cond;
@@ -35,3 +34,112 @@ namespace PR6376 {
3534

3635
Z<float, int> z0;
3736
}
37+
38+
namespace OutOfLine {
39+
template<typename T>
40+
struct A {
41+
struct B { };
42+
43+
template<typename U, B V>
44+
void f();
45+
46+
template<typename U, B V>
47+
void g() { } // expected-note {{previous definition is here}}
48+
49+
template<typename U, B V>
50+
static int x;
51+
52+
template<typename U, B V>
53+
static int x<U*, V>;
54+
55+
template<typename U, B V>
56+
static constexpr int x<U&, V> = 0; // expected-note {{previous definition is here}}
57+
58+
template<typename U, B V>
59+
struct C;
60+
61+
template<typename U, B V>
62+
struct C<U*, V>;
63+
64+
template<typename U, B V>
65+
struct C<U&, V> { }; // expected-note {{previous definition is here}}
66+
};
67+
68+
template<typename T>
69+
template<typename U, typename A<T>::B V>
70+
void A<T>::f() { }
71+
72+
template<typename T>
73+
template<typename U, typename A<T>::B V>
74+
void A<T>::g() { } // expected-error {{redefinition of 'g'}}
75+
76+
template<typename T>
77+
template<typename U, typename A<T>::B V>
78+
int A<T>::x = 0;
79+
80+
template<typename T>
81+
template<typename U, typename A<T>::B V>
82+
int A<T>::x<U*, V> = 0;
83+
84+
template<typename T>
85+
template<typename U, typename A<T>::B V>
86+
constexpr int A<T>::x<U&, V> = 0; // expected-error {{redefinition of 'x<U &, V>'}}
87+
88+
template<typename T>
89+
template<typename U, typename A<T>::B V>
90+
struct A<T>::C { };
91+
92+
template<typename T>
93+
template<typename U, typename A<T>::B V>
94+
struct A<T>::C<U*, V> { };
95+
96+
template<typename T>
97+
template<typename U, typename A<T>::B V>
98+
struct A<T>::C<U&, V> { }; // expected-error {{redefinition of 'C<U &, V>'}}
99+
100+
// FIXME: Crashes when parsing the non-type template parameter prior to C++20
101+
template<>
102+
template<typename U, A<int>::B V>
103+
void A<int>::f() { }
104+
105+
template<>
106+
template<typename U, A<int>::B V>
107+
void A<int>::g() { } // expected-note {{previous definition is here}}
108+
109+
template<>
110+
template<typename U, A<int>::B V>
111+
void A<int>::g() { } // expected-error {{redefinition of 'g'}}
112+
113+
template<>
114+
template<typename U, A<int>::B V>
115+
int A<int>::x = 0;
116+
117+
template<>
118+
template<typename U, A<int>::B V>
119+
int A<int>::x<U*, V> = 0;
120+
121+
template<>
122+
template<typename U, A<int>::B V>
123+
constexpr int A<int>::x<U&, V> = 0;
124+
125+
// FIXME: We should diagnose this redefinition!
126+
template<>
127+
template<typename U, A<int>::B V>
128+
constexpr int A<int>::x<U&, V> = 0;
129+
130+
template<>
131+
template<typename U, A<int>::B V>
132+
struct A<int>::C { };
133+
134+
template<>
135+
template<typename U, A<int>::B V>
136+
struct A<int>::C<U*, V> { };
137+
138+
template<>
139+
template<typename U, A<int>::B V>
140+
struct A<int>::C<U&, V> { }; // expected-note {{previous definition is here}}
141+
142+
template<>
143+
template<typename U, A<int>::B V>
144+
struct A<int>::C<U&, V> { }; // expected-error {{redefinition of 'C<U &, V>'}}
145+
}

0 commit comments

Comments
 (0)