Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -1209,20 +1209,19 @@ ExprArg.get(), Loc); } -/// \brief Determine whether the current tokens can only be parsed as a -/// template argument list (starting with the '<') and never as a '<' -/// expression. +/// \brief Determine whether the current tokens (starting with the '<') can be +/// parsed as a template argument list bool Parser::IsTemplateArgumentList(unsigned Skip) { struct AlwaysRevertAction : TentativeParsingAction { AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } ~AlwaysRevertAction() { Revert(); } } Tentative(*this); - + while (Skip) { ConsumeToken(); --Skip; } - + // '<' if (!TryConsumeToken(tok::less)) return false; @@ -1230,13 +1229,15 @@ // 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) - ConsumeToken(); - - // If we have a '>' or a ',' then this is a template argument list. - return Tok.isOneOf(tok::greater, tok::comma); + + SuppressAllDiagnostics S(Diags); + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + TemplateArgList TemplateArgs; + if (ParseTemplateArgumentList(TemplateArgs)) + return false; + + // Closing '>' + return Tok.is(tok::greater); } /// ParseTemplateArgumentList - Parse a C++ template-argument-list Index: lib/Parse/RAIIObjectsForParser.h =================================================================== --- lib/Parse/RAIIObjectsForParser.h +++ lib/Parse/RAIIObjectsForParser.h @@ -442,6 +442,18 @@ void skipToEnd(); }; + /// \brief RAII object that suppresses all diagnostics + class SuppressAllDiagnostics { + DiagnosticsEngine &Diags; + bool OldVal; + public: + SuppressAllDiagnostics(DiagnosticsEngine &Diags) : Diags(Diags) { + OldVal = Diags.getSuppressAllDiagnostics(); + Diags.setSuppressAllDiagnostics(true); + } + ~SuppressAllDiagnostics() { Diags.setSuppressAllDiagnostics(OldVal); } + }; + } // end namespace clang #endif Index: test/SemaTemplate/dependent-template-recover.cpp =================================================================== --- test/SemaTemplate/dependent-template-recover.cpp +++ test/SemaTemplate/dependent-template-recover.cpp @@ -11,12 +11,35 @@ T::getAs(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}} t->T::getAs(); // expected-error{{use 'template' keyword to treat 'getAs' as a dependent template name}} - // FIXME: We can't recover from these yet - (*t).f2(); // expected-error{{expected expression}} - (*t).f2<0>(); // expected-error{{expected expression}} + (*t).f2(); // expected-error{{use 'template' keyword to treat 'f2' as a dependent template name}} + (*t).f2<0>(); // expected-error{{use 'template' keyword to treat 'f2' as a dependent template name}} } }; +namespace PR13566 { +template +struct S +{ + template + void foo(); + + template + void foo(int); +}; + +template +void bar() +{ + S s; + s.foo<1>(); // expected-error{{use 'template' keyword to treat 'foo' as a dependent template name}} + s.foo<1>(0); // expected-error{{use 'template' keyword to treat 'foo' as a dependent template name}} +} + +void instantiate() { + bar(); +} +} + namespace PR9401 { // From GCC PR c++/45558 template