diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 14 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.param/p2.cpp | 28 | ||||
-rw-r--r-- | clang/test/FixIt/fixit-typedef-instead-of-typename-typo.cpp | 16 |
4 files changed, 47 insertions, 14 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 620adc80bc0..80644a7de0d 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1162,6 +1162,9 @@ def err_objc_parameterized_implementation : Error< def err_objc_type_args_after_protocols : Error< "protocol qualifiers must precede type arguments">; + +def note_meant_to_use_typename : Note< + "did you mean to use 'typename'?">; } let CategoryName = "Coroutines Issue" in { diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 611c0779b16..46367316719 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -488,6 +488,20 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); + // Is there just a typo in the input code? ('typedef' instead of 'typename') + if (Tok.is(tok::kw_typedef)) { + Diag(Tok.getLocation(), diag::err_expected_template_parameter); + + Diag(Tok.getLocation(), diag::note_meant_to_use_typename) + << FixItHint::CreateReplacement(CharSourceRange::getCharRange( + Tok.getLocation(), Tok.getEndLoc()), + "typename"); + + Tok.setKind(tok::kw_typename); + + return ParseTypeParameter(Depth, Position); + } + // If it's none of the above, then it must be a parameter declaration. // NOTE: This will pick up errors in the closure of the template parameter // list (e.g., template < ; Check here to implement >> style closures. diff --git a/clang/test/CXX/temp/temp.param/p2.cpp b/clang/test/CXX/temp/temp.param/p2.cpp index 20e0b8ef35f..656bd26ff08 100644 --- a/clang/test/CXX/temp/temp.param/p2.cpp +++ b/clang/test/CXX/temp/temp.param/p2.cpp @@ -15,29 +15,29 @@ template<typename T, typename X<T>::type Value> struct Y1; // A storage class shall not be specified in a template-parameter declaration. template<static int Value> struct Z; //expected-error{{invalid declaration specifier}} -template<typedef int Value> struct Z0; //expected-error{{invalid declaration specifier}} -template<extern inline int Value> struct Z0; //expected-error2{{invalid declaration specifier}} -template<virtual int Value> struct Z0; //expected-error{{invalid declaration specifier}} -template<explicit int Value> struct Z0; //expected-error{{invalid declaration specifier}} -template<inline int Value> struct Z0; //expected-error{{invalid declaration specifier}} -template<extern int> struct Z0; //expected-error{{invalid declaration specifier}} -template<static int> struct Z0; //expected-error{{invalid declaration specifier}} -template<explicit int Value> struct Z0; //expected-error{{invalid declaration specifier}} -template<mutable int> struct Z0; //expected-error{{invalid declaration specifier}} +template<typedef int Value> struct Z0; //expected-error{{expected template parameter}} expected-error{{expected identifier}} expected-error{{extraneous 'template<>' in declaration of struct 'Z0'}} expected-note{{did you mean to use 'typename'?}} +template<extern inline int Value> struct Z1; //expected-error2{{invalid declaration specifier}} +template<virtual int Value> struct Z2; //expected-error{{invalid declaration specifier}} +template<explicit int Value> struct Z3; //expected-error{{invalid declaration specifier}} +template<inline int Value> struct Z4; //expected-error{{invalid declaration specifier}} +template<extern int> struct Z5; //expected-error{{invalid declaration specifier}} +template<static int> struct Z6; //expected-error{{invalid declaration specifier}} +template<explicit int Value> struct Z7; //expected-error{{invalid declaration specifier}} +template<mutable int> struct Z8; //expected-error{{invalid declaration specifier}} -template<const int> struct Z0; // OK -template<volatile int> struct Z0; // OK +template<const int> struct Z9; // OK +template<volatile int> struct Z10; // OK #ifdef CPP11 -template<thread_local int> struct Z0; //expected-error{{invalid declaration specifier}} -template<constexpr int> struct Z0; //expected-error{{invalid declaration specifier}} +template<thread_local int> struct Z11; //expected-error{{invalid declaration specifier}} +template<constexpr int> struct Z12; //expected-error{{invalid declaration specifier}} #endif #ifdef CPP17 -template<auto> struct Z1; // OK +template<auto> struct Z13; // OK #endif // Make sure that we properly disambiguate non-type template parameters that diff --git a/clang/test/FixIt/fixit-typedef-instead-of-typename-typo.cpp b/clang/test/FixIt/fixit-typedef-instead-of-typename-typo.cpp new file mode 100644 index 00000000000..9a6f116664a --- /dev/null +++ b/clang/test/FixIt/fixit-typedef-instead-of-typename-typo.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template <typename A, typedef B> struct Foo { + // expected-error@-1 {{expected template parameter}} expected-note@-1 {{did you mean to use 'typename'?}} + + // Check that we are speculatively (with fixit applied) trying to parse the rest. + + // Should not produce error about type since parsing speculatively with fixit applied. + B member; + + a // expected-error {{unknown type name 'a'}} // expected-error@+1 {{expected member name or ';' after declaration specifiers}} +}; + + +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// CHECK: fix-it:{{.*}}:{3:23-3:30}:"typename" |