diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
commit | 2b6b257f4e5503a7a2675bdb8735693db769f75c (patch) | |
tree | e85e046ae7003fe3bcc8b5454cd0fa3f7407b470 /lib/Parse/ParseTentative.cpp | |
parent | b4348ed0b7e90c0831b925fbee00b5f179a99796 (diff) | |
download | src-2b6b257f4e5503a7a2675bdb8735693db769f75c.tar.gz src-2b6b257f4e5503a7a2675bdb8735693db769f75c.zip |
Vendor import of clang release_39 branch r276489:vendor/clang/clang-release_39-r276489
Notes
Notes:
svn path=/vendor/clang/dist/; revision=303233
svn path=/vendor/clang/clang-release_39-r276489/; revision=303234; tag=vendor/clang/clang-release_39-r276489
Diffstat (limited to 'lib/Parse/ParseTentative.cpp')
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 193 |
1 files changed, 131 insertions, 62 deletions
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 6fbcfd9bd217..7703c33b8780 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -125,10 +125,11 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { // Ok, we have a simple-type-specifier/typename-specifier followed by a '(', // or an identifier which doesn't resolve as anything. We need tentative // parsing... - - TentativeParsingAction PA(*this); - TPR = TryParseSimpleDeclaration(AllowForRangeDecl); - PA.Revert(); + + { + RevertingTentativeParsingAction PA(*this); + TPR = TryParseSimpleDeclaration(AllowForRangeDecl); + } // In case of an error, let the declaration parsing code handle it. if (TPR == TPResult::Error) @@ -329,10 +330,70 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { return TPResult::Ambiguous; } -/// isCXXConditionDeclaration - Disambiguates between a declaration or an -/// expression for a condition of a if/switch/while/for statement. -/// If during the disambiguation process a parsing error is encountered, -/// the function returns true to let the declaration parsing code handle it. +struct Parser::ConditionDeclarationOrInitStatementState { + Parser &P; + bool CanBeExpression = true; + bool CanBeCondition = true; + bool CanBeInitStatement; + + ConditionDeclarationOrInitStatementState(Parser &P, bool CanBeInitStatement) + : P(P), CanBeInitStatement(CanBeInitStatement) {} + + void markNotExpression() { + CanBeExpression = false; + + if (CanBeCondition && CanBeInitStatement) { + // 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 (P.Tok.isNot(tok::r_paren)) + CanBeCondition = false; + if (P.Tok.isNot(tok::semi)) + CanBeInitStatement = false; + } + } + + bool markNotCondition() { + CanBeCondition = false; + return !CanBeInitStatement || !CanBeExpression; + } + + bool update(TPResult IsDecl) { + switch (IsDecl) { + case TPResult::True: + markNotExpression(); + return true; + case TPResult::False: + CanBeCondition = CanBeInitStatement = false; + return true; + case TPResult::Ambiguous: + return false; + case TPResult::Error: + CanBeExpression = CanBeCondition = CanBeInitStatement = false; + return true; + } + llvm_unreachable("unknown tentative parse result"); + } + + ConditionOrInitStatement result() const { + assert(CanBeExpression + CanBeCondition + CanBeInitStatement < 2 && + "result called but not yet resolved"); + if (CanBeExpression) + return ConditionOrInitStatement::Expression; + if (CanBeCondition) + return ConditionOrInitStatement::ConditionDecl; + if (CanBeInitStatement) + return ConditionOrInitStatement::InitStmtDecl; + return ConditionOrInitStatement::Error; + } +}; + +/// \brief Disambiguates between a declaration in a condition, a +/// simple-declaration in an init-statement, and an expression for +/// a condition of a if/switch statement. /// /// condition: /// expression @@ -341,47 +402,64 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { /// [C++11] type-specifier-seq declarator braced-init-list /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression +/// simple-declaration: +/// decl-specifier-seq init-declarator-list[opt] ';' /// -bool Parser::isCXXConditionDeclaration() { - TPResult TPR = isCXXDeclarationSpecifier(); - if (TPR != TPResult::Ambiguous) - return TPR != TPResult::False; // Returns true for TPResult::True or - // TPResult::Error. - - // FIXME: Add statistics about the number of ambiguous statements encountered - // and how they were resolved (number of declarations+number of expressions). +/// Note that, unlike isCXXSimpleDeclaration, we must disambiguate all the way +/// 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); - // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. - // We need tentative parsing... + if (State.update(isCXXDeclarationSpecifier())) + return State.result(); - TentativeParsingAction PA(*this); + // It might be a declaration; we need tentative parsing. + RevertingTentativeParsingAction PA(*this); - // type-specifier-seq - TryConsumeDeclarationSpecifier(); + // FIXME: A tag definition unambiguously tells us this is an init-statement. + if (State.update(TryConsumeDeclarationSpecifier())) + return State.result(); assert(Tok.is(tok::l_paren) && "Expected '('"); - // declarator - TPR = TryParseDeclarator(false/*mayBeAbstract*/); + while (true) { + // Consume a declarator. + if (State.update(TryParseDeclarator(false/*mayBeAbstract*/))) + return State.result(); + + // Attributes, asm label, or an initializer imply this is not an expression. + // FIXME: Disambiguate properly after an = instead of assuming that it's a + // valid declaration. + if (Tok.isOneOf(tok::equal, tok::kw_asm, tok::kw___attribute) || + (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))) { + State.markNotExpression(); + return State.result(); + } - // In case of an error, let the declaration parsing code handle it. - if (TPR == TPResult::Error) - TPR = TPResult::True; + // 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(); - if (TPR == TPResult::Ambiguous) { - // '=' - // [GNU] simple-asm-expr[opt] attributes[opt] - if (Tok.isOneOf(tok::equal, tok::kw_asm, tok::kw___attribute)) - TPR = TPResult::True; - else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) - TPR = TPResult::True; - else - TPR = TPResult::False; - } + // A parenthesized initializer could be part of an expression or a + // simple-declaration. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + SkipUntil(tok::r_paren, StopAtSemi); + } - PA.Revert(); + if (!TryConsumeToken(tok::comma)) + break; + } - assert(TPR == TPResult::True || TPR == TPResult::False); - return TPR == TPResult::True; + // We reached the end. If it can now be some kind of decl, then it is. + if (State.CanBeCondition && Tok.is(tok::r_paren)) + return ConditionOrInitStatement::ConditionDecl; + else if (State.CanBeInitStatement && Tok.is(tok::semi)) + return ConditionOrInitStatement::InitStmtDecl; + else + return ConditionOrInitStatement::Expression; } /// \brief Determine whether the next set of tokens contains a type-id. @@ -423,7 +501,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. // We need tentative parsing... - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); // type-specifier-seq TryConsumeDeclarationSpecifier(); @@ -456,8 +534,6 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { TPR = TPResult::False; } - PA.Revert(); - assert(TPR == TPResult::True || TPR == TPResult::False); return TPR == TPResult::True; } @@ -508,7 +584,7 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, if (!Disambiguate && !getLangOpts().ObjC1) return CAK_AttributeSpecifier; - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); // Opening brackets were checked for above. ConsumeBracket(); @@ -520,8 +596,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, bool IsAttribute = SkipUntil(tok::r_square); IsAttribute &= Tok.is(tok::r_square); - PA.Revert(); - return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier; } @@ -542,8 +616,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, // A lambda cannot end with ']]', and an attribute must. bool IsAttribute = Tok.is(tok::r_square); - PA.Revert(); - if (IsAttribute) // Case 1: C++11 attribute. return CAK_AttributeSpecifier; @@ -564,7 +636,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, while (Tok.isNot(tok::r_square)) { if (Tok.is(tok::comma)) { // Case 1: Stray commas can only occur in attributes. - PA.Revert(); return CAK_AttributeSpecifier; } @@ -611,8 +682,6 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, } } - PA.Revert(); - if (IsAttribute) // Case 1: C++11 statement attribute. return CAK_AttributeSpecifier; @@ -833,7 +902,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // '(' abstract-declarator ')' if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec, tok::kw___cdecl, tok::kw___stdcall, tok::kw___fastcall, tok::kw___thiscall, - tok::kw___vectorcall, tok::kw___unaligned)) + tok::kw___vectorcall)) return TPResult::True; // attributes indicate declaration TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); if (TPR != TPResult::Ambiguous) @@ -946,6 +1015,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_char: case tok::kw_const: case tok::kw_double: + case tok::kw___float128: case tok::kw_enum: case tok::kw_half: case tok::kw_float: @@ -987,6 +1057,8 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___pixel: case tok::kw___bool: case tok::kw__Atomic: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" case tok::kw___unknown_anytype: return TPResult::False; @@ -1317,7 +1389,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, Tok.getAnnotationRange(), SS); if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); ConsumeToken(); ConsumeToken(); bool isIdentifier = Tok.is(tok::identifier); @@ -1325,7 +1397,6 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, if (!isIdentifier) TPR = isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); - PA.Revert(); if (isIdentifier || TPR == TPResult::True || TPR == TPResult::Error) @@ -1337,6 +1408,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, *HasMissingTypename = true; return TPResult::Ambiguous; } + + // FIXME: Fails to either revert or commit the tentative parse! } else { // Try to resolve the name. If it doesn't exist, assume it was // intended to name a type and keep disambiguating. @@ -1388,15 +1461,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, // In Objective-C, we might have a protocol-qualified type. if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { // Tentatively parse the protocol qualifiers. - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); ConsumeToken(); // The type token TPResult TPR = TryParseProtocolQualifiers(); bool isFollowedByParen = Tok.is(tok::l_paren); bool isFollowedByBrace = Tok.is(tok::l_brace); - PA.Revert(); - if (TPR == TPResult::Error) return TPResult::Error; @@ -1424,6 +1495,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::annot_decltype: if (NextToken().is(tok::l_paren)) @@ -1448,14 +1520,12 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, if (NextToken().isNot(tok::l_paren)) return TPResult::True; - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); TPResult TPR = TryParseTypeofSpecifier(); bool isFollowedByParen = Tok.is(tok::l_paren); bool isFollowedByBrace = Tok.is(tok::l_brace); - PA.Revert(); - if (TPR == TPResult::Error) return TPResult::Error; @@ -1515,6 +1585,7 @@ bool Parser::isCXXDeclarationSpecifierAType() { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::kw___unknown_anytype: case tok::kw___auto_type: @@ -1594,7 +1665,7 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { // ambiguities mentioned in 6.8, the resolution is to consider any construct // that could possibly be a declaration a declaration. - TentativeParsingAction PA(*this); + RevertingTentativeParsingAction PA(*this); ConsumeParen(); bool InvalidAsDeclaration = false; @@ -1618,8 +1689,6 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) { } } - PA.Revert(); - if (IsAmbiguous && TPR == TPResult::Ambiguous) *IsAmbiguous = true; |