Skip to content

Commit

Permalink
Template Diagnostic Improvements (llvm#99933)
Browse files Browse the repository at this point in the history
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 llvm#17959.
  • Loading branch information
bradenhelmer authored Jul 23, 2024
1 parent 4d5f81c commit ef7d46c
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 16 deletions.
10 changes: 10 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ Attribute Changes in Clang
Improvements to Clang's diagnostics
-----------------------------------

- Some template related diagnostics have been improved.

.. code-block:: c++

void foo() { template <typename> int i; } // error: templates can only be declared in namespace or class scope

struct S {
template <typename> int i; // error: non-static data member 'i' cannot be declared as a template
};

Improvements to Clang's time-trace
----------------------------------

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5168,7 +5168,7 @@ def warn_cxx11_compat_variable_template : Warning<
InGroup<CXXPre14Compat>, DefaultIgnore;
def err_template_variable_noparams : Error<
"extraneous 'template<>' in declaration of variable %0">;
def err_template_member : Error<"member %0 declared as a template">;
def err_template_member : Error<"non-static data member %0 cannot be declared as a template">;
def err_member_with_template_arguments : Error<"member %0 cannot have template arguments">;
def err_template_member_noparams : Error<
"extraneous 'template<>' in declaration of member %0">;
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,15 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
goto Retry;
}

case tok::kw_template: {
SourceLocation DeclEnd;
ParsedAttributes Attrs(AttrFactory);
ParseTemplateDeclarationOrSpecialization(DeclaratorContext::Block, DeclEnd,
Attrs,
getAccessSpecifierIfPresent());
return StmtError();
}

case tok::kw_case: // C99 6.8.1: labeled-statement
return ParseCaseStatement(StmtCtx);
case tok::kw_default: // C99 6.8.1: labeled-statement
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/drs/cwg6xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1265,7 +1265,7 @@ namespace cwg687 { // cwg687 (9 c++20, but the issue is still considered open)

// This is not.
template g<int>(a);
// expected-error@-1 {{expected expression}}
// expected-error@-1 {{expected '<' after 'template'}}
}
}

Expand Down
8 changes: 4 additions & 4 deletions clang/test/CXX/temp/temp.spec/temp.expl.spec/p2-20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct B {
static int y;

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

template<typename T>
static int x<T*>;
Expand All @@ -65,7 +65,7 @@ struct B {
static int y<T*>;

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

template<>
int x<short>;
Expand Down Expand Up @@ -169,7 +169,7 @@ struct D {
static int y;

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

template<typename U>
static int x<U*>;
Expand All @@ -178,7 +178,7 @@ struct D {
static int y<U*>;

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

template<>
int x<short>;
Expand Down
4 changes: 4 additions & 0 deletions clang/test/Parser/cxx-template-decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,7 @@ namespace PR46231 {
template<> int; // expected-error {{declaration does not declare anything}}
template<int> int; // expected-error {{declaration does not declare anything}}
}

namespace PR99933 {
void foo() { template <typename> int i; } // expected-error {{templates can only be declared in namespace or class scope}}
}
16 changes: 8 additions & 8 deletions clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
#endif

class A {
template<typename T> CONST T wrong; // expected-error {{member 'wrong' declared as a template}}
template<typename T> CONST T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}}
template<typename T> CONST T wrong; // expected-error {{non-static data member 'wrong' cannot be declared as a template}}
template<typename T> CONST T wrong_init = 5; // expected-error {{non-static data member 'wrong_init' cannot be declared as a template}}
template<typename T, typename T0> static CONST T right = T(100);
template<typename T> static CONST T right<T,int> = 5;
template<typename T> CONST int right<int,T>; // expected-error {{member 'right' declared as a template}}
template<typename T> CONST float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
template<typename T> CONST int right<int,T>; // expected-error {{non-static data member 'right' cannot be declared as a template}}
template<typename T> CONST float right<float,T> = 5; // expected-error {{non-static data member 'right' cannot be declared as a template}}
#ifdef PRECXX11
// expected-warning@-2 {{in-class initializer for static data member of type 'const float' is a GNU extension}}
#else
Expand Down Expand Up @@ -161,14 +161,14 @@ namespace non_const_init {
#ifndef PRECXX11
namespace constexpred {
class A {
template<typename T> constexpr T wrong; // expected-error {{member 'wrong' declared as a template}}
template<typename T> constexpr T wrong; // expected-error {{non-static data member 'wrong' cannot be declared as a template}}
// expected-error@-1 {{declaration of constexpr static data member 'wrong' requires an initializer}}
template<typename T> constexpr T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}}
template<typename T> constexpr T wrong_init = 5; // expected-error {{non-static data member 'wrong_init' cannot be declared as a template}}
template<typename T, typename T0> static constexpr T right = T(100);
template<typename T> static constexpr T right<T,int> = 5;
template<typename T> constexpr int right<int,T>; // expected-error {{member 'right' declared as a template}}
template<typename T> constexpr int right<int,T>; // expected-error {{non-static data member 'right' cannot be declared as a template}}
// expected-error@-1 {{declaration of constexpr static data member 'right<int, T>' requires an initializer}}
template<typename T> constexpr float right<float,T> = 5; // expected-error {{member 'right' declared as a template}}
template<typename T> constexpr float right<float,T> = 5; // expected-error {{non-static data member 'right' cannot be declared as a template}}
template<> constexpr int right<int,int> = 7;
template<> constexpr float right<float, int>; // expected-error {{declaration of constexpr static data member 'right<float, int>' requires an initializer}}
template static constexpr int right<int,int>; // expected-error {{expected '<' after 'template'}}
Expand Down
6 changes: 6 additions & 0 deletions clang/test/SemaCXX/invalid-template-declaration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
// PR99933

struct S {
template <typename> int i; // expected-error {{non-static data member 'i' cannot be declared as a template}}
};
2 changes: 1 addition & 1 deletion clang/test/SemaTemplate/class-template-decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class X {
};

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

template<typename T> class X1 var; // expected-error {{variable has incomplete type 'class X1'}} \
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaTemplate/nested-template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ namespace PR10896 {
private:

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

Expand Down

0 comments on commit ef7d46c

Please sign in to comment.