forked from OSchip/llvm-project
Teach function-try-blocks on constructors and destructors to implicitly
rethrow. Fixes rdar://problem/7696603 llvm-svn: 107757
This commit is contained in:
parent
3956106543
commit
b609d3f5f9
|
@ -606,11 +606,9 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
|
|||
|
||||
// Enter the function-try-block before the constructor prologue if
|
||||
// applicable.
|
||||
CXXTryStmtInfo TryInfo;
|
||||
bool IsTryBody = (Body && isa<CXXTryStmt>(Body));
|
||||
|
||||
if (IsTryBody)
|
||||
TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body));
|
||||
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
|
||||
|
||||
EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
|
||||
|
||||
|
@ -631,7 +629,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
|
|||
PopCleanupBlocks(CleanupDepth);
|
||||
|
||||
if (IsTryBody)
|
||||
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo);
|
||||
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
|
||||
}
|
||||
|
||||
/// EmitCtorPrologue - This routine generates necessary code to initialize
|
||||
|
@ -671,11 +669,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
|
|||
// anything else --- unless we're in a deleting destructor, in which
|
||||
// case we're just going to call the complete destructor and then
|
||||
// call operator delete() on the way out.
|
||||
CXXTryStmtInfo TryInfo;
|
||||
bool isTryBody = (DtorType != Dtor_Deleting &&
|
||||
Body && isa<CXXTryStmt>(Body));
|
||||
if (isTryBody)
|
||||
TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body));
|
||||
EnterCXXTryStmt(*cast<CXXTryStmt>(Body), true);
|
||||
|
||||
// Emit the destructor epilogue now. If this is a complete
|
||||
// destructor with a function-try-block, perform the base epilogue
|
||||
|
@ -742,7 +739,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
|
|||
|
||||
// Exit the try if applicable.
|
||||
if (isTryBody)
|
||||
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo);
|
||||
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
|
||||
}
|
||||
|
||||
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
|
||||
|
|
|
@ -563,13 +563,12 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) {
|
|||
}
|
||||
|
||||
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
|
||||
CXXTryStmtInfo Info = EnterCXXTryStmt(S);
|
||||
EnterCXXTryStmt(S);
|
||||
EmitStmt(S.getTryBlock());
|
||||
ExitCXXTryStmt(S, Info);
|
||||
ExitCXXTryStmt(S);
|
||||
}
|
||||
|
||||
CodeGenFunction::CXXTryStmtInfo
|
||||
CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S) {
|
||||
void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
|
||||
unsigned NumHandlers = S.getNumHandlers();
|
||||
EHCatchScope *CatchScope = EHStack.pushCatch(NumHandlers);
|
||||
|
||||
|
@ -593,8 +592,6 @@ CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S) {
|
|||
CatchScope->setCatchAllHandler(I, Handler);
|
||||
}
|
||||
}
|
||||
|
||||
return CXXTryStmtInfo();
|
||||
}
|
||||
|
||||
/// Check whether this is a non-EH scope, i.e. a scope which doesn't
|
||||
|
@ -1103,8 +1100,7 @@ static void BeginCatch(CodeGenFunction &CGF,
|
|||
CGF.EmitLocalBlockVarDecl(*CatchParam, &InitCatchParam);
|
||||
}
|
||||
|
||||
void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
|
||||
CXXTryStmtInfo TryInfo) {
|
||||
void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
|
||||
unsigned NumHandlers = S.getNumHandlers();
|
||||
EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
|
||||
assert(CatchScope.getNumHandlers() == NumHandlers);
|
||||
|
@ -1123,6 +1119,12 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
|
|||
if (HaveInsertPoint())
|
||||
Builder.CreateBr(ContBB);
|
||||
|
||||
// Determine if we need an implicit rethrow for all these catch handlers.
|
||||
bool ImplicitRethrow = false;
|
||||
if (IsFnTryBlock)
|
||||
ImplicitRethrow = isa<CXXDestructorDecl>(CurCodeDecl) ||
|
||||
isa<CXXConstructorDecl>(CurCodeDecl);
|
||||
|
||||
for (unsigned I = 0; I != NumHandlers; ++I) {
|
||||
llvm::BasicBlock *CatchBlock = Handlers[I].Block;
|
||||
EmitBlock(CatchBlock);
|
||||
|
@ -1137,6 +1139,14 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
|
|||
// Initialize the catch variable and set up the cleanups.
|
||||
BeginCatch(*this, C);
|
||||
|
||||
// If there's an implicit rethrow, push a normal "cleanup" to call
|
||||
// _cxa_rethrow. This needs to happen before _cxa_end_catch is
|
||||
// called.
|
||||
if (ImplicitRethrow) {
|
||||
CleanupBlock Rethrow(*this, NormalCleanup);
|
||||
EmitCallOrInvoke(getReThrowFn(*this), 0, 0);
|
||||
}
|
||||
|
||||
// Perform the body of the catch.
|
||||
EmitStmt(C->getHandlerBlock());
|
||||
|
||||
|
|
|
@ -1102,9 +1102,8 @@ public:
|
|||
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
|
||||
|
||||
llvm::Constant *getUnwindResumeOrRethrowFn();
|
||||
struct CXXTryStmtInfo {};
|
||||
CXXTryStmtInfo EnterCXXTryStmt(const CXXTryStmt &S);
|
||||
void ExitCXXTryStmt(const CXXTryStmt &S, CXXTryStmtInfo Info);
|
||||
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
|
||||
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
|
||||
|
||||
void EmitCXXTryStmt(const CXXTryStmt &S);
|
||||
|
||||
|
|
|
@ -193,3 +193,30 @@ namespace test8 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor function-try-block must rethrow on fallthrough.
|
||||
// rdar://problem/7696603
|
||||
namespace test9 {
|
||||
void opaque();
|
||||
|
||||
struct A { A(); };
|
||||
|
||||
// CHECK: define void @_ZN5test91AC1Ev
|
||||
// CHECK: call void @_ZN5test91AC2Ev
|
||||
// CHECK-NEXT: ret void
|
||||
|
||||
// CHECK: define void @_ZN5test91AC2Ev(
|
||||
A::A() try {
|
||||
// CHECK: invoke void @_ZN5test96opaqueEv()
|
||||
opaque();
|
||||
} catch (int x) {
|
||||
// CHECK: call i8* @__cxa_begin_catch
|
||||
// CHECK: invoke void @_ZN5test96opaqueEv()
|
||||
// CHECK: invoke void @__cxa_rethrow()
|
||||
opaque();
|
||||
}
|
||||
|
||||
// landing pad from first call to invoke
|
||||
// CHECK: call i8* @llvm.eh.exception
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue