Skip to content

Commit ef7d46c

Browse files
authored
Template Diagnostic Improvements (#99933)
It turns out `SemaTemplate` handles this type of diagnostic already, however when template gets encountered, it never gets parsed as a possible statement or declaration, only as an expression. Fixes #17959.
1 parent 4d5f81c commit ef7d46c

File tree

10 files changed

+45
-16
lines changed

10 files changed

+45
-16
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ Attribute Changes in Clang
110110
Improvements to Clang's diagnostics
111111
-----------------------------------
112112

113+
- Some template related diagnostics have been improved.
114+
115+
.. code-block:: c++
116+
117+
void foo() { template <typename> int i; } // error: templates can only be declared in namespace or class scope
118+
119+
struct S {
120+
template <typename> int i; // error: non-static data member 'i' cannot be declared as a template
121+
};
122+
113123
Improvements to Clang's time-trace
114124
----------------------------------
115125

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5168,7 +5168,7 @@ def warn_cxx11_compat_variable_template : Warning<
51685168
InGroup<CXXPre14Compat>, DefaultIgnore;
51695169
def err_template_variable_noparams : Error<
51705170
"extraneous 'template<>' in declaration of variable %0">;
5171-
def err_template_member : Error<"member %0 declared as a template">;
5171+
def err_template_member : Error<"non-static data member %0 cannot be declared as a template">;
51725172
def err_member_with_template_arguments : Error<"member %0 cannot have template arguments">;
51735173
def err_template_member_noparams : Error<
51745174
"extraneous 'template<>' in declaration of member %0">;

clang/lib/Parse/ParseStmt.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,15 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
299299
goto Retry;
300300
}
301301

302+
case tok::kw_template: {
303+
SourceLocation DeclEnd;
304+
ParsedAttributes Attrs(AttrFactory);
305+
ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Block, DeclEnd,
306+
Attrs,
307+
getAccessSpecifierIfPresent());
308+
return StmtError();
309+
}
310+
302311
case tok::kw_case: // C99 6.8.1: labeled-statement
303312
return ParseCaseStatement(StmtCtx);
304313
case tok::kw_default: // C99 6.8.1: labeled-statement

clang/test/CXX/drs/cwg6xx.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ namespace cwg687 { // cwg687 (9 c++20, but the issue is still considered open)
12651265

12661266
// This is not.
12671267
template g<int>(a);
1268-
// expected-error@-1 {{expected expression}}
1268+
// expected-error@-1 {{expected '<' after 'template'}}
12691269
}
12701270
}
12711271

clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-20.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct B {
5656
static int y;
5757

5858
template<typename T>
59-
int z; // expected-error {{member 'z' declared as a template}}
59+
int z; // expected-error {{non-static data member 'z' cannot be declared as a template}}
6060

6161
template<typename T>
6262
static int x<T*>;
@@ -65,7 +65,7 @@ struct B {
6565
static int y<T*>;
6666

6767
template<typename T>
68-
int x<T**>; // expected-error {{member 'x' declared as a template}}
68+
int x<T**>; // expected-error {{non-static data member 'x' cannot be declared as a template}}
6969

7070
template<>
7171
int x<short>;
@@ -169,7 +169,7 @@ struct D {
169169
static int y;
170170

171171
template<typename U>
172-
int z; // expected-error {{member 'z' declared as a template}}
172+
int z; // expected-error {{non-static data member 'z' cannot be declared as a template}}
173173

174174
template<typename U>
175175
static int x<U*>;
@@ -178,7 +178,7 @@ struct D {
178178
static int y<U*>;
179179

180180
template<typename U>
181-
int x<U**>; // expected-error {{member 'x' declared as a template}}
181+
int x<U**>; // expected-error {{non-static data member 'x' cannot be declared as a template}}
182182

183183
template<>
184184
int x<short>;

clang/test/Parser/cxx-template-decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,7 @@ namespace PR46231 {
297297
template<> int; // expected-error {{declaration does not declare anything}}
298298
template<int> int; // expected-error {{declaration does not declare anything}}
299299
}
300+
301+
namespace PR99933 {
302+
void foo() { template <typename> int i; } // expected-error {{templates can only be declared in namespace or class scope}}
303+
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
#endif
1010

1111
class A {
12-
template<typename T> CONST T wrong; // expected-error {{member 'wrong' declared as a template}}
13-
template<typename T> CONST T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}}
12+
template<typename T> CONST T wrong; // expected-error {{non-static data member 'wrong' cannot be declared as a template}}
13+
template<typename T> CONST T wrong_init = 5; // expected-error {{non-static data member 'wrong_init' cannot be declared as a template}}
1414
template<typename T, typename T0> static CONST T right = T(100);
1515
template<typename T> static CONST T right<T,int> = 5;
16-
template<typename T> CONST int right<int,T>; // expected-error {{member 'right' declared as a template}}
17-
template<typename T> CONST float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
16+
template<typename T> CONST int right<int,T>; // expected-error {{non-static data member 'right' cannot be declared as a template}}
17+
template<typename T> CONST float right<float,T> = 5; // expected-error {{non-static data member 'right' cannot be declared as a template}}
1818
#ifdef PRECXX11
1919
// expected-warning@-2 {{in-class initializer for static data member of type 'const float' is a GNU extension}}
2020
#else
@@ -161,14 +161,14 @@ namespace non_const_init {
161161
#ifndef PRECXX11
162162
namespace constexpred {
163163
class A {
164-
template<typename T> constexpr T wrong; // expected-error {{member 'wrong' declared as a template}}
164+
template<typename T> constexpr T wrong; // expected-error {{non-static data member 'wrong' cannot be declared as a template}}
165165
// expected-error@-1 {{declaration of constexpr static data member 'wrong' requires an initializer}}
166-
template<typename T> constexpr T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}}
166+
template<typename T> constexpr T wrong_init = 5; // expected-error {{non-static data member 'wrong_init' cannot be declared as a template}}
167167
template<typename T, typename T0> static constexpr T right = T(100);
168168
template<typename T> static constexpr T right<T,int> = 5;
169-
template<typename T> constexpr int right<int,T>; // expected-error {{member 'right' declared as a template}}
169+
template<typename T> constexpr int right<int,T>; // expected-error {{non-static data member 'right' cannot be declared as a template}}
170170
// expected-error@-1 {{declaration of constexpr static data member 'right<int, T>' requires an initializer}}
171-
template<typename T> constexpr float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
171+
template<typename T> constexpr float right<float,T> = 5; // expected-error {{non-static data member 'right' cannot be declared as a template}}
172172
template<> constexpr int right<int,int> = 7;
173173
template<> constexpr float right<float, int>; // expected-error {{declaration of constexpr static data member 'right<float, int>' requires an initializer}}
174174
template static constexpr int right<int,int>; // expected-error {{expected '<' after 'template'}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %clang_cc1 %s -verify -fsyntax-only
2+
// PR99933
3+
4+
struct S {
5+
template <typename> int i; // expected-error {{non-static data member 'i' cannot be declared as a template}}
6+
};

clang/test/SemaTemplate/class-template-decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class X {
6363
};
6464

6565
void f() {
66-
template<typename T> class X; // expected-error{{expression}}
66+
template<typename T> class X; // expected-error{{templates can only be declared in namespace or class scope}}
6767
}
6868

6969
template<typename T> class X1 var; // expected-error {{variable has incomplete type 'class X1'}} \

clang/test/SemaTemplate/nested-template.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ namespace PR10896 {
132132
private:
133133

134134
template<typename T>
135-
T SomeField; // expected-error {{member 'SomeField' declared as a template}}
135+
T SomeField; // expected-error {{non-static data member 'SomeField' cannot be declared as a template}}
136136
template<> int SomeField2; // expected-error {{extraneous 'template<>' in declaration of variable 'SomeField2'}}
137137
};
138138

0 commit comments

Comments
 (0)