Make tentative parsing to detect template-argument-lists less aggressive
(and less wrong).
It's not correct to assume that X<something, Type> is always a
template-id; there are a few cases where the comma takes us into a
non-expression syntactic context in which 'Type' might be permissible.
Stop doing that.
This slightly regresses our error recovery on the cases where the
construct is intended to be a template-id. We typically do still manage
to diagnose a missing 'template' keyword, but we realize this too late
to properly recover from the error.
This fixes a regression introduced by r360308.
llvm-svn: 360827
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 2d2705d..4393326 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -2065,33 +2065,31 @@
if (!TryConsumeToken(tok::less))
return TPResult::False;
+ // We can't do much to tell an expression apart from a template-argument,
+ // but one good distinguishing factor is that a "decl-specifier" not
+ // followed by '(' or '{' can't appear in an expression.
bool InvalidAsTemplateArgumentList = false;
- while (true) {
- // We can't do much to tell an expression apart from a template-argument,
- // but one good distinguishing factor is that a "decl-specifier" not
- // followed by '(' or '{' can't appear in an expression.
- if (isCXXDeclarationSpecifier(
- TPResult::False, &InvalidAsTemplateArgumentList) == TPResult::True)
- return TPResult::True;
+ if (isCXXDeclarationSpecifier(TPResult::False,
+ &InvalidAsTemplateArgumentList) ==
+ TPResult::True)
+ return TPResult::True;
+ if (InvalidAsTemplateArgumentList)
+ return TPResult::False;
- // That didn't help, try the next template-argument.
- SkipUntil({tok::comma, tok::greater, tok::greatergreater,
- tok::greatergreatergreater},
- StopAtSemi | StopBeforeMatch);
- switch (Tok.getKind()) {
- case tok::comma:
- ConsumeToken();
- break;
+ // FIXME: In many contexts, X<thing1, Type> can only be a
+ // template-argument-list. But that's not true in general:
+ //
+ // using b = int;
+ // void f() {
+ // int a = A<B, b, c = C>D; // OK, declares b, not a template-id.
+ //
+ // X<Y<0, int> // ', int>' might be end of X's template argument list
+ //
+ // We might be able to disambiguate a few more cases if we're careful.
- case tok::greater:
- case tok::greatergreater:
- case tok::greatergreatergreater:
- if (InvalidAsTemplateArgumentList)
- return TPResult::False;
- return TPResult::Ambiguous;
-
- default:
- return TPResult::False;
- }
- }
+ // A template-argument-list must be terminated by a '>'.
+ if (SkipUntil({tok::greater, tok::greatergreater, tok::greatergreatergreater},
+ StopAtSemi | StopBeforeMatch))
+ return TPResult::Ambiguous;
+ return TPResult::False;
}