diff options
-rw-r--r-- | Parse/ParseExpr.cpp | 17 | ||||
-rw-r--r-- | Parse/ParseObjc.cpp | 74 | ||||
-rw-r--r-- | Parse/ParseStmt.cpp | 19 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 5 | ||||
-rw-r--r-- | test/Parser/objc-try-catch-1.m | 36 |
6 files changed, 146 insertions, 7 deletions
diff --git a/Parse/ParseExpr.cpp b/Parse/ParseExpr.cpp index 2e2a64ef88..1a7c403bd7 100644 --- a/Parse/ParseExpr.cpp +++ b/Parse/ParseExpr.cpp @@ -172,6 +172,18 @@ Parser::ExprResult Parser::ParseExpression() { return ParseRHSOfBinaryExpression(LHS, prec::Comma); } +/// This routine is called when the '@' is seen and consumed. +/// Current token is an Identifier and is not a 'try'. This +/// routine is necessary to disambiguate @try-statement from +/// ,for example, @encode-expression. +/// +Parser::ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation &AtLoc) { + ExprResult LHS = ParseObjCExpression(AtLoc); + if (LHS.isInvalid) return LHS; + + return ParseRHSOfBinaryExpression(LHS, prec::Comma); +} + /// ParseAssignmentExpression - Parse an expr that doesn't include commas. /// Parser::ExprResult Parser::ParseAssignmentExpression() { @@ -589,7 +601,10 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { case tok::kw_static_cast: return ParseCXXCasts(); case tok::at: - return ParseObjCExpression(); + { + SourceLocation AtLoc = ConsumeToken(); + return ParseObjCExpression(AtLoc); + } case tok::l_square: return ParseObjCMessageExpression (); default: diff --git a/Parse/ParseObjc.cpp b/Parse/ParseObjc.cpp index 356c7a7fd4..0533660974 100644 --- a/Parse/ParseObjc.cpp +++ b/Parse/ParseObjc.cpp @@ -916,6 +916,77 @@ Parser::DeclTy *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { Diag(Tok, diag::err_expected_semi_after, "@dynamic"); return 0; } + +/// objc-throw-statement: +/// throw expression[opt]; +/// +Parser::DeclTy *Parser::ParseObjCThrowStmt(SourceLocation &atLoc) { + ConsumeToken(); // consume throw + if (Tok.getKind() != tok::semi) { + ExprResult Res = ParseAssignmentExpression(); + if (Res.isInvalid) { + SkipUntil(tok::semi); + return 0; + } + } + return 0; +} + +/// objc-try-catch-statement: +/// @try compound-statement objc-catch-list[opt] +/// @try compound-statement objc-catch-list[opt] @finally compound-statement +/// +/// objc-catch-list: +/// @catch ( parameter-declaration ) compound-statement +/// objc-catch-list @catch ( catch-parameter-declaration ) compound-statement +/// catch-parameter-declaration: +/// parameter-declaration +/// '...' [OBJC2] +/// +Parser::DeclTy *Parser::ParseObjCTryStmt(SourceLocation &atLoc) { + bool catch_or_finally_seen = false; + ConsumeToken(); // consume try + if (Tok.getKind() != tok::l_brace) { + Diag (Tok, diag::err_expected_lbrace); + return 0; + } + StmtResult TryBody = ParseCompoundStatementBody(); + while (Tok.getKind() == tok::at) { + ConsumeToken(); + if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_catch) { + SourceLocation catchLoc = ConsumeToken(); // consume catch + if (Tok.getKind() == tok::l_paren) { + ConsumeParen(); + if (Tok.getKind() != tok::ellipsis) { + DeclSpec DS; + ParseDeclarationSpecifiers(DS); + // Parse the parameter-declaration. + // FIXME: BlockContext may not be the right context! + Declarator ParmDecl(DS, Declarator::BlockContext); + ParseDeclarator(ParmDecl); + } + else + ConsumeToken(); // consume '...' + ConsumeParen(); + StmtResult CatchMody = ParseCompoundStatementBody(); + } + else { + Diag(catchLoc, diag::err_expected_lparen_after, "@catch clause"); + return 0; + } + catch_or_finally_seen = true; + } + else if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_finally) { + ConsumeToken(); // consume finally + StmtResult FinallyBody = ParseCompoundStatementBody(); + catch_or_finally_seen = true; + break; + } + } + if (!catch_or_finally_seen) + Diag(atLoc, diag::err_missing_catch_finally); + return 0; +} /// objc-method-def: objc-method-proto ';'[opt] '{' body '}' /// @@ -954,8 +1025,7 @@ void Parser::ParseObjCClassMethodDefinition() { StmtResult FnBody = ParseCompoundStatementBody(); } -Parser::ExprResult Parser::ParseObjCExpression() { - SourceLocation AtLoc = ConsumeToken(); // the "@" +Parser::ExprResult Parser::ParseObjCExpression(SourceLocation &AtLoc) { switch (Tok.getKind()) { case tok::string_literal: // primary-expression: string-literal diff --git a/Parse/ParseStmt.cpp b/Parse/ParseStmt.cpp index fb4fe1e339..d37973b013 100644 --- a/Parse/ParseStmt.cpp +++ b/Parse/ParseStmt.cpp @@ -75,22 +75,35 @@ Parser::StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) { // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), // or they directly 'return;' if not. - switch (Tok.getKind()) { + tok::TokenKind Kind = Tok.getKind(); + SourceLocation AtLoc; + switch (Kind) { case tok::identifier: // C99 6.8.1: labeled-statement // identifier ':' statement // declaration (if !OnlyStatement) // expression[opt] ';' return ParseIdentifierStatement(OnlyStatement); + case tok::at: // May be a @try or @throw statement + { + AtLoc = ConsumeToken(); // consume @ + if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_try) + return ParseObjCTryStmt(AtLoc); + else if (Tok.getIdentifierInfo()->getObjCKeywordID() == tok::objc_throw) + return ParseObjCThrowStmt(AtLoc); + } + // Fall thru. + default: - if (!OnlyStatement && isDeclarationSpecifier()) { + if (Kind != tok::at && !OnlyStatement && isDeclarationSpecifier()) { return Actions.ActOnDeclStmt(ParseDeclaration(Declarator::BlockContext)); } else if (Tok.getKind() == tok::r_brace) { Diag(Tok, diag::err_expected_statement); return true; } else { // expression[opt] ';' - ExprResult Res = ParseExpression(); + ExprResult Res = (Kind == tok::at) ? ParseExpressionWithLeadingAt(AtLoc) + : ParseExpression(); 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 diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 30253f7226..059edecb86 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -406,6 +406,8 @@ DIAG(err_objc_protocol_required, ERROR, "@required may be specified in protocols only") DIAG(err_objc_protocol_optional, ERROR, "@optional may be specified in protocols only") +DIAG(err_missing_catch_finally, ERROR, + "@try statment without a @catch and @finally clause") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9f57b13780..243b88f9ff 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -270,6 +270,8 @@ private: DeclTy *ParseObjCAtAliasDeclaration(SourceLocation atLoc); DeclTy *ParseObjCPropertySynthesize(SourceLocation atLoc); DeclTy *ParseObjCPropertyDynamic(SourceLocation atLoc); + DeclTy *ParseObjCTryStmt(SourceLocation &atLoc); + DeclTy *ParseObjCThrowStmt(SourceLocation &atLoc); IdentifierInfo *ParseObjCSelector(); // Definitions for Objective-c context sensitive keywords recognition. @@ -310,6 +312,7 @@ private: ExprResult ParseAssignmentExpression(); // Expr that doesn't include commas. ExprResult ParseExpressionWithLeadingIdentifier(const Token &Tok); + ExprResult ParseExpressionWithLeadingAt(SourceLocation &AtLoc); ExprResult ParseAssignmentExprWithLeadingIdentifier(const Token &Tok); ExprResult ParseAssignmentExpressionWithLeadingStar(const Token &Tok); @@ -355,7 +358,7 @@ private: //===--------------------------------------------------------------------===// // Objective-C Expressions - ExprResult ParseObjCExpression(); + ExprResult ParseObjCExpression(SourceLocation &AtLocation); ExprResult ParseObjCStringLiteral(); ExprResult ParseObjCEncodeExpression(); ExprResult ParseObjCProtocolExpression(); diff --git a/test/Parser/objc-try-catch-1.m b/test/Parser/objc-try-catch-1.m new file mode 100644 index 0000000000..f4a1201c85 --- /dev/null +++ b/test/Parser/objc-try-catch-1.m @@ -0,0 +1,36 @@ +void * proc(); + +@interface Frob +@end + +@interface Frob1 +@end + +void * foo() +{ + @try { + return proc(); + } + @catch (Frob* ex) { + @throw; + } + @catch (Frob1* ex) { + @throw proc(); + } + @finally { + @try { + return proc(); + } + @catch (Frob* ex) { + @throw; + } + @catch(...) { + @throw (4,3,proc()); + } + } + + @try { // expected-error {{@try statment without a @catch and @finally clause}} + return proc(); + } +} + |