aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/StmtObjC.h127
-rw-r--r--include/clang/Parse/Action.h32
-rw-r--r--lib/AST/Stmt.cpp80
-rw-r--r--lib/AST/StmtDumper.cpp11
-rw-r--r--lib/AST/StmtPrinter.cpp7
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp7
-rw-r--r--lib/CodeGen/CGObjCMac.cpp77
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp27
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp9
-rw-r--r--lib/Frontend/RewriteObjC.cpp24
-rw-r--r--lib/Parse/ParseObjc.cpp17
-rw-r--r--lib/Sema/JumpDiagnostics.cpp4
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaStmt.cpp20
-rw-r--r--lib/Sema/TreeTransform.h20
-rw-r--r--test/PCH/objc_stmts.h22
-rw-r--r--test/PCH/objc_stmts.m12
17 files changed, 329 insertions, 173 deletions
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index 3fd8f1672d..6cb2b1f18a 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -71,30 +71,23 @@ public:
/// 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 @@ public:
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 @@ public:
/// @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]);
}
- ObjCAtCatchStmt *getCatchStmts() {
- return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
+
+ /// \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]);
}
- void setCatchStmts(Stmt *S) { SubStmts[CATCH] = S; }
-
+
+ /// \brief Set a particular catch statement.
+ void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) {
+ assert(I < NumCatchStmts && "Out-of-bounds @catch index");
+ getStmts()[I + 1] = 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;
}
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index c4ffa8be40..dd12fdfe3e 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -938,20 +938,46 @@ public:
}
// 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-@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();
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index ee4a74a612..67fd74c288 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -392,26 +392,53 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
RParenLoc = RPL;
}
-
-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(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;
+}
+
+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 @@ Stmt::child_iterator AsmStmt::child_end() {
}
// 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
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 05adc0292e..8481055b9d 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -143,6 +143,7 @@ namespace {
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::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
}
}
+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 << " ";
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index a895b63a79..3996528287 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -388,11 +388,8 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
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())
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 36162f7e5e..a248c5a1be 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -1781,11 +1781,12 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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()));
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 421136ba47..e000bd22aa 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -2646,8 +2646,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// 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 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
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);
}
}
}
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index d253654f7c..cf26b6e237 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -838,12 +838,11 @@ unsigned PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
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::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
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 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
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);
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 9a9539bb54..a0ea5c9553 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -764,7 +764,6 @@ void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
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::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
}
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;
}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index 66b8d39c70..fc674354c4 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -1861,8 +1861,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
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 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
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 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
}
}
// 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 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
} else {
assert(false && "@catch rewrite bug");
}
- // make sure all the catch bodies get rewritten!
- catchList = catchList->getNextCatchStmt();
}
// Complete the catch list...
if (lastCatchBody) {
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 7337445b64..4846dad7b0 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -1509,7 +1509,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
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 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
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 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
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));
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 1c761b9503..0694294903 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -155,8 +155,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) {
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()));
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 1065fc4fa8..e9cd6ca7d6 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1675,15 +1675,15 @@ public:
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);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index ee7cc69242..a5292efea1 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1526,8 +1526,7 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
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 @@ Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
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 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
}
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>()));
+ unsigne