Patch to parse objective-c's @try-statement and @throw-statement.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42148 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Parse/ParseExpr.cpp b/Parse/ParseExpr.cpp
index 2e2a64e..1a7c403 100644
--- a/Parse/ParseExpr.cpp
+++ b/Parse/ParseExpr.cpp
@@ -172,6 +172,18 @@
   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 @@
   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 356c7a7..0533660 100644
--- a/Parse/ParseObjc.cpp
+++ b/Parse/ParseObjc.cpp
@@ -916,6 +916,77 @@
     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 @@
   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 fb4fe1e..d37973b 100644
--- a/Parse/ParseStmt.cpp
+++ b/Parse/ParseStmt.cpp
@@ -75,22 +75,35 @@
   // 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 30253f7..059edec 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -406,6 +406,8 @@
      "@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 9f57b13..243b88f 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -270,6 +270,8 @@
   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 @@
   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 @@
   
   //===--------------------------------------------------------------------===//
   // 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 0000000..f4a1201
--- /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();
+        }
+}
+