summaryrefslogtreecommitdiffstats
path: root/clang/lib/Parse/ParseTentative.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2018-09-28 18:44:09 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2018-09-28 18:44:09 +0000
commit8baa50013c86c34a58d8327c5d1a043898b86398 (patch)
treec3e17acda6afd5e69242ee9dd6d330796f1c3670 /clang/lib/Parse/ParseTentative.cpp
parent8e90bad63d3a448ed680616b393a47d25280fd87 (diff)
downloadbcm5719-llvm-8baa50013c86c34a58d8327c5d1a043898b86398.tar.gz
bcm5719-llvm-8baa50013c86c34a58d8327c5d1a043898b86398.zip
[cxx2a] P0614R1: Support init-statements in range-based for loops.
We don't yet support this for the case where a range-based for loop is implicitly rewritten to an ObjC for..in statement. llvm-svn: 343350
Diffstat (limited to 'clang/lib/Parse/ParseTentative.cpp')
-rw-r--r--clang/lib/Parse/ParseTentative.cpp85
1 files changed, 69 insertions, 16 deletions
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index dfd1f8c3b2e..2b5e266104c 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -345,22 +345,55 @@ struct Parser::ConditionDeclarationOrInitStatementState {
bool CanBeExpression = true;
bool CanBeCondition = true;
bool CanBeInitStatement;
+ bool CanBeForRangeDecl;
- ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement)
- : P(P), CanBeInitStatement(CanBeInitStatement) {}
+ ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement,
+ bool CanBeForRangeDecl)
+ : P(P), CanBeInitStatement(CanBeInitStatement),
+ CanBeForRangeDecl(CanBeForRangeDecl) {}
+
+ bool resolved() {
+ return CanBeExpression + CanBeCondition + CanBeInitStatement +
+ CanBeForRangeDecl < 2;
+ }
void markNotExpression() {
CanBeExpression = false;
- if (CanBeCondition && CanBeInitStatement) {
+ if (!resolved()) {
// FIXME: Unify the parsing codepaths for condition variables and
// simple-declarations so that we don't need to eagerly figure out which
// kind we have here. (Just parse init-declarators until we reach a
// semicolon or right paren.)
RevertingTentativeParsingAction PA(P);
- P.SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
+ if (CanBeForRangeDecl) {
+ // Skip until we hit a ')', ';', or a ':' with no matching '?'.
+ // The final case is a for range declaration, the rest are not.
+ while (true) {
+ unsigned QuestionColonDepth = 0;
+ P.SkipUntil({tok::r_paren, tok::semi, tok::question, tok::colon},
+ StopBeforeMatch);
+ if (P.Tok.is(tok::question))
+ ++QuestionColonDepth;
+ else if (P.Tok.is(tok::colon)) {
+ if (QuestionColonDepth)
+ --QuestionColonDepth;
+ else {
+ CanBeCondition = CanBeInitStatement = false;
+ return;
+ }
+ } else {
+ CanBeForRangeDecl = false;
+ break;
+ }
+ P.ConsumeToken();
+ }
+ } else {
+ // Just skip until we hit a ')' or ';'.
+ P.SkipUntil(tok::r_paren, tok::semi, StopBeforeMatch);
+ }
if (P.Tok.isNot(tok::r_paren))
- CanBeCondition = false;
+ CanBeCondition = CanBeForRangeDecl = false;
if (P.Tok.isNot(tok::semi))
CanBeInitStatement = false;
}
@@ -368,28 +401,36 @@ struct Parser::ConditionDeclarationOrInitStatementState {
bool markNotCondition() {
CanBeCondition = false;
- return !CanBeInitStatement || !CanBeExpression;
+ return resolved();
+ }
+
+ bool markNotForRangeDecl() {
+ CanBeForRangeDecl = false;
+ return resolved();
}
bool update(TPResult IsDecl) {
switch (IsDecl) {
case TPResult::True:
markNotExpression();
- return true;
+ assert(resolved() && "can't continue after tentative parsing bails out");
+ break;
case TPResult::False:
- CanBeCondition = CanBeInitStatement = false;
- return true;
+ CanBeCondition = CanBeInitStatement = CanBeForRangeDecl = false;
+ break;
case TPResult::Ambiguous:
- return false;
+ break;
case TPResult::Error:
- CanBeExpression = CanBeCondition = CanBeInitStatement = false;
- return true;
+ CanBeExpression = CanBeCondition = CanBeInitStatement =
+ CanBeForRangeDecl = false;
+ break;
}
- llvm_unreachable("unknown tentative parse result");
+ return resolved();
}
ConditionOrInitStatement result() const {
- assert(CanBeExpression + CanBeCondition + CanBeInitStatement < 2 &&
+ assert(CanBeExpression + CanBeCondition + CanBeInitStatement +
+ CanBeForRangeDecl < 2 &&
"result called but not yet resolved");
if (CanBeExpression)
return ConditionOrInitStatement::Expression;
@@ -397,6 +438,8 @@ struct Parser::ConditionDeclarationOrInitStatementState {
return ConditionOrInitStatement::ConditionDecl;
if (CanBeInitStatement)
return ConditionOrInitStatement::InitStmtDecl;
+ if (CanBeForRangeDecl)
+ return ConditionOrInitStatement::ForRangeDecl;
return ConditionOrInitStatement::Error;
}
};
@@ -419,8 +462,10 @@ struct Parser::ConditionDeclarationOrInitStatementState {
/// to the ';' to disambiguate cases like 'int(x))' (an expression) from
/// 'int(x);' (a simple-declaration in an init-statement).
Parser::ConditionOrInitStatement
-Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement) {
- ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement);
+Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement,
+ bool CanBeForRangeDecl) {
+ ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement,
+ CanBeForRangeDecl);
if (State.update(isCXXDeclarationSpecifier()))
return State.result();
@@ -447,11 +492,19 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement) {
return State.result();
}
+ // A colon here identifies a for-range declaration.
+ if (State.CanBeForRangeDecl && Tok.is(tok::colon))
+ return ConditionOrInitStatement::ForRangeDecl;
+
// At this point, it can't be a condition any more, because a condition
// must have a brace-or-equal-initializer.
if (State.markNotCondition())
return State.result();
+ // Likewise, it can't be a for-range declaration any more.
+ if (State.markNotForRangeDecl())
+ return State.result();
+
// A parenthesized initializer could be part of an expression or a
// simple-declaration.
if (Tok.is(tok::l_paren)) {
OpenPOWER on IntegriCloud