[cfe-commits] r102221 - in /cfe/trunk: include/clang/AST/StmtObjC.h include/clang/Parse/Action.h lib/AST/Stmt.cpp lib/AST/StmtDumper.cpp lib/AST/StmtPrinter.cpp lib/CodeGen/CGObjCGNU.cpp lib/CodeGen/CGObjCMac.cpp lib/Frontend/PCHReaderStmt.cpp lib/Frontend/PCHWriterStmt.cpp lib/Frontend/RewriteObjC.cpp lib/Parse/ParseObjc.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/Sema.h lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h test/PCH/objc_stmts.h test/PCH/objc_stmts.m

Douglas Gregor dgregor at apple.com
Fri Apr 23 15:50:50 PDT 2010


Author: dgregor
Date: Fri Apr 23 17:50:49 2010
New Revision: 102221

URL: http://llvm.org/viewvc/llvm-project?rev=102221&view=rev
Log:
Improve the AST representation of Objective-C @try/@catch/@finally
statements. Instead of the @try having a single @catch, where all of
the @catch's were chained (using an O(n^2) algorithm nonetheless),
@try just holds an array of its @catch blocks. The resulting AST is
slightly more compact (not important) and better represents the actual
language semantics (good).


Added:
    cfe/trunk/test/PCH/objc_stmts.h
    cfe/trunk/test/PCH/objc_stmts.m
Modified:
    cfe/trunk/include/clang/AST/StmtObjC.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/AST/Stmt.cpp
    cfe/trunk/lib/AST/StmtDumper.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp
    cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
    cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
    cfe/trunk/lib/Frontend/RewriteObjC.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Sema/JumpDiagnostics.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/TreeTransform.h

Modified: cfe/trunk/include/clang/AST/StmtObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtObjC.h?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtObjC.h (original)
+++ cfe/trunk/include/clang/AST/StmtObjC.h Fri Apr 23 17:50:49 2010
@@ -71,30 +71,23 @@
 /// ObjCAtCatchStmt - This represents objective-c's @catch statement.
 class ObjCAtCatchStmt : public Stmt {
 private:
-  enum { BODY, NEXT_CATCH, END_EXPR };
   ParmVarDecl *ExceptionDecl;
-  Stmt *SubExprs[END_EXPR];
+  Stmt *Body;
   SourceLocation AtCatchLoc, RParenLoc;
 
 public:
   ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc,
                   ParmVarDecl *catchVarDecl,
-                  Stmt *atCatchStmt, Stmt *atCatchList);
+                  Stmt *atCatchStmt)
+    : Stmt(ObjCAtCatchStmtClass), ExceptionDecl(catchVarDecl), 
+    Body(atCatchStmt), AtCatchLoc(atCatchLoc), RParenLoc(rparenloc) { }
 
   explicit ObjCAtCatchStmt(EmptyShell Empty) :
     Stmt(ObjCAtCatchStmtClass, Empty) { }
 
-  const Stmt *getCatchBody() const { return SubExprs[BODY]; }
-  Stmt *getCatchBody() { return SubExprs[BODY]; }
-  void setCatchBody(Stmt *S) { SubExprs[BODY] = S; }
-
-  const ObjCAtCatchStmt *getNextCatchStmt() const {
-    return static_cast<const ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
-  }
-  ObjCAtCatchStmt *getNextCatchStmt() {
-    return static_cast<ObjCAtCatchStmt*>(SubExprs[NEXT_CATCH]);
-  }
-  void setNextCatchStmt(Stmt *S) { SubExprs[NEXT_CATCH] = S; }
+  const Stmt *getCatchBody() const { return Body; }
+  Stmt *getCatchBody() { return Body; }
+  void setCatchBody(Stmt *S) { Body = S; }
 
   const ParmVarDecl *getCatchParamDecl() const {
     return ExceptionDecl;
@@ -110,7 +103,7 @@
   void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
 
   virtual SourceRange getSourceRange() const {
-    return SourceRange(AtCatchLoc, SubExprs[BODY]->getLocEnd());
+    return SourceRange(AtCatchLoc, Body->getLocEnd());
   }
 
   bool hasEllipsis() const { return getCatchParamDecl() == 0; }
@@ -160,50 +153,94 @@
 /// @try ... @catch ... @finally statement.
 class ObjCAtTryStmt : public Stmt {
 private:
-  enum { TRY, CATCH, FINALLY, END_EXPR };
-  Stmt* SubStmts[END_EXPR];
-
+  // The location of the 
   SourceLocation AtTryLoc;
-public:
+  
+  // The number of catch blocks in this statement.
+  unsigned NumCatchStmts : 16;
+  
+  // Whether this statement has a @finally statement.
+  bool HasFinally : 1;
+  
+  /// \brief Retrieve the statements that are stored after this @try statement.
+  ///
+  /// The order of the statements in memory follows the order in the source,
+  /// with the @try body first, followed by the @catch statements (if any) and,
+  /// finally, the @finally (if it exists).
+  Stmt **getStmts() { return reinterpret_cast<Stmt **> (this + 1); }
+  const Stmt* const *getStmts() const { 
+    return reinterpret_cast<const Stmt * const*> (this + 1); 
+  }
+  
   ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
-                Stmt *atCatchStmt,
-                Stmt *atFinallyStmt)
-  : Stmt(ObjCAtTryStmtClass) {
-      SubStmts[TRY] = atTryStmt;
-      SubStmts[CATCH] = atCatchStmt;
-      SubStmts[FINALLY] = atFinallyStmt;
-      AtTryLoc = atTryLoc;
-    }
-  explicit ObjCAtTryStmt(EmptyShell Empty) :
-    Stmt(ObjCAtTryStmtClass, Empty) { }
+                Stmt **CatchStmts, unsigned NumCatchStmts,
+                Stmt *atFinallyStmt);
+  
+  explicit ObjCAtTryStmt(EmptyShell Empty, unsigned NumCatchStmts,
+                         bool HasFinally)
+    : Stmt(ObjCAtTryStmtClass, Empty), NumCatchStmts(NumCatchStmts),
+      HasFinally(HasFinally) { }
 
+public:
+  static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc, 
+                               Stmt *atTryStmt,
+                               Stmt **CatchStmts, unsigned NumCatchStmts,
+                               Stmt *atFinallyStmt);
+  static ObjCAtTryStmt *CreateEmpty(ASTContext &Context, 
+                                    unsigned NumCatchStmts,
+                                    bool HasFinally);
+  
+  /// \brief Retrieve the location of the @ in the @try.
   SourceLocation getAtTryLoc() const { return AtTryLoc; }
   void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; }
 
-  const Stmt *getTryBody() const { return SubStmts[TRY]; }
-  Stmt *getTryBody() { return SubStmts[TRY]; }
-  void setTryBody(Stmt *S) { SubStmts[TRY] = S; }
-
-  const ObjCAtCatchStmt *getCatchStmts() const {
-    return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
+  /// \brief Retrieve the @try body.
+  const Stmt *getTryBody() const { return getStmts()[0]; }
+  Stmt *getTryBody() { return getStmts()[0]; }
+  void setTryBody(Stmt *S) { getStmts()[0] = S; }
+
+  /// \brief Retrieve the number of @catch statements in this try-catch-finally
+  /// block.
+  unsigned getNumCatchStmts() const { return NumCatchStmts; }
+  
+  /// \brief Retrieve a @catch statement.
+  const ObjCAtCatchStmt *getCatchStmt(unsigned I) const {
+    assert(I < NumCatchStmts && "Out-of-bounds @catch index");
+    return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
+  }
+  
+  /// \brief Retrieve a @catch statement.
+  ObjCAtCatchStmt *getCatchStmt(unsigned I) {
+    assert(I < NumCatchStmts && "Out-of-bounds @catch index");
+    return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
+  }
+  
+  /// \brief Set a particular catch statement.
+  void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) {
+    assert(I < NumCatchStmts && "Out-of-bounds @catch index");
+    getStmts()[I + 1] = S;
   }
-  ObjCAtCatchStmt *getCatchStmts() {
-    return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
-  }
-  void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; }
-
+  
+  /// Retrieve the @finally statement, if any.
   const ObjCAtFinallyStmt *getFinallyStmt() const {
-    return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
+    if (!HasFinally)
+      return 0;
+    
+    return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
   }
   ObjCAtFinallyStmt *getFinallyStmt() {
-    return dyn_cast_or_null<ObjCAtFinallyStmt>(SubStmts[FINALLY]);
+    if (!HasFinally)
+      return 0;
+    
+    return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
   }
-  void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; }
-
-  virtual SourceRange getSourceRange() const {
-    return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd());
+  void setFinallyStmt(Stmt *S) { 
+    assert(HasFinally && "@try does not have a @finally slot!");
+    getStmts()[1 + NumCatchStmts] = S; 
   }
 
+  virtual SourceRange getSourceRange() const;
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == ObjCAtTryStmtClass;
   }

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Apr 23 17:50:49 2010
@@ -938,20 +938,46 @@
   }
 
   // Objective-c statements
+  
+  /// \brief Parsed an Objective-C @catch statement.
+  ///
+  /// \param AtLoc The location of the '@' starting the '@catch'.
+  ///
+  /// \param RParen The location of the right parentheses ')' after the
+  /// exception variable.
+  ///
+  /// \param Parm The variable that will catch the exception. Will be NULL if 
+  /// this is a @catch(...) block.
+  ///
+  /// \param Body The body of the @catch block.
   virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
                                                 SourceLocation RParen,
-                                                DeclPtrTy Parm, StmtArg Body,
-                                                StmtArg CatchList) {
+                                                DeclPtrTy Parm, StmtArg Body) {
     return StmtEmpty();
   }
 
+  /// \brief Parsed an Objective-C @finally statement.
+  ///
+  /// \param AtLoc The location of the '@' starting the '@finally'.
+  ///
+  /// \param Body The body of the @finally block.
   virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
                                                   StmtArg Body) {
     return StmtEmpty();
   }
 
+  /// \brief Parsed an Objective-C @try- at catch-@finally statement.
+  ///
+  /// \param AtLoc The location of the '@' starting '@try'.
+  ///
+  /// \param Try The body of the '@try' statement.
+  ///
+  /// \param CatchStmts The @catch statements.
+  ///
+  /// \param Finally The @finally statement.
   virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
-                                              StmtArg Try, StmtArg Catch,
+                                              StmtArg Try, 
+                                              MultiStmtArg CatchStmts,
                                               StmtArg Finally) {
     return StmtEmpty();
   }

Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Fri Apr 23 17:50:49 2010
@@ -392,26 +392,53 @@
   RParenLoc = RPL;
 }
 
+ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
+                             Stmt **CatchStmts, unsigned NumCatchStmts,
+                             Stmt *atFinallyStmt)
+  : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc),
+    NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0)
+{
+  Stmt **Stmts = getStmts();
+  Stmts[0] = atTryStmt;
+  for (unsigned I = 0; I != NumCatchStmts; ++I)
+    Stmts[I + 1] = CatchStmts[I];
+  
+  if (HasFinally)
+    Stmts[NumCatchStmts + 1] = atFinallyStmt;
+}
 
-ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
-                                 SourceLocation rparenloc,
-                                 ParmVarDecl *catchVarDecl, Stmt *atCatchStmt,
-                                 Stmt *atCatchList)
-: Stmt(ObjCAtCatchStmtClass) {
-  ExceptionDecl = catchVarDecl;
-  SubExprs[BODY] = atCatchStmt;
-  SubExprs[NEXT_CATCH] = NULL;
-  // FIXME: O(N^2) in number of catch blocks.
-  if (atCatchList) {
-    ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);
-
-    while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
-      AtCatchList = NextCatch;
-
-    AtCatchList->SubExprs[NEXT_CATCH] = this;
-  }
-  AtCatchLoc = atCatchLoc;
-  RParenLoc = rparenloc;
+ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, 
+                                     SourceLocation atTryLoc, 
+                                     Stmt *atTryStmt,
+                                     Stmt **CatchStmts, 
+                                     unsigned NumCatchStmts,
+                                     Stmt *atFinallyStmt) {
+  unsigned Size = sizeof(ObjCAtTryStmt) + 
+    (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
+  void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+  return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
+                                 atFinallyStmt);
+}
+
+ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, 
+                                                 unsigned NumCatchStmts,
+                                                 bool HasFinally) {
+  unsigned Size = sizeof(ObjCAtTryStmt) + 
+    (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
+  void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+  return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);  
+}
+
+SourceRange ObjCAtTryStmt::getSourceRange() const {
+  SourceLocation EndLoc;
+  if (HasFinally)
+    EndLoc = getFinallyStmt()->getLocEnd();
+  else if (NumCatchStmts)
+    EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
+  else
+    EndLoc = getTryBody()->getLocEnd();
+  
+  return SourceRange(AtTryLoc, EndLoc);
 }
 
 CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
@@ -630,19 +657,18 @@
 }
 
 // ObjCAtCatchStmt
-Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator ObjCAtCatchStmt::child_end() {
-  return &SubExprs[0]+END_EXPR;
-}
+Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; }
+Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; }
 
 // ObjCAtFinallyStmt
 Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
 Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
 
 // ObjCAtTryStmt
-Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
-Stmt::child_iterator ObjCAtTryStmt::child_end()   {
-  return &SubStmts[0]+END_EXPR;
+Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); }
+
+Stmt::child_iterator ObjCAtTryStmt::child_end() {
+  return getStmts() + 1 + NumCatchStmts + HasFinally;
 }
 
 // ObjCAtThrowStmt

Modified: cfe/trunk/lib/AST/StmtDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtDumper.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtDumper.cpp (original)
+++ cfe/trunk/lib/AST/StmtDumper.cpp Fri Apr 23 17:50:49 2010
@@ -143,6 +143,7 @@
     void DumpCXXTemporary(CXXTemporary *Temporary);
 
     // ObjC
+    void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
     void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
     void VisitObjCMessageExpr(ObjCMessageExpr* Node);
     void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
@@ -524,6 +525,16 @@
   }
 }
 
+void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
+  DumpStmt(Node);
+  if (ParmVarDecl *CatchParam = Node->getCatchParamDecl()) {
+    OS << " catch parm = ";
+    DumpDeclarator(CatchParam);
+  } else {
+    OS << " catch all";
+  }
+}
+
 void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
   DumpExpr(Node);
   OS << " ";

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Fri Apr 23 17:50:49 2010
@@ -388,11 +388,8 @@
     OS << "\n";
   }
 
-  for (ObjCAtCatchStmt *catchStmt =
-         static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts());
-       catchStmt;
-       catchStmt =
-         static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) {
+  for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) {
+    ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I);
     Indent() << "@catch(";
     if (catchStmt->getCatchParamDecl()) {
       if (Decl *DS = catchStmt->getCatchParamDecl())

Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Fri Apr 23 17:50:49 2010
@@ -1781,11 +1781,12 @@
   bool HasCatchAll = false;
   // Only @try blocks are allowed @catch blocks, but both can have @finally
   if (isTry) {
-    if (const ObjCAtCatchStmt* CatchStmt =
-      cast<ObjCAtTryStmt>(S).getCatchStmts())  {
+    if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
+      const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S);
       CGF.setInvokeDest(CatchInCatch);
 
-      for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+      for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) {
+        const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I);
         const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
         Handlers.push_back(std::make_pair(CatchDecl,
                                           CatchStmt->getCatchBody()));

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Fri Apr 23 17:50:49 2010
@@ -2646,8 +2646,9 @@
     CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext),
                             CallTryExitPtr);
     CGF.EmitBranchThroughCleanup(FinallyRethrow);
-  } else if (const ObjCAtCatchStmt* CatchStmt =
-             cast<ObjCAtTryStmt>(S).getCatchStmts()) {
+  } else if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) {
+    const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S);
+    
     // Enter a new exception try block (in case a @catch block throws
     // an exception).
     CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
@@ -2666,7 +2667,8 @@
     // matched and avoid generating code for falling off the end if
     // so.
     bool AllMatched = false;
-    for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+    for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) {
+      const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I);
       llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch");
 
       const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl();
@@ -5579,42 +5581,41 @@
   llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers;
   bool HasCatchAll = false;
   if (isTry) {
-    if (const ObjCAtCatchStmt* CatchStmt =
-        cast<ObjCAtTryStmt>(S).getCatchStmts())  {
-      for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
-        const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
-        Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
-
-        // catch(...) always matches.
-        if (!CatchDecl) {
-          // Use i8* null here to signal this is a catch all, not a cleanup.
-          llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
-          SelectorArgs.push_back(Null);
-          HasCatchAll = true;
-          break;
-        }
+    const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S);
+    for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) {
+      const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I);
+      const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl();
+      Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody()));
 
-        if (CatchDecl->getType()->isObjCIdType() ||
-            CatchDecl->getType()->isObjCQualifiedIdType()) {
-          llvm::Value *IDEHType =
-            CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
-          if (!IDEHType)
-            IDEHType =
-              new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
-                                       false,
-                                       llvm::GlobalValue::ExternalLinkage,
-                                       0, "OBJC_EHTYPE_id");
-          SelectorArgs.push_back(IDEHType);
-        } else {
-          // All other types should be Objective-C interface pointer types.
-          const ObjCObjectPointerType *PT =
-            CatchDecl->getType()->getAs<ObjCObjectPointerType>();
-          assert(PT && "Invalid @catch type.");
-          const ObjCInterfaceType *IT = PT->getInterfaceType();
-          assert(IT && "Invalid @catch type.");
-          llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
-          SelectorArgs.push_back(EHType);
-        }
+      // catch(...) always matches.
+      if (!CatchDecl) {
+        // Use i8* null here to signal this is a catch all, not a cleanup.
+        llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
+        SelectorArgs.push_back(Null);
+        HasCatchAll = true;
+        break;
+      }
+
+      if (CatchDecl->getType()->isObjCIdType() ||
+          CatchDecl->getType()->isObjCQualifiedIdType()) {
+        llvm::Value *IDEHType =
+          CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
+        if (!IDEHType)
+          IDEHType =
+            new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy,
+                                     false,
+                                     llvm::GlobalValue::ExternalLinkage,
+                                     0, "OBJC_EHTYPE_id");
+        SelectorArgs.push_back(IDEHType);
+      } else {
+        // All other types should be Objective-C interface pointer types.
+        const ObjCObjectPointerType *PT =
+          CatchDecl->getType()->getAs<ObjCObjectPointerType>();
+        assert(PT && "Invalid @catch type.");
+        const ObjCInterfaceType *IT = PT->getInterfaceType();
+        assert(IT && "Invalid @catch type.");
+        llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false);
+        SelectorArgs.push_back(EHType);
       }
     }
   }

Modified: cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderStmt.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderStmt.cpp Fri Apr 23 17:50:49 2010
@@ -838,12 +838,11 @@
 
 unsigned PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
   VisitStmt(S);
-  S->setCatchBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
-  S->setNextCatchStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+  S->setCatchBody(cast_or_null<Stmt>(StmtStack.back()));
   S->setCatchParamDecl(cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
   S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
   S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
-  return 2;
+  return 1;
 }
 
 unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
@@ -855,11 +854,21 @@
 
 unsigned PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
   VisitStmt(S);
-  S->setTryBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3]));
-  S->setCatchStmts(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
-  S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+  assert(Record[Idx] == S->getNumCatchStmts());
+  ++Idx;
+  bool HasFinally = Record[Idx++];
+  for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+    unsigned Offset = StmtStack.size() - N - HasFinally + I;
+    S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(StmtStack[Offset]));
+  }
+
+  unsigned TryOffset
+    = StmtStack.size() - S->getNumCatchStmts() - HasFinally - 1;
+  S->setTryBody(cast_or_null<Stmt>(StmtStack[TryOffset]));
+  if (HasFinally)
+    S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
   S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
-  return 3;
+  return 1 + S->getNumCatchStmts() + HasFinally;
 }
 
 unsigned PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
@@ -1231,7 +1240,9 @@
       S = new (Context) ObjCAtFinallyStmt(Empty);
       break;
     case pch::STMT_OBJC_AT_TRY:
-      S = new (Context) ObjCAtTryStmt(Empty);
+      S = ObjCAtTryStmt::CreateEmpty(*Context, 
+                                     Record[PCHStmtReader::NumStmtFields],
+                                     Record[PCHStmtReader::NumStmtFields + 1]);
       break;
     case pch::STMT_OBJC_AT_SYNCHRONIZED:
       S = new (Context) ObjCAtSynchronizedStmt(Empty);

Modified: cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterStmt.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterStmt.cpp Fri Apr 23 17:50:49 2010
@@ -764,7 +764,6 @@
 
 void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) {
   Writer.WriteSubStmt(S->getCatchBody());
-  Writer.WriteSubStmt(S->getNextCatchStmt());
   Writer.AddDeclRef(S->getCatchParamDecl(), Record);
   Writer.AddSourceLocation(S->getAtCatchLoc(), Record);
   Writer.AddSourceLocation(S->getRParenLoc(), Record);
@@ -778,9 +777,13 @@
 }
 
 void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
+  Record.push_back(S->getNumCatchStmts());
+  Record.push_back(S->getFinallyStmt() != 0);
   Writer.WriteSubStmt(S->getTryBody());
-  Writer.WriteSubStmt(S->getCatchStmts());
-  Writer.WriteSubStmt(S->getFinallyStmt());
+  for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I)
+    Writer.WriteSubStmt(S->getCatchStmt(I));
+  if (S->getFinallyStmt())
+    Writer.WriteSubStmt(S->getFinallyStmt());
   Writer.AddSourceLocation(S->getAtTryLoc(), Record);
   Code = pch::STMT_OBJC_AT_TRY;
 }

Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original)
+++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Fri Apr 23 17:50:49 2010
@@ -1861,8 +1861,7 @@
   assert((*startBuf == '}') && "bogus @try block");
 
   SourceLocation lastCurlyLoc = startLoc;
-  ObjCAtCatchStmt *catchList = S->getCatchStmts();
-  if (catchList) {
+  if (S->getNumCatchStmts()) {
     startLoc = startLoc.getFileLocWithOffset(1);
     buf = " /* @catch begin */ else {\n";
     buf += " id _caught = objc_exception_extract(&_stack);\n";
@@ -1880,26 +1879,27 @@
   }
   bool sawIdTypedCatch = false;
   Stmt *lastCatchBody = 0;
-  while (catchList) {
-    ParmVarDecl *catchDecl = catchList->getCatchParamDecl();
+  for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+    ObjCAtCatchStmt *Catch = S->getCatchStmt(I);
+    ParmVarDecl *catchDecl = Catch->getCatchParamDecl();
 
-    if (catchList == S->getCatchStmts())
+    if (I == 0)
       buf = "if ("; // we are generating code for the first catch clause
     else
       buf = "else if (";
-    startLoc = catchList->getLocStart();
+    startLoc = Catch->getLocStart();
     startBuf = SM->getCharacterData(startLoc);
 
     assert((*startBuf == '@') && "bogus @catch location");
 
     const char *lParenLoc = strchr(startBuf, '(');
 
-    if (catchList->hasEllipsis()) {
+    if (Catch->hasEllipsis()) {
       // Now rewrite the body...
-      lastCatchBody = catchList->getCatchBody();
+      lastCatchBody = Catch->getCatchBody();
       SourceLocation bodyLoc = lastCatchBody->getLocStart();
       const char *bodyBuf = SM->getCharacterData(bodyLoc);
-      assert(*SM->getCharacterData(catchList->getRParenLoc()) == ')' &&
+      assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' &&
              "bogus @catch paren location");
       assert((*bodyBuf == '{') && "bogus @catch body location");
 
@@ -1923,8 +1923,8 @@
         }
       }
       // Now rewrite the body...
-      lastCatchBody = catchList->getCatchBody();
-      SourceLocation rParenLoc = catchList->getRParenLoc();
+      lastCatchBody = Catch->getCatchBody();
+      SourceLocation rParenLoc = Catch->getRParenLoc();
       SourceLocation bodyLoc = lastCatchBody->getLocStart();
       const char *bodyBuf = SM->getCharacterData(bodyLoc);
       const char *rParenBuf = SM->getCharacterData(rParenLoc);
@@ -1937,8 +1937,6 @@
     } else {
       assert(false && "@catch rewrite bug");
     }
-    // make sure all the catch bodies get rewritten!
-    catchList = catchList->getNextCatchStmt();
   }
   // Complete the catch list...
   if (lastCatchBody) {

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Fri Apr 23 17:50:49 2010
@@ -1509,7 +1509,7 @@
     Diag(Tok, diag::err_expected_lbrace);
     return StmtError();
   }
-  OwningStmtResult CatchStmts(Actions);
+  StmtVector CatchStmts(Actions);
   OwningStmtResult FinallyStmt(Actions);
   ParseScope TryScope(this, Scope::DeclScope);
   OwningStmtResult TryBody(ParseCompoundStatementBody());
@@ -1564,9 +1564,14 @@
           Diag(Tok, diag::err_expected_lbrace);
         if (CatchBody.isInvalid())
           CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
-        CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
-                        RParenLoc, FirstPart, move(CatchBody),
-                        move(CatchStmts));
+        
+        OwningStmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc,
+                                                              RParenLoc, 
+                                                              FirstPart, 
+                                                              move(CatchBody));
+        if (!Catch.isInvalid())
+          CatchStmts.push_back(Catch.release());
+        
       } else {
         Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
           << "@catch clause";
@@ -1595,7 +1600,9 @@
     Diag(atLoc, diag::err_missing_catch_finally);
     return StmtError();
   }
-  return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts),
+  
+  return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), 
+                                    move_arg(CatchStmts),
                                     move(FinallyStmt));
 }
 

Modified: cfe/trunk/lib/Sema/JumpDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/JumpDiagnostics.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/JumpDiagnostics.cpp (original)
+++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp Fri Apr 23 17:50:49 2010
@@ -155,8 +155,8 @@
         BuildScopeInformation(TryPart, Scopes.size()-1);
 
       // Jump from the catch to the finally or try is not valid.
-      for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC;
-           AC = AC->getNextCatchStmt()) {
+      for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
+        ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
         Scopes.push_back(GotoScope(ParentScope,
                                    diag::note_protected_by_objc_catch,
                                    AC->getAtCatchLoc()));

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Apr 23 17:50:49 2010
@@ -1675,15 +1675,15 @@
 
   virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
                                                 SourceLocation RParen,
-                                                DeclPtrTy Parm, StmtArg Body,
-                                                StmtArg CatchList);
+                                                DeclPtrTy Parm, StmtArg Body);
 
   virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
                                                   StmtArg Body);
 
   virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
                                               StmtArg Try,
-                                              StmtArg Catch, StmtArg Finally);
+                                              MultiStmtArg Catch, 
+                                              StmtArg Finally);
 
   virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc,
                                                 ExprArg Throw);

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri Apr 23 17:50:49 2010
@@ -1526,8 +1526,7 @@
 Action::OwningStmtResult
 Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
                            SourceLocation RParen, DeclPtrTy Parm,
-                           StmtArg Body, StmtArg catchList) {
-  Stmt *CatchList = catchList.takeAs<Stmt>();
+                           StmtArg Body) {
   ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>());
 
   // PVD == 0 implies @catch(...).
@@ -1544,9 +1543,8 @@
                        diag::err_illegal_qualifiers_on_catch_parm));
   }
 
-  ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen,
-    PVD, Body.takeAs<Stmt>(), CatchList);
-  return Owned(CatchList ? CatchList : CS);
+  return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, PVD, 
+                                             Body.takeAs<Stmt>()));
 }
 
 Action::OwningStmtResult
@@ -1556,12 +1554,14 @@
 }
 
 Action::OwningStmtResult
-Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
-                         StmtArg Try, StmtArg Catch, StmtArg Finally) {
+Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try, 
+                         MultiStmtArg CatchStmts, StmtArg Finally) {
   FunctionNeedsScopeChecking() = true;
-  return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
-                                           Catch.takeAs<Stmt>(),
-                                           Finally.takeAs<Stmt>()));
+  unsigned NumCatchStmts = CatchStmts.size();
+  return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try.takeAs<Stmt>(),
+                                     (Stmt **)CatchStmts.release(),
+                                     NumCatchStmts,
+                                     Finally.takeAs<Stmt>()));
 }
 
 Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=102221&r1=102220&r2=102221&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Apr 23 17:50:49 2010
@@ -896,9 +896,9 @@
   /// Subclasses may override this routine to provide different behavior.
   OwningStmtResult RebuildObjCAtTryStmt(SourceLocation AtLoc,
                                         StmtArg TryBody,
-                                        StmtArg Catch,
+                                        MultiStmtArg CatchStmts,
                                         StmtArg Finally) {
-    return getSema().ActOnObjCAtTryStmt(AtLoc, move(TryBody), move(Catch),
+    return getSema().ActOnObjCAtTryStmt(AtLoc, move(TryBody), move(CatchStmts),
                                         move(Finally));
   }
 
@@ -3688,12 +3688,16 @@
   if (TryBody.isInvalid())
     return SemaRef.StmtError();
   
-  // Transform the @catch statement (if present).
-  OwningStmtResult Catch(SemaRef);
-  if (S->getCatchStmts()) {
-    Catch = getDerived().TransformStmt(S->getCatchStmts());
+  // Transform the @catch statements (if present).
+  bool AnyCatchChanged = false;
+  ASTOwningVector<&ActionBase::DeleteStmt> CatchStmts(SemaRef);
+  for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) {
+    OwningStmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I));
     if (Catch.isInvalid())
       return SemaRef.StmtError();
+    if (Catch.get() != S->getCatchStmt(I))
+      AnyCatchChanged = true;
+    CatchStmts.push_back(Catch.release());
   }
   
   // Transform the @finally statement (if present).
@@ -3707,13 +3711,13 @@
   // If nothing changed, just retain this statement.
   if (!getDerived().AlwaysRebuild() &&
       TryBody.get() == S->getTryBody() &&
-      Catch.get() == S->getCatchStmts() &&
+      !AnyCatchChanged &&
       Finally.get() == S->getFinallyStmt())
     return SemaRef.Owned(S->Retain());
   
   // Build a new statement.
   return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), move(TryBody),
-                                           move(Catch), move(Finally));
+                                           move_arg(CatchStmts), move(Finally));
 }
 
 template<typename Derived>

Added: cfe/trunk/test/PCH/objc_stmts.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_stmts.h?rev=102221&view=auto
==============================================================================
--- cfe/trunk/test/PCH/objc_stmts.h (added)
+++ cfe/trunk/test/PCH/objc_stmts.h Fri Apr 23 17:50:49 2010
@@ -0,0 +1,22 @@
+/* For use with the methods.m test */
+
+ at interface A
+ at end
+
+ at interface B
+ at end
+
+ at interface TestPCH
+- (void)instMethod;
+ at end
+
+ at implementation TestPCH
+- (void)instMethod {
+  @try {
+  } @catch(A *a) {
+  } @catch(B *b) {
+  } @catch(...) {
+  } @finally {
+  }
+}
+ at end

Added: cfe/trunk/test/PCH/objc_stmts.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_stmts.m?rev=102221&view=auto
==============================================================================
--- cfe/trunk/test/PCH/objc_stmts.m (added)
+++ cfe/trunk/test/PCH/objc_stmts.m Fri Apr 23 17:50:49 2010
@@ -0,0 +1,12 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %S/objc_stmts.h -emit-llvm -o - %s
+// RUN: %clang_cc1 -include %S/objc_stmts.h -ast-dump -o - %s 2>&1 | FileCheck %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x objective-c -emit-pch -o %t %S/objc_stmts.h
+// RUN: %clang_cc1 -include-pch %t -emit-llvm -o - %s 
+// RUN: %clang_cc1 -include-pch %t -ast-dump -o - %s 2>&1 | FileCheck %s
+
+// CHECK: catch parm = "A *a"
+// CHECK: catch parm = "B *b"
+// CHECK: catch all





More information about the cfe-commits mailing list