diff options
Diffstat (limited to 'lib/Parse/ParseTentative.cpp')
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 105 |
1 files changed, 79 insertions, 26 deletions
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index dfd1f8c3b2e68..de39e0675fdb8 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -159,7 +159,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { ConsumeToken(); break; } - // Fall through. + LLVM_FALLTHROUGH; case tok::kw_typeof: case tok::kw___attribute: case tok::kw___underlying_type: { @@ -219,11 +219,11 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { case tok::annot_cxxscope: ConsumeAnnotationToken(); - // Fall through. + LLVM_FALLTHROUGH; default: ConsumeAnyToken(); - if (getLangOpts().ObjC1 && Tok.is(tok::less)) + if (getLangOpts().ObjC && Tok.is(tok::less)) return TryParseProtocolQualifiers(); break; } @@ -345,22 +345,55 @@ struct Parser::ConditionDeclarationOrInitStatementState { bool CanBeExpression = true; bool CanBeCondition = true; bool CanBeInitStatement; + bool CanBeForRangeDecl; + + ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement, + bool CanBeForRangeDecl) + : P(P), CanBeInitStatement(CanBeInitStatement), + CanBeForRangeDecl(CanBeForRangeDecl) {} - ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement) - : P(P), CanBeInitStatement(CanBeInitStatement) {} + 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)) { @@ -596,7 +649,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, return CAK_NotAttributeSpecifier; // No tentative parsing if we don't need to look for ']]' or a lambda. - if (!Disambiguate && !getLangOpts().ObjC1) + if (!Disambiguate && !getLangOpts().ObjC) return CAK_AttributeSpecifier; RevertingTentativeParsingAction PA(*this); @@ -605,7 +658,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, ConsumeBracket(); // Outside Obj-C++11, treat anything with a matching ']]' as an attribute. - if (!getLangOpts().ObjC1) { + if (!getLangOpts().ObjC) { ConsumeBracket(); bool IsAttribute = SkipUntil(tok::r_square); @@ -1107,8 +1160,8 @@ public: // Reject any candidate that only resolves to instance members since they // aren't viable as standalone identifiers instead of member references. if (Candidate.isResolved() && !Candidate.isKeyword() && - std::all_of(Candidate.begin(), Candidate.end(), - [](NamedDecl *ND) { return ND->isCXXInstanceMember(); })) + llvm::all_of(Candidate, + [](NamedDecl *ND) { return ND->isCXXInstanceMember(); })) return false; return CorrectionCandidateCallback::ValidateCandidate(Candidate); @@ -1233,7 +1286,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, const Token &Next = NextToken(); // In 'foo bar', 'foo' is always a type name outside of Objective-C. - if (!getLangOpts().ObjC1 && Next.is(tok::identifier)) + if (!getLangOpts().ObjC && Next.is(tok::identifier)) return TPResult::True; if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) { @@ -1299,8 +1352,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, if (Next.isOneOf(tok::kw_new, // ::new tok::kw_delete)) // ::delete return TPResult::False; + LLVM_FALLTHROUGH; } - // Fall through. case tok::kw___super: case tok::kw_decltype: // Annotate typenames and C++ scope specifiers. If we get one, just @@ -1506,7 +1559,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::annot_typename: case_typename: // In Objective-C, we might have a protocol-qualified type. - if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { + if (getLangOpts().ObjC && NextToken().is(tok::less)) { // Tentatively parse the protocol qualifiers. RevertingTentativeParsingAction PA(*this); ConsumeAnyToken(); // The type token |