From: Steve Naroff Date: Tue, 5 Feb 2008 21:27:35 +0000 (+0000) Subject: Fix Parser::ParseObjCTryStmt() to allow for trailing @-keyword statements/expressions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=64515f31850024a263e8f55f81e9ea4b39925cfa;p=clang 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 663fa98aa2..890b9bcaf9 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -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()) { diff --git a/Parse/ParseStmt.cpp b/Parse/ParseStmt.cpp index 8559a3dd48..b6cd558b04 100644 --- a/Parse/ParseStmt.cpp +++ b/Parse/ParseStmt.cpp @@ -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: diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 6c3bbcddb2..2dbae31339 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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 &Names, diff --git a/test/Parser/objc-try-catch-1.m b/test/Parser/objc-try-catch-1.m index d6ad8d38ef..95ca5a18f4 100644 --- a/test/Parser/objc-try-catch-1.m +++ b/test/Parser/objc-try-catch-1.m @@ -50,3 +50,13 @@ void baz() @finally {} } +void noTwoTokenLookAheadRequiresABitOfFancyFootworkInTheParser() { + @try { + // Do something + } @catch (...) {} + @try { + // Do something + } @catch (...) {} + return 0; +} +