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
This commit is contained in:
Richard Smith 2018-08-17 19:43:40 +00:00
parent c912e867c0
commit 75af897e99
2 changed files with 29 additions and 18 deletions

View File

@ -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 (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);
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
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.

View File

@ -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