forked from OSchip/llvm-project
Restrict fixit for missing 'class' in template template parameters.
Based on Doug's feedback to r153887 this omits the FixIt if the following token isn't syntactically valid for the context. (not a comma, '...', identifier, '>', or '>>') There's a bunch of work to handle the '>>' case, but it makes for a much more pleasant diagnostic in this case. llvm-svn: 154163
This commit is contained in:
parent
2b4aeca74e
commit
cbd8125a6a
|
@ -479,8 +479,8 @@ def err_unknown_template_name : Error<
|
|||
"unknown template name %0">;
|
||||
def err_expected_comma_greater : Error<
|
||||
"expected ',' or '>' in template-parameter-list">;
|
||||
def err_expected_class_on_template_template_param : Error<
|
||||
"template template parameters require 'class' after the argument list">;
|
||||
def err_class_on_template_template_param : Error<
|
||||
"template template parameter requires 'class' after the parameter list">;
|
||||
def err_template_spec_syntax_non_template : Error<
|
||||
"identifier followed by '<' indicates a class template specialization but "
|
||||
"%0 %select{does not refer to a template|refers to a function "
|
||||
|
|
|
@ -312,11 +312,15 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
|
|||
if (Tok.is(tok::greater))
|
||||
RAngleLoc = ConsumeToken();
|
||||
else if (ParseTemplateParameterList(Depth, TemplateParams)) {
|
||||
if (!Tok.is(tok::greater)) {
|
||||
if (Tok.is(tok::greatergreater)) {
|
||||
Tok.setKind(tok::greater);
|
||||
Tok.setLocation(Tok.getLocation().getLocWithOffset(1));
|
||||
} else if (Tok.is(tok::greater))
|
||||
RAngleLoc = ConsumeToken();
|
||||
else {
|
||||
Diag(Tok.getLocation(), diag::err_expected_greater);
|
||||
return true;
|
||||
}
|
||||
RAngleLoc = ConsumeToken();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -339,13 +343,13 @@ Parser::ParseTemplateParameterList(unsigned Depth,
|
|||
} else {
|
||||
// If we failed to parse a template parameter, skip until we find
|
||||
// a comma or closing brace.
|
||||
SkipUntil(tok::comma, tok::greater, true, true);
|
||||
SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
|
||||
}
|
||||
|
||||
// Did we find a comma or the end of the template parmeter list?
|
||||
if (Tok.is(tok::comma)) {
|
||||
ConsumeToken();
|
||||
} else if (Tok.is(tok::greater)) {
|
||||
} else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
|
||||
// Don't consume this... that's done by template parser.
|
||||
break;
|
||||
} else {
|
||||
|
@ -490,7 +494,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
|
|||
ParamName = Tok.getIdentifierInfo();
|
||||
NameLoc = ConsumeToken();
|
||||
} else if (Tok.is(tok::equal) || Tok.is(tok::comma) ||
|
||||
Tok.is(tok::greater)) {
|
||||
Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
|
||||
// Unnamed template parameter. Don't have to do anything here, just
|
||||
// don't consume this token.
|
||||
} else {
|
||||
|
@ -539,15 +543,24 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
|
|||
}
|
||||
|
||||
// Generate a meaningful error if the user forgot to put class before the
|
||||
// identifier, comma, or greater.
|
||||
if (Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct)) {
|
||||
Diag(Tok.getLocation(), diag::err_expected_class_on_template_template_param)
|
||||
<< FixItHint::CreateReplacement(Tok.getLocation(), "class");
|
||||
ConsumeToken();
|
||||
} else if (!Tok.is(tok::kw_class))
|
||||
Diag(Tok.getLocation(), diag::err_expected_class_on_template_template_param)
|
||||
<< FixItHint::CreateInsertion(Tok.getLocation(), "class ");
|
||||
else
|
||||
// identifier, comma, or greater. Provide a fixit if the identifier, comma,
|
||||
// or greater appear immediately or after 'typename' or 'struct'. In the
|
||||
// latter case, replace the keyword with 'class'.
|
||||
if (!Tok.is(tok::kw_class)) {
|
||||
bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct);
|
||||
const Token& Next = Replace ? NextToken() : Tok;
|
||||
if (Next.is(tok::identifier) || Next.is(tok::comma) ||
|
||||
Next.is(tok::greater) || Next.is(tok::greatergreater) ||
|
||||
Next.is(tok::ellipsis))
|
||||
Diag(Tok.getLocation(), diag::err_class_on_template_template_param)
|
||||
<< (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class")
|
||||
: FixItHint::CreateInsertion(Tok.getLocation(), "class "));
|
||||
else
|
||||
Diag(Tok.getLocation(), diag::err_class_on_template_template_param);
|
||||
|
||||
if (Replace)
|
||||
ConsumeToken();
|
||||
} else
|
||||
ConsumeToken();
|
||||
|
||||
// Parse the ellipsis, if given.
|
||||
|
@ -567,7 +580,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
|
|||
if (Tok.is(tok::identifier)) {
|
||||
ParamName = Tok.getIdentifierInfo();
|
||||
NameLoc = ConsumeToken();
|
||||
} else if (Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
|
||||
} else if (Tok.is(tok::equal) || Tok.is(tok::comma) ||
|
||||
Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
|
||||
// Unnamed template parameter. Don't have to do anything here, just
|
||||
// don't consume this token.
|
||||
} else {
|
||||
|
|
|
@ -100,3 +100,7 @@ namespace TestMisplacedEllipsisRecovery {
|
|||
int f = me.f(ifn, kfn);
|
||||
int g = me.g(ifn, kfn);
|
||||
}
|
||||
|
||||
template<template<typename> ...Foo, // expected-error {{template template parameters require 'class' after the parameter list}}
|
||||
template<template<template<typename>>>> // expected-error 3 {{template template parameters require 'class' after the parameter list}}
|
||||
void func();
|
||||
|
|
|
@ -200,7 +200,7 @@ template<class T> typedef Mystery<T>::type getMysteriousThing() { // \
|
|||
return Mystery<T>::get();
|
||||
}
|
||||
|
||||
template<template<typename> Foo, // expected-error {{template template parameters require 'class' after the argument list}}
|
||||
template<typename> typename Bar, // expected-error {{template template parameters require 'class' after the argument list}}
|
||||
template<typename> struct Baz> // expected-error {{template template parameters require 'class' after the argument list}}
|
||||
template<template<typename> Foo, // expected-error {{template template parameters require 'class' after the parameter list}}
|
||||
template<typename> typename Bar, // expected-error {{template template parameters require 'class' after the parameter list}}
|
||||
template<typename> struct Baz> // expected-error {{template template parameters require 'class' after the parameter list}}
|
||||
void func();
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s
|
||||
|
||||
// test that the diagnostics produced by this code do not include fixit hints
|
||||
|
||||
// CHECK-NOT: fix-it:
|
||||
|
||||
template<template<typename> +> void func();
|
|
@ -11,8 +11,8 @@ template < ; // expected-error {{parse error}} \
|
|||
// expected-warning {{declaration does not declare anything}}
|
||||
template <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \
|
||||
// expected-error{{extraneous}}
|
||||
template <template <typename> > struct Err2; // expected-error {{template template parameters require 'class' after the argument list}}
|
||||
template <template <typename> Foo> struct Err3; // expected-error {{template template parameters require 'class' after the argument list}}
|
||||
template <template <typename> > struct Err2; // expected-error {{template template parameters require 'class' after the parameter list}}
|
||||
template <template <typename> Foo> struct Err3; // expected-error {{template template parameters require 'class' after the parameter list}}
|
||||
|
||||
// Template function declarations
|
||||
template <typename T> void foo();
|
||||
|
|
Loading…
Reference in New Issue