Skip to content

Commit 7ecfb66

Browse files
authored
[Clang][Sema] Correctly look up primary template for variable template specializations (llvm#80359)
Consider the following: ``` namespace N0 { namespace N1 { template<typename T> int x1 = 0; } using namespace N1; } template<> int N0::x1<int>; ``` According to [dcl.meaning.general] p3.3: > - If the _declarator_ declares an explicit instantiation or a partial or explicit specialization, the _declarator_ does not bind a name. If it declares a class member, the terminal name of the _declarator-id_ is not looked up; otherwise, **only those lookup results that are nominable in `S` are considered when identifying any function template specialization being declared**. In particular, the requirement for lookup results to be nominal in the lookup context of the terminal name of the _declarator-id_ only applies to function template specializations -- not variable template specializations. We currently reject the above declaration, but we do (correctly) accept it if the using-directive is replaced with a `using` declaration naming `N0::N1::x1`. This patch makes it so the above specialization is (correctly) accepted.
1 parent 7b08b43 commit 7ecfb66

File tree

5 files changed

+130
-19
lines changed

5 files changed

+130
-19
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ Bug Fixes in This Version
160160

161161
- Fixed missing warnings when doing bool-like conversions in C23 (`#79435 <https://github.com/llvm/llvm-project/issues/79435>`_).
162162

163+
- Clang now accepts qualified partial/explicit specializations of variable templates that
164+
are not nominable in the lookup context of the specialization.
165+
163166
Bug Fixes to Compiler Builtins
164167
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
165168

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8456,7 +8456,7 @@ class Sema final {
84568456
SourceLocation RAngleLoc);
84578457

84588458
DeclResult ActOnVarTemplateSpecialization(
8459-
Scope *S, Declarator &D, TypeSourceInfo *DI,
8459+
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
84608460
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
84618461
StorageClass SC, bool IsPartialSpecialization);
84628462

clang/lib/Sema/SemaDecl.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7727,7 +7727,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
77277727
? TemplateParamLists[0]->getTemplateLoc()
77287728
: SourceLocation();
77297729
DeclResult Res = ActOnVarTemplateSpecialization(
7730-
S, D, TInfo, TemplateKWLoc, TemplateParams, SC,
7730+
S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
77317731
IsPartialSpecialization);
77327732
if (Res.isInvalid())
77337733
return nullptr;
@@ -8070,8 +8070,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
80708070
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
80718071
} else {
80728072
// If this is an explicit specialization of a static data member, check it.
8073-
if (IsMemberSpecialization && !NewVD->isInvalidDecl() &&
8074-
CheckMemberSpecialization(NewVD, Previous))
8073+
if (IsMemberSpecialization && !IsVariableTemplateSpecialization &&
8074+
!NewVD->isInvalidDecl() && CheckMemberSpecialization(NewVD, Previous))
80758075
NewVD->setInvalidDecl();
80768076

80778077
// Merge the decl with the existing one if appropriate.
@@ -8086,15 +8086,16 @@ NamedDecl *Sema::ActOnVariableDeclarator(
80868086
Previous.clear();
80878087
NewVD->setInvalidDecl();
80888088
}
8089-
} else if (D.getCXXScopeSpec().isSet()) {
8089+
} else if (D.getCXXScopeSpec().isSet() &&
8090+
!IsVariableTemplateSpecialization) {
80908091
// No previous declaration in the qualifying scope.
80918092
Diag(D.getIdentifierLoc(), diag::err_no_member)
80928093
<< Name << computeDeclContext(D.getCXXScopeSpec(), true)
80938094
<< D.getCXXScopeSpec().getRange();
80948095
NewVD->setInvalidDecl();
80958096
}
80968097

8097-
if (!IsVariableTemplateSpecialization && !IsPlaceholderVariable)
8098+
if (!IsPlaceholderVariable)
80988099
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
80998100

81008101
// CheckVariableDeclaration will set NewVD as invalid if something is in

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4601,9 +4601,9 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
46014601
}
46024602

46034603
DeclResult Sema::ActOnVarTemplateSpecialization(
4604-
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
4605-
TemplateParameterList *TemplateParams, StorageClass SC,
4606-
bool IsPartialSpecialization) {
4604+
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
4605+
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
4606+
StorageClass SC, bool IsPartialSpecialization) {
46074607
// D must be variable template id.
46084608
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
46094609
"Variable template specialization is declared with a template id.");
@@ -4783,17 +4783,12 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
47834783
// Note that this is an explicit specialization.
47844784
Specialization->setSpecializationKind(TSK_ExplicitSpecialization);
47854785

4786-
if (PrevDecl) {
4787-
// Check that this isn't a redefinition of this specialization,
4788-
// merging with previous declarations.
4789-
LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName,
4790-
forRedeclarationInCurContext());
4791-
PrevSpec.addDecl(PrevDecl);
4792-
D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
4793-
} else if (Specialization->isStaticDataMember() &&
4794-
Specialization->isOutOfLine()) {
4786+
Previous.clear();
4787+
if (PrevDecl)
4788+
Previous.addDecl(PrevDecl);
4789+
else if (Specialization->isStaticDataMember() &&
4790+
Specialization->isOutOfLine())
47954791
Specialization->setAccess(VarTemplate->getAccess());
4796-
}
47974792

47984793
return Specialization;
47994794
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
namespace N0 {
4+
template<typename T>
5+
void f0();
6+
7+
template<typename T>
8+
int x0 = 0;
9+
10+
template<typename T>
11+
class C0;
12+
}
13+
using namespace N0;
14+
15+
template<>
16+
void f0<int>(); // expected-error {{no function template matches}}
17+
18+
template<>
19+
int x0<int>;
20+
21+
template<>
22+
class C0<int>;
23+
24+
namespace N1 {
25+
namespace N2 {
26+
template<typename T>
27+
void f2();
28+
29+
template<typename T>
30+
int x2 = 0;
31+
32+
template<typename T>
33+
class C2;
34+
}
35+
using namespace N2;
36+
}
37+
38+
template<>
39+
void N1::f2<int>(); // expected-error {{no function template matches}}
40+
41+
template<>
42+
int N1::x2<int>;
43+
44+
template<>
45+
class N1::C2<int>;
46+
47+
namespace N3 {
48+
namespace N4 {
49+
template<typename T>
50+
void f4();
51+
52+
template<typename T>
53+
int x4 = 0;
54+
55+
template<typename T>
56+
class C4;
57+
}
58+
using N4::f4;
59+
using N4::x4;
60+
using N4::C4;
61+
}
62+
63+
template<>
64+
void N3::f4<int>(); // expected-error {{no function template matches}}
65+
66+
template<>
67+
int N3::x4<int>;
68+
69+
template<>
70+
class N3::C4<int>;
71+
72+
inline namespace N5 {
73+
template<typename T>
74+
void f5();
75+
76+
template<typename T>
77+
int x5 = 0;
78+
79+
template<typename T>
80+
class C5;
81+
}
82+
83+
template<>
84+
void f5<int>();
85+
86+
template<>
87+
int x5<int>;
88+
89+
template<>
90+
class C5<int>;
91+
92+
namespace N6 {
93+
inline namespace N7 {
94+
template<typename T>
95+
void f7();
96+
97+
template<typename T>
98+
int x7 = 0;
99+
100+
template<typename T>
101+
class C7;
102+
}
103+
}
104+
105+
template<>
106+
void N6::f7<int>();
107+
108+
template<>
109+
int N6::x7<int>;
110+
111+
template<>
112+
class N6::C7<int>;

0 commit comments

Comments
 (0)