зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
ec951e0c2f
Коммит
8f5e3dd32e
|
@ -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>
|
||||
|
|
|
@ -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
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче