aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Parse/ParseTentative.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:44:14 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:44:14 +0000
commit2b6b257f4e5503a7a2675bdb8735693db769f75c (patch)
treee85e046ae7003fe3bcc8b5454cd0fa3f7407b470 /lib/Parse/ParseTentative.cpp
parentb4348ed0b7e90c0831b925fbee00b5f179a99796 (diff)
downloadsrc-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.cpp193
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;