forked from OSchip/llvm-project
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. llvm-svn: 46768
This commit is contained in:
parent
a838141957
commit
e6016798bf
|
@ -1150,8 +1150,11 @@ Parser::StmtResult Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
|
|||
/// 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 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
|||
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 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
|||
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 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
|
|||
FinallyBody.Val);
|
||||
catch_or_finally_seen = true;
|
||||
break;
|
||||
} else {
|
||||
processAtKeyword = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!catch_or_finally_seen) {
|
||||
|
@ -1259,6 +1262,31 @@ Parser::DeclTy *Parser::ParseObjCMethodDefinition() {
|
|||
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()) {
|
||||
|
|
|
@ -87,23 +87,7 @@ Parser::StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) {
|
|||
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:
|
||||
|
|
|
@ -403,7 +403,8 @@ private:
|
|||
StmtResult ParseBreakStatement();
|
||||
StmtResult ParseReturnStatement();
|
||||
StmtResult ParseAsmStatement();
|
||||
StmtResult ParseObjCTryStmt(SourceLocation atLoc);
|
||||
StmtResult ParseObjCAtStatement(SourceLocation atLoc);
|
||||
StmtResult ParseObjCTryStmt(SourceLocation atLoc, bool &processAtKeyword);
|
||||
StmtResult ParseObjCThrowStmt(SourceLocation atLoc);
|
||||
StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc);
|
||||
void ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
|
||||
|
|
|
@ -50,3 +50,13 @@ void baz()
|
|||
@finally {}
|
||||
}
|
||||
|
||||
void noTwoTokenLookAheadRequiresABitOfFancyFootworkInTheParser() {
|
||||
@try {
|
||||
// Do something
|
||||
} @catch (...) {}
|
||||
@try {
|
||||
// Do something
|
||||
} @catch (...) {}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue