From 75af897e99f6b35cf4c97a7388f6387d738e9d5a Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 17 Aug 2018 19:43:40 +0000 Subject: [PATCH] Improve diagnostic for missing comma in template parameter list. Given 'typename T typename U', we would correctly diagnose the missing comma, but incorrectly disambiguate the first parameter as being a non-type parameter and complain that the 'T' is not a qualified-id. See also gcc.gnu.org/PR86998. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@340074 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Parse/ParseTemplate.cpp | 38 ++++++++++++++++++++------------- test/CXX/temp/temp.param/p2.cpp | 9 +++++--- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 063f7ccea3..5af543702c 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -425,7 +425,9 @@ bool Parser::isStartOfTemplateTypeParameter() { } } - if (Tok.isNot(tok::kw_typename)) + // 'typedef' is a reasonably-common typo/thinko for 'typename', and is + // ill-formed otherwise. + if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef)) return false; // C++ [temp.param]p2: @@ -448,6 +450,13 @@ bool Parser::isStartOfTemplateTypeParameter() { case tok::ellipsis: return true; + case tok::kw_typename: + case tok::kw_typedef: + case tok::kw_class: + // These indicate that a comma was missed after a type parameter, not that + // we have found a non-type parameter. + return true; + default: return false; } @@ -469,26 +478,25 @@ bool Parser::isStartOfTemplateTypeParameter() { /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] /// = id-expression NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - if (isStartOfTemplateTypeParameter()) - return ParseTypeParameter(Depth, Position); - - if (Tok.is(tok::kw_template)) - return ParseTemplateTemplateParameter(Depth, Position); + if (isStartOfTemplateTypeParameter()) { + // 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); - // 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"); + Diag(Tok.getLocation(), diag::note_meant_to_use_typename) + << FixItHint::CreateReplacement(CharSourceRange::getCharRange( + Tok.getLocation(), Tok.getEndLoc()), + "typename"); - Tok.setKind(tok::kw_typename); + Tok.setKind(tok::kw_typename); + } return ParseTypeParameter(Depth, Position); } + if (Tok.is(tok::kw_template)) + return ParseTemplateTemplateParameter(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/test/CXX/temp/temp.param/p2.cpp b/test/CXX/temp/temp.param/p2.cpp index 656bd26ff0..c70b1d354f 100644 --- a/test/CXX/temp/temp.param/p2.cpp +++ b/test/CXX/temp/temp.param/p2.cpp @@ -8,14 +8,17 @@ template struct X; template struct X; -// typename followed by aqualified-id denotes the type in a non-type +// typename followed by a qualified-id denotes the type in a non-type // parameter-declaration. template struct Y0; template::type Value> struct Y1; +template struct Y2; // expected-error{{expected ',' or '>'}} +template struct Y3; // expected-error{{expected a qualified name after 'typename'}} expected-error{{expected ',' or '>'}} +template struct Y4; // expected-error{{expected template parameter}} expected-note {{did you mean to use 'typename'?}} expected-error{{expected ',' or '>'}} // 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{{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 Z0; //expected-error{{invalid declaration specifier}} template struct Z1; //expected-error2{{invalid declaration specifier}} template struct Z2; //expected-error{{invalid declaration specifier}} template struct Z3; //expected-error{{invalid declaration specifier}} @@ -43,6 +46,6 @@ template struct Z13; // OK // Make sure that we properly disambiguate non-type template parameters that // start with 'class'. class X1 { }; -template struct Y2 { }; +template struct X2 { }; // FIXME: add the example from p2 -- 2.40.0