From: David Blaikie Date: Fri, 6 Apr 2012 05:26:43 +0000 (+0000) Subject: Restrict fixit for missing 'class' in template template parameters. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9df1b963a69dc85a271b3791267e994485e0bfe1;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154163 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 87de39fb36..33657a1553 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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 " diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 91a9d723a6..b7cc862b4d 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -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 { diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp index dfc5c8c561..9e1f737742 100644 --- a/test/FixIt/fixit-cxx0x.cpp +++ b/test/FixIt/fixit-cxx0x.cpp @@ -100,3 +100,7 @@ namespace TestMisplacedEllipsisRecovery { int f = me.f(ifn, kfn); int g = me.g(ifn, kfn); } + +template ...Foo, // expected-error {{template template parameters require 'class' after the parameter list}} + template>>> // expected-error 3 {{template template parameters require 'class' after the parameter list}} +void func(); diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp index c61902d028..e6701ada04 100644 --- a/test/FixIt/fixit.cpp +++ b/test/FixIt/fixit.cpp @@ -200,7 +200,7 @@ template typedef Mystery::type getMysteriousThing() { // \ return Mystery::get(); } -template Foo, // expected-error {{template template parameters require 'class' after the argument list}} - template typename Bar, // expected-error {{template template parameters require 'class' after the argument list}} - template struct Baz> // expected-error {{template template parameters require 'class' after the argument list}} +template Foo, // expected-error {{template template parameters require 'class' after the parameter list}} + template typename Bar, // expected-error {{template template parameters require 'class' after the parameter list}} + template struct Baz> // expected-error {{template template parameters require 'class' after the parameter list}} void func(); diff --git a/test/FixIt/no-fixit.cpp b/test/FixIt/no-fixit.cpp new file mode 100644 index 0000000000..c95c8670d6 --- /dev/null +++ b/test/FixIt/no-fixit.cpp @@ -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 +> void func(); diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp index af3eb2ded5..21ff21b016 100644 --- a/test/Parser/cxx-template-decl.cpp +++ b/test/Parser/cxx-template-decl.cpp @@ -11,8 +11,8 @@ template < ; // expected-error {{parse error}} \ // expected-warning {{declaration does not declare anything}} template