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).



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102221 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-04-23 22:50:49 +00:00
Родитель ec951e0c2f
Коммит 8f5e3dd32e
17 изменённых файлов: 324 добавлений и 168 удалений

Просмотреть файл

@ -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,49 +153,93 @@ 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; }
/// \brief Retrieve the @try body.
const Stmt *getTryBody() const { return getStmts()[0]; }
Stmt *getTryBody() { return getStmts()[0]; }
void setTryBody(Stmt *S) { getStmts()[0] = S; }
const ObjCAtCatchStmt *getCatchStmts() const {
return dyn_cast_or_null<ObjCAtCatchStmt>(SubStmts[CATCH]);
/// \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) {
assert(HasFinally && "@try does not have a @finally slot!");
getStmts()[1 + NumCatchStmts] = S;
}
void setFinallyStmt(Stmt *S) { SubStmts[FINALLY] = S; }
virtual SourceRange getSourceRange() const {
return SourceRange(AtTryLoc, SubStmts[TRY]->getLocEnd());
}
virtual SourceRange getSourceRange() const;
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtTryStmtClass;

Просмотреть файл

@ -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();
}

Просмотреть файл

@ -392,26 +392,53 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
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);
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);
}
while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
AtCatchList = NextCatch;
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);
}
AtCatchList->SubExprs[NEXT_CATCH] = this;
}
AtCatchLoc = atCatchLoc;
RParenLoc = rparenloc;
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

Просмотреть файл

@ -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 << " ";

Просмотреть файл

@ -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())

Просмотреть файл

@ -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()));

Просмотреть файл

@ -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()));
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()));
// 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;
}
// 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);
}
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);
}
}
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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));
}

Просмотреть файл

@ -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()));

Просмотреть файл

@ -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);

Просмотреть файл

@ -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>()));
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,

Просмотреть файл

@ -896,9 +896,9 @@ public:
/// 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 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
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 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) {
// 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>

22
test/PCH/objc_stmts.h Normal file
Просмотреть файл

@ -0,0 +1,22 @@
/* For use with the methods.m test */
@interface A
@end
@interface B
@end
@interface TestPCH
- (void)instMethod;
@end
@implementation TestPCH
- (void)instMethod {
@try {
} @catch(A *a) {
} @catch(B *b) {
} @catch(...) {
} @finally {
}
}
@end

12
test/PCH/objc_stmts.m Normal file
Просмотреть файл

@ -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