diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-09-28 18:44:09 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-09-28 18:44:09 +0000 |
commit | 8baa50013c86c34a58d8327c5d1a043898b86398 (patch) | |
tree | c3e17acda6afd5e69242ee9dd6d330796f1c3670 /clang/lib/Parse/ParseTentative.cpp | |
parent | 8e90bad63d3a448ed680616b393a47d25280fd87 (diff) | |
download | bcm5719-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.cpp | 85 |
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)) { |