// 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();
PopCleanupBlocks(CleanupDepth);
if (IsTryBody)
- ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo);
+ ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
}
/// EmitCtorPrologue - This routine generates necessary code to initialize
// 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
// 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
}
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);
CatchScope->setCatchAllHandler(I, Handler);
}
}
-
- return CXXTryStmtInfo();
}
/// Check whether this is a non-EH scope, i.e. a scope which doesn't
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);
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);
// 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());
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);
}
}
}
+
+// 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)
+}