Skip to content

Commit f46d146

Browse files
evelez7shafik
andauthored
[clang] require template arg list after template kw (#80801)
Require a template argument list after an identifier prefixed by the template keyword. Introduced by [CWG 96](https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#96), but the current wording of [[temp.names]p5](https://eel.is/c++draft/temp.names#6) was introduced in [P1787R6](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1787r6.html), and became [temp.names]p6 somewhere else. Fixes #53095 --------- Co-authored-by: Shafik Yaghmour <shafik.yaghmour@intel.com>
1 parent 458a315 commit f46d146

File tree

10 files changed

+52
-46
lines changed

10 files changed

+52
-46
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ Resolutions to C++ Defect Reports
251251
- P0522 implementation is enabled by default in all language versions, and
252252
provisional wording for CWG2398 is implemented.
253253

254+
- Clang now requires a template argument list after a template keyword.
255+
(`CWG96: Syntactic disambiguation using the template keyword <https://cplusplus.github.io/CWG/issues/96.html>`_).
256+
254257
C Language Changes
255258
------------------
256259

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,10 @@ def err_requires_expr_in_simple_requirement : Error<
887887
"requires expression in requirement body; did "
888888
"you intend to place it in a nested requirement? (add another 'requires' "
889889
"before the expression)">;
890+
def missing_template_arg_list_after_template_kw : Extension<
891+
"a template argument list is expected after a name prefixed by the template "
892+
"keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>,
893+
DefaultError;
890894

891895
def err_missing_dependent_template_keyword : Error<
892896
"use 'template' keyword to treat '%0' as a dependent template name">;

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/AST/DeclTemplate.h"
1515
#include "clang/AST/ExprCXX.h"
1616
#include "clang/Basic/PrettyStackTrace.h"
17+
#include "clang/Basic/TemplateKinds.h"
1718
#include "clang/Basic/TokenKinds.h"
1819
#include "clang/Lex/LiteralSupport.h"
1920
#include "clang/Parse/ParseDiagnostic.h"
@@ -3026,13 +3027,23 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
30263027
SS, ObjectType, ObjectHadErrors,
30273028
TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc,
30283029
EnteringContext, Result, TemplateSpecified);
3029-
else if (TemplateSpecified &&
3030-
Actions.ActOnTemplateName(
3031-
getCurScope(), SS, *TemplateKWLoc, Result, ObjectType,
3032-
EnteringContext, Template,
3033-
/*AllowInjectedClassName*/ true) == TNK_Non_template)
3034-
return true;
30353030

3031+
if (TemplateSpecified) {
3032+
TemplateNameKind TNK =
3033+
Actions.ActOnTemplateName(getCurScope(), SS, *TemplateKWLoc, Result,
3034+
ObjectType, EnteringContext, Template,
3035+
/*AllowInjectedClassName=*/true);
3036+
if (TNK == TNK_Non_template)
3037+
return true;
3038+
3039+
// C++2c [tem.names]p6
3040+
// A name prefixed by the keyword template shall be followed by a template
3041+
// argument list or refer to a class template or an alias template.
3042+
if ((TNK == TNK_Function_template || TNK == TNK_Dependent_template_name ||
3043+
TNK == TNK_Var_template) &&
3044+
!Tok.is(tok::less))
3045+
Diag(IdLoc, diag::missing_template_arg_list_after_template_kw);
3046+
}
30363047
return false;
30373048
}
30383049

clang/test/CXX/drs/cwg0xx.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1404,7 +1404,7 @@ namespace cwg95 { // cwg95: 3.3
14041404
// expected-note@#cwg95-C-f {{implicitly declared private here}}
14051405
}
14061406

1407-
namespace cwg96 { // cwg96: no
1407+
namespace cwg96 { // cwg96: sup P1787
14081408
struct A {
14091409
void f(int);
14101410
template<typename T> int f(T);
@@ -1419,6 +1419,7 @@ namespace cwg96 { // cwg96: no
14191419
// name a class template.
14201420
// FIXME: What about alias templates?
14211421
int k2 = a.template f(1);
1422+
// expected-error@-1 {{a template argument list is expected after a name prefixed by the template keyword}}
14221423
A::template S<int> s;
14231424
B<A::template S> b;
14241425
}

clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,16 +384,16 @@ namespace dependent_static_var_template {
384384
struct A {
385385
template<int = 0> static int n; // expected-note 2{{here}}
386386
};
387-
int &r = A::template n; // expected-error {{use of variable template 'A::template n' requires template arguments}}
387+
int &r = A::template n; // expected-error {{use of variable template 'A::template n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
388388

389389
template<typename T>
390-
int &f() { return T::template n; } // expected-error {{use of variable template 'A::template n' requires template arguments}}
390+
int &f() { return T::template n; } // expected-error {{use of variable template 'A::template n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
391391
int &s = f<A>(); // expected-note {{instantiation of}}
392392

393393
namespace B {
394394
template<int = 0> static int n; // expected-note {{here}}
395395
}
396-
int &t = B::template n; // expected-error {{use of variable template 'B::template n' requires template arguments}}
396+
int &t = B::template n; // expected-error {{use of variable template 'B::template n' requires template arguments}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
397397

398398
struct C {
399399
template <class T> static T G;

clang/test/SemaCXX/template-specialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct B {
1111
template <int i>
1212
static void foo() {
1313
int array[i];
14-
A::template bar(array[0]); // expected-error {{no matching function for call to 'bar'}}
14+
A::template bar(array[0]); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{no matching function for call to 'bar'}}
1515
}
1616
};
1717

clang/test/SemaTemplate/dependent-names.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ template <typename> struct CT2 {
420420
template <typename T> int CT2<int>::X<>; // expected-error {{template parameter list matching the non-templated nested type 'CT2<int>' should be empty}}
421421

422422
namespace DependentTemplateIdWithNoArgs {
423-
template<typename T> void f() { T::template f(); }
423+
template<typename T> void f() { T::template f(); } // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
424424
struct X {
425425
template<int = 0> static void f();
426426
};
@@ -431,7 +431,7 @@ namespace DependentUnresolvedUsingTemplate {
431431
template<typename T>
432432
struct X : T {
433433
using T::foo;
434-
void f() { this->template foo(); } // expected-error {{does not refer to a template}}
434+
void f() { this->template foo(); } // expected-error {{does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
435435
void g() { this->template foo<>(); } // expected-error {{does not refer to a template}}
436436
void h() { this->template foo<int>(); } // expected-error {{does not refer to a template}}
437437
};
@@ -450,7 +450,7 @@ namespace DependentUnresolvedUsingTemplate {
450450
namespace PR37680 {
451451
template <class a> struct b : a {
452452
using a::add;
453-
template<int> int add() { return this->template add(0); }
453+
template<int> int add() { return this->template add(0); } // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
454454
};
455455
struct a {
456456
template<typename T = void> int add(...);

clang/test/SemaTemplate/template-id-expr.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,23 +65,23 @@ struct Y0 {
6565
template<typename U>
6666
void f() {
6767
Y0::template f1<U>(0);
68-
Y0::template f1(0);
69-
this->template f1(0);
68+
Y0::template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
69+
this->template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
7070

7171
Y0::template f2<U>(0);
72-
Y0::template f2(0);
72+
Y0::template f2(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
7373

7474
Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
7575
Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
7676

7777
int x;
7878
x = Y0::f4(0);
7979
x = Y0::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
80-
x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
80+
x = Y0::template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}}
8181

8282
x = this->f4(0);
8383
x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
84-
x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
84+
x = this->template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}}
8585
}
8686
};
8787

@@ -109,23 +109,23 @@ struct Y1 {
109109
template<typename U>
110110
void f() {
111111
Y1::template f1<U>(0);
112-
Y1::template f1(0);
113-
this->template f1(0);
112+
Y1::template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
113+
this->template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
114114

115115
Y1::template f2<U>(0);
116-
Y1::template f2(0);
116+
Y1::template f2(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
117117

118118
Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
119119
Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
120120

121121
int x;
122122
x = Y1::f4(0);
123123
x = Y1::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
124-
x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
124+
x = Y1::template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}}
125125

126126
x = this->f4(0);
127127
x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
128-
x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
128+
x = this->template f4(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}} expected-error {{assigning to 'int' from incompatible type 'void'}}
129129
}
130130
};
131131

@@ -138,23 +138,23 @@ struct Y2 : Y1<T> {
138138
template<typename U>
139139
void f(Y1 *p) {
140140
Y1::template f1<U>(0);
141-
Y1::template f1(0);
142-
p->template f1(0);
141+
Y1::template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
142+
p->template f1(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
143143

144144
Y1::template f2<U>(0);
145-
Y1::template f2(0);
145+
Y1::template f2(0); // expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
146146

147-
Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
148-
Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
147+
Y1::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
148+
Y1::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
149149

150150
int x;
151151
x = Y1::f4(0);
152152
x = Y1::f4<int>(0); // expected-error {{use 'template'}} expected-error {{assigning to 'int' from incompatible type 'void'}}
153-
x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
153+
x = Y1::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
154154

155155
x = p->f4(0);
156156
x = p->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{use 'template'}}
157-
x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
157+
x = p->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
158158
}
159159
};
160160

@@ -169,7 +169,7 @@ struct A {
169169

170170
template<int I>
171171
void f5() {
172-
A::template B<I>::template b1(); // expected-error {{'b1' following the 'template' keyword does not refer to a template}}
172+
A::template B<I>::template b1(); // expected-error {{'b1' following the 'template' keyword does not refer to a template}} expected-error {{a template argument list is expected after a name prefixed by the template keyword}}
173173
}
174174

175175
template void f5<0>(); // expected-note {{in instantiation of function template specialization 'f5<0>' requested here}}

clang/test/SemaTemplate/template-id-printing.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ template <typename T>
9999
void test() {
100100
// CHECK: S<T>::foo;
101101
S<T>::foo;
102-
// CHECK: S<T>::template foo;
103-
S<T>::template foo;
104102
// CHECK: S<T>::template foo<>;
105103
S<T>::template foo<>;
106104
// CHECK: S<T>::template foo<T>;
@@ -121,21 +119,10 @@ void test() {
121119
S<T> s;
122120
// CHECK: s.foo;
123121
s.foo;
124-
// CHECK: s.template foo;
125-
s.template foo;
126122
// CHECK: s.template foo<>;
127123
s.template foo<>;
128124
// CHECK: s.template foo<T>;
129125
s.template foo<T>;
130126
}
131127

132128
} // namespace DSME
133-
134-
namespace DSDRE_withImplicitTemplateArgs {
135-
136-
template <typename T> void foo() {
137-
// CHECK: T::template bar();
138-
T::template bar();
139-
}
140-
141-
} // namespace DSDRE_withImplicitTemplateArgs

clang/www/cxx_dr_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
614614
<td><a href="https://cplusplus.github.io/CWG/issues/96.html">96</a></td>
615615
<td>C++11</td>
616616
<td>Syntactic disambiguation using the <TT>template</TT> keyword</td>
617-
<td class="none" align="center">No</td>
617+
<td class="na" align="center">Superseded by <a href="https://wg21.link/P1787">P1787</a></td>
618618
</tr>
619619
<tr id="97">
620620
<td><a href="https://cplusplus.github.io/CWG/issues/97.html">97</a></td>

0 commit comments

Comments
 (0)