From 59a7000a79118e4c140885ccbb2ac6a686a73092 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 7 Jul 2010 06:56:46 +0000 Subject: [PATCH] Teach function-try-blocks on constructors and destructors to implicitly rethrow. Fixes rdar://problem/7696603 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107757 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGClass.cpp | 11 ++++------- lib/CodeGen/CGException.cpp | 26 ++++++++++++++++++-------- lib/CodeGen/CodeGenFunction.h | 5 ++--- test/CodeGenCXX/eh.cpp | 27 +++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index a69a3f9566..df5ea18c0c 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -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(Body)); - if (IsTryBody) - TryInfo = EnterCXXTryStmt(*cast(Body)); + EnterCXXTryStmt(*cast(Body), true); EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin(); @@ -631,7 +629,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { PopCleanupBlocks(CleanupDepth); if (IsTryBody) - ExitCXXTryStmt(*cast(Body), TryInfo); + ExitCXXTryStmt(*cast(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(Body)); if (isTryBody) - TryInfo = EnterCXXTryStmt(*cast(Body)); + EnterCXXTryStmt(*cast(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(Body), TryInfo); + ExitCXXTryStmt(*cast(Body), true); } /// EmitDtorEpilogue - Emit all code that comes at the end of class's diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 1645e66d55..085dddd95d 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -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(*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(CurCodeDecl) || + isa(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()); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 00a0936044..3e4cd3bbe2 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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); diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp index 4d0955877d..d03dc91715 100644 --- a/test/CodeGenCXX/eh.cpp +++ b/test/CodeGenCXX/eh.cpp @@ -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) +} -- 2.40.0