aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Parse/ParseTentative.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:04:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:04:05 +0000
commit676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63 (patch)
tree02a1ac369cb734d0abfa5000dd86e5b7797e6a74 /lib/Parse/ParseTentative.cpp
parentc7e70c433efc6953dc3888b9fbf9f3512d7da2b0 (diff)
downloadsrc-676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63.tar.gz
src-676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63.zip
Vendor import of clang trunk r351319 (just before the release_80 branchvendor/clang/clang-trunk-r351319
Notes
Notes: svn path=/vendor/clang/dist/; revision=343173 svn path=/vendor/clang/clang-trunk-r351319/; revision=343174; tag=vendor/clang/clang-trunk-r351319
Diffstat (limited to 'lib/Parse/ParseTentative.cpp')
-rw-r--r--lib/Parse/ParseTentative.cpp105
1 files changed, 79 insertions, 26 deletions
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index dfd1f8c3b2e6..de39e0675fdb 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