diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-15 23:36:14 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-15 23:36:14 +0000 |
commit | beda951d788a0041e9f5fabbb4e018e8b9d0a2d3 (patch) | |
tree | cd27c014a19a93329a6207c23dbda65623c43fb2 /clang/lib/Parse/ParseTentative.cpp | |
parent | 7684d05d95b9369fa0454b525093ed04ee91b1e1 (diff) | |
download | llvm-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.cpp | 50 |
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; } |