mirror of https://github.com/microsoft/clang.git
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:
parent
c912e867c0
commit
75af897e99
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue