aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseTentative.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-15 23:36:14 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-15 23:36:14 +0000
commitbeda951d788a0041e9f5fabbb4e018e8b9d0a2d3 (patch)
treecd27c014a19a93329a6207c23dbda65623c43fb2 /clang/lib/Parse/ParseTentative.cpp
parent7684d05d95b9369fa0454b525093ed04ee91b1e1 (diff)
downloadllvm-beda951d788a0041e9f5fabbb4e018e8b9d0a2d3.zip
llvm-beda951d788a0041e9f5fabbb4e018e8b9d0a2d3.tar.gz
llvm-beda951d788a0041e9f5fabbb4e018e8b9d0a2d3.tar.bz2
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
Diffstat (limited to 'clang/lib/Parse/ParseTentative.cpp')
-rw-r--r--clang/lib/Parse/ParseTentative.cpp50
1 files changed, 24 insertions, 26 deletions
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 @@ Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) {
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;
-
- // 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;
+ if (isCXXDeclarationSpecifier(TPResult::False,
+ &InvalidAsTemplateArgumentList) ==
+ TPResult::True)
+ return TPResult::True;
+ if (InvalidAsTemplateArgumentList)
+ return TPResult::False;
- case tok::greater:
- case tok::greatergreater:
- case tok::greatergreatergreater:
- if (InvalidAsTemplateArgumentList)
- return TPResult::False;
- return TPResult::Ambiguous;
+ // 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.
- 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;
}