Author: rsmith Date: Fri Aug 17 12:43:40 2018 New Revision: 340074 URL: http://llvm.org/viewvc/llvm-project?rev=340074&view=rev Log: 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. Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp cfe/trunk/test/CXX/temp/temp.param/p2.cpp Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=340074&r1=340073&r2=340074&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseTemplate.cpp (original) +++ cfe/trunk/lib/Parse/ParseTemplate.cpp Fri Aug 17 12:43:40 2018 @@ -425,7 +425,9 @@ bool Parser::isStartOfTemplateTypeParame } } - 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::isStartOfTemplateTypeParame 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::isStartOfTemplateTypeParame /// '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); + + Diag(Tok.getLocation(), diag::note_meant_to_use_typename) + << FixItHint::CreateReplacement(CharSourceRange::getCharRange( + Tok.getLocation(), Tok.getEndLoc()), + "typename"); - // 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); + 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. Modified: cfe/trunk/test/CXX/temp/temp.param/p2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p2.cpp?rev=340074&r1=340073&r2=340074&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.param/p2.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.param/p2.cpp Fri Aug 17 12:43:40 2018 @@ -8,14 +8,17 @@ template<class T> struct X; template<typename T> 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<typename T, typename T::type Value> struct Y0; template<typename T, typename X<T>::type Value> struct Y1; +template<typename T typename U> struct Y2; // expected-error{{expected ',' or '>'}} +template<typename T U> struct Y3; // expected-error{{expected a qualified name after 'typename'}} expected-error{{expected ',' or '>'}} +template<typedef T typename U> 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<static int Value> struct Z; //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<typedef int Value> struct Z0; //expected-error{{invalid declaration specifier}} 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}} @@ -43,6 +46,6 @@ template<auto> struct Z13; // OK // Make sure that we properly disambiguate non-type template parameters that // start with 'class'. class X1 { }; -template<class X1 *xptr> struct Y2 { }; +template<class X1 *xptr> struct X2 { }; // FIXME: add the example from p2 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits