Index: FixIt/fixit-template-for-dependent-name.cpp =================================================================== --- /dev/null +++ FixIt/fixit-template-for-dependent-name.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template void foo() { + T::bar(); // expected-error {{use 'template' keyword to treat 'bar' as a dependent template name}} + T::baz(); // expected-error {{use 'template' keyword to treat 'baz' as a dependent template name}} +} + +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// CHECK: fix-it:{{.*}}:{4:8-4:8}:"template " +// CHECK: fix-it:{{.*}}:{5:8-5:8}:"template " Index: Parse/ParseTemplate.cpp =================================================================== --- Parse/ParseTemplate.cpp +++ Parse/ParseTemplate.cpp @@ -1247,30 +1247,45 @@ /// template argument list (starting with the '<') and never as a '<' /// expression. bool Parser::IsTemplateArgumentList(unsigned Skip) { - struct AlwaysRevertAction : TentativeParsingAction { - AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } - ~AlwaysRevertAction() { Revert(); } - } Tentative(*this); - - while (Skip) { - ConsumeAnyToken(); - --Skip; + { + RevertingTentativeParsingAction AutoRevertScopeGuard(*this); + + for (; Skip > 0; --Skip) { + ConsumeToken(); + } + + if (!TryConsumeToken(tok::less)) + return false; + + // If the first wannabe template argument consists only of decl specs + // it's a template argument list indeed. + + // See whether we have declaration specifiers, which indicate a type. + while (isCXXDeclarationSpecifier() == TPResult::True) + ConsumeAnyToken(); + + // If we have a '>' or a ',' then this is a template argument list. + if (Tok.isOneOf(tok::greater, tok::comma)) + return true; } - - // '<' + + RevertingTentativeParsingAction AutoRevertScopeGuard(*this); + + for (; Skip > 0; --Skip) { + ConsumeToken(); + } + if (!TryConsumeToken(tok::less)) return false; - // An empty template argument list. - if (Tok.is(tok::greater)) - return true; - - // See whether we have declaration specifiers, which indicate a type. - while (isCXXDeclarationSpecifier() == TPResult::True) - ConsumeAnyToken(); - - // If we have a '>' or a ',' then this is a template argument list. - return Tok.isOneOf(tok::greater, tok::comma); + TemplateArgList ignore; + if (ParseTemplateArgumentList(ignore)) + return false; + + if (!TryConsumeToken(tok::greater)) + return false; + + return true; } /// ParseTemplateArgumentList - Parse a C++ template-argument-list Index: SemaTemplate/dependent-template-recover.cpp =================================================================== --- SemaTemplate/dependent-template-recover.cpp +++ SemaTemplate/dependent-template-recover.cpp @@ -6,6 +6,7 @@ t->f0(); // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}} t->operator+(); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}} + t->operator+<1, U const>(); // expected-error{{use 'template' keyword to treat 'operator +' as a dependent template name}} t->f1(); // expected-error{{use 'template' keyword to treat 'f1' as a dependent template name}} T::getAs(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}}