From 3a98e51823beaefa63016814c8e92e46a31599fc Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Thu, 8 Feb 2018 14:37:58 +0000 Subject: [PATCH] [Parser][FixIt] Better diagnostics for "typedef" instead of "typename" typo rdar://problem/10214588 Differential Revision: https://reviews.llvm.org/D42170 llvm-svn: 324607 --- .../clang/Basic/DiagnosticParseKinds.td | 3 ++ clang/lib/Parse/ParseTemplate.cpp | 14 ++++++++++ clang/test/CXX/temp/temp.param/p2.cpp | 28 +++++++++---------- ...fixit-typedef-instead-of-typename-typo.cpp | 16 +++++++++++ 4 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 clang/test/FixIt/fixit-typedef-instead-of-typename-typo.cpp diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 620adc80bc03..80644a7de0d1 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 611c0779b160..463673167194 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 20e0b8ef35f8..656bd26ff08d 100644 --- a/clang/test/CXX/temp/temp.param/p2.cpp +++ b/clang/test/CXX/temp/temp.param/p2.cpp @@ -15,29 +15,29 @@ template::type Value> struct Y1; // A storage class shall not be specified in a template-parameter declaration. template struct Z; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error2{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} +template 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 struct Z1; //expected-error2{{invalid declaration specifier}} +template struct Z2; //expected-error{{invalid declaration specifier}} +template struct Z3; //expected-error{{invalid declaration specifier}} +template struct Z4; //expected-error{{invalid declaration specifier}} +template struct Z5; //expected-error{{invalid declaration specifier}} +template struct Z6; //expected-error{{invalid declaration specifier}} +template struct Z7; //expected-error{{invalid declaration specifier}} +template struct Z8; //expected-error{{invalid declaration specifier}} -template struct Z0; // OK -template struct Z0; // OK +template struct Z9; // OK +template struct Z10; // OK #ifdef CPP11 -template struct Z0; //expected-error{{invalid declaration specifier}} -template struct Z0; //expected-error{{invalid declaration specifier}} +template struct Z11; //expected-error{{invalid declaration specifier}} +template struct Z12; //expected-error{{invalid declaration specifier}} #endif #ifdef CPP17 -template struct Z1; // OK +template 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 000000000000..9a6f116664a4 --- /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 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"