Fix Parser::ParseObjCTryStmt() to allow for trailing @-keyword statements/expressions.
This bug fix is the result of not having 2-token lookahead to recognize specific @-keywords.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46768 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp
index 663fa98..890b9bc 100644
--- a/Parse/ParseObjc.cpp
+++ b/Parse/ParseObjc.cpp
@@ -1150,8 +1150,11 @@
/// parameter-declaration
/// '...' [OBJC2]
///
-Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
+Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc,
+ bool &processAtKeyword) {
bool catch_or_finally_seen = false;
+ processAtKeyword = false;
+
ConsumeToken(); // consume try
if (Tok.isNot(tok::l_brace)) {
Diag (Tok, diag::err_expected_lbrace);
@@ -1180,8 +1183,7 @@
DeclaratorInfo, 0);
StmtResult stmtResult = Actions.ActOnDeclStmt(aBlockVarDecl);
FirstPart = stmtResult.isInvalid ? 0 : stmtResult.Val;
- }
- else
+ } else
ConsumeToken(); // consume '...'
SourceLocation RParenLoc = ConsumeParen();
StmtResult CatchBody = ParseCompoundStatementBody();
@@ -1190,16 +1192,14 @@
CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, RParenLoc,
FirstPart, CatchBody.Val, CatchStmts.Val);
ExitScope();
- }
- else {
+ } else {
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after,
"@catch clause");
return true;
}
catch_or_finally_seen = true;
- }
- else if (Tok.isObjCAtKeyword(tok::objc_finally)) {
- ConsumeToken(); // consume finally
+ } else if (Tok.isObjCAtKeyword(tok::objc_finally)) {
+ ConsumeToken(); // consume finally
StmtResult FinallyBody = ParseCompoundStatementBody();
if (FinallyBody.isInvalid)
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
@@ -1207,6 +1207,9 @@
FinallyBody.Val);
catch_or_finally_seen = true;
break;
+ } else {
+ processAtKeyword = true;
+ break;
}
}
if (!catch_or_finally_seen) {
@@ -1259,6 +1262,31 @@
return MDecl;
}
+Parser::StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
+ if (Tok.isObjCAtKeyword(tok::objc_try)) {
+ bool parsedAtSign;
+
+ StmtResult Res = ParseObjCTryStmt(AtLoc, parsedAtSign);
+ if (!Res.isInvalid && parsedAtSign)
+ return ParseObjCAtStatement(AtLoc);
+ return Res;
+ } else if (Tok.isObjCAtKeyword(tok::objc_throw))
+ return ParseObjCThrowStmt(AtLoc);
+ else if (Tok.isObjCAtKeyword(tok::objc_synchronized))
+ return ParseObjCSynchronizedStmt(AtLoc);
+ ExprResult Res = ParseExpressionWithLeadingAt(AtLoc);
+ if (Res.isInvalid) {
+ // If the expression is invalid, skip ahead to the next semicolon. Not
+ // doing this opens us up to the possibility of infinite loops if
+ // ParseExpression does not consume any tokens.
+ SkipUntil(tok::semi);
+ return true;
+ }
+ // Otherwise, eat the semicolon.
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
+ return Actions.ActOnExprStmt(Res.Val);
+}
+
Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
switch (Tok.getKind()) {
diff --git a/Parse/ParseStmt.cpp b/Parse/ParseStmt.cpp
index 8559a3d..b6cd558 100644
--- a/Parse/ParseStmt.cpp
+++ b/Parse/ParseStmt.cpp
@@ -87,23 +87,7 @@
case tok::at: // May be a @try or @throw statement
{
AtLoc = ConsumeToken(); // consume @
- if (Tok.isObjCAtKeyword(tok::objc_try))
- return ParseObjCTryStmt(AtLoc);
- else if (Tok.isObjCAtKeyword(tok::objc_throw))
- return ParseObjCThrowStmt(AtLoc);
- else if (Tok.isObjCAtKeyword(tok::objc_synchronized))
- return ParseObjCSynchronizedStmt(AtLoc);
- ExprResult Res = ParseExpressionWithLeadingAt(AtLoc);
- if (Res.isInvalid) {
- // If the expression is invalid, skip ahead to the next semicolon. Not
- // doing this opens us up to the possibility of infinite loops if
- // ParseExpression does not consume any tokens.
- SkipUntil(tok::semi);
- return true;
- }
- // Otherwise, eat the semicolon.
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Res.Val);
+ return ParseObjCAtStatement(AtLoc);
}
default: