From: John McCall Date: Tue, 12 Feb 2013 03:51:46 +0000 (+0000) Subject: Call __cxa_begin_catch with the current exception before X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=66b22771fc0a1dba598e50469f2961048e7edd55;p=clang Call __cxa_begin_catch with the current exception before calling std::terminate(). rdar://11904428 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174940 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index b2329253ec..8dced6327b 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -1516,6 +1516,65 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) { CGF.PopCleanupBlock(); } +/// In a terminate landing pad, should we use __clang__call_terminate +/// or just a naked call to std::terminate? +/// +/// __clang_call_terminate calls __cxa_begin_catch, which then allows +/// std::terminate to usefully report something about the +/// violating exception. +static bool useClangCallTerminate(CodeGenModule &CGM) { + // Only do this for Itanium-family ABIs in C++ mode. + return (CGM.getLangOpts().CPlusPlus && + CGM.getTarget().getCXXABI().isItaniumFamily()); +} + +/// Get or define the following function: +/// void @__clang_call_terminate(i8* %exn) nounwind noreturn +/// This code is used only in C++. +static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) { + llvm::FunctionType *fnTy = + llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false); + llvm::Constant *fnRef = + CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate"); + + llvm::Function *fn = dyn_cast(fnRef); + if (fn && fn->empty()) { + fn->setDoesNotThrow(); + fn->setDoesNotReturn(); + + // What we really want is to massively penalize inlining without + // forbidding it completely. The difference between that and + // 'noinline' is negligible. + fn->addFnAttr(llvm::Attribute::NoInline); + + // Allow this function to be shared across translation units, but + // we don't want it to turn into an exported symbol. + fn->setLinkage(llvm::Function::LinkOnceODRLinkage); + fn->setVisibility(llvm::Function::HiddenVisibility); + + // Set up the function. + llvm::BasicBlock *entry = + llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn); + CGBuilderTy builder(entry); + + // Pull the exception pointer out of the parameter list. + llvm::Value *exn = &*fn->arg_begin(); + + // Call __cxa_begin_catch(exn). + builder.CreateCall(getBeginCatchFn(CGM), exn)->setDoesNotThrow(); + + // Call std::terminate(). + llvm::CallInst *termCall = builder.CreateCall(getTerminateFn(CGM)); + termCall->setDoesNotThrow(); + termCall->setDoesNotReturn(); + + // std::terminate cannot return. + builder.CreateUnreachable(); + } + + return fnRef; +} + llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { if (TerminateLandingPad) return TerminateLandingPad; @@ -1533,9 +1592,16 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { getOpaquePersonalityFn(CGM, Personality), 0); LPadInst->addClause(getCatchAllValue(*this)); - llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(CGM)); - TerminateCall->setDoesNotReturn(); - TerminateCall->setDoesNotThrow(); + llvm::CallInst *terminateCall; + if (useClangCallTerminate(CGM)) { + // Extract out the exception pointer. + llvm::Value *exn = Builder.CreateExtractValue(LPadInst, 0); + terminateCall = Builder.CreateCall(getClangCallTerminateFn(CGM), exn); + } else { + terminateCall = Builder.CreateCall(getTerminateFn(CGM)); + } + terminateCall->setDoesNotReturn(); + terminateCall->setDoesNotThrow(); Builder.CreateUnreachable(); // Restore the saved insertion state. diff --git a/test/CXX/except/except.spec/p9-noexcept.cpp b/test/CXX/except/except.spec/p9-noexcept.cpp index 7c8d0ef1fb..0e592ce001 100644 --- a/test/CXX/except/except.spec/p9-noexcept.cpp +++ b/test/CXX/except/except.spec/p9-noexcept.cpp @@ -7,9 +7,10 @@ void target() noexcept // CHECK: invoke void @_Z8externalv() external(); } -// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +// CHECK: [[T0:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) // CHECK-NEXT: catch i8* null -// CHECK-NEXT: call void @_ZSt9terminatev() noreturn nounwind +// CHECK-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0 +// CHECK-NEXT: call void @__clang_call_terminate(i8* [[T1]]) noreturn nounwind // CHECK-NEXT: unreachable void reverse() noexcept(false) diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp index de739d0ad8..e909f03204 100644 --- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp +++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp @@ -29,12 +29,12 @@ delegator::delegator(bool) // CHECK: define {{.*}} @_ZN9delegatorC1Ec // CHECK: {{.*}} @_ZN9delegatorC1Eb // CHECK: void @__cxa_throw -// CHECK: void @_ZSt9terminatev +// CHECK: void @__clang_call_terminate // CHECK: {{.*}} @_ZN9delegatorD1Ev // CHECK: define {{.*}} @_ZN9delegatorC2Ec // CHECK: {{.*}} @_ZN9delegatorC2Eb // CHECK: void @__cxa_throw -// CHECK: void @_ZSt9terminatev +// CHECK: void @__clang_call_terminate // CHECK: {{.*}} @_ZN9delegatorD2Ev delegator::delegator(char) : delegator(true) { diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp index 06003c0cd6..f9727282c5 100644 --- a/test/CodeGenCXX/exceptions.cpp +++ b/test/CodeGenCXX/exceptions.cpp @@ -69,6 +69,13 @@ namespace test1 { return new A(B().x); } + // rdar://11904428 + // Terminate landing pads should call __cxa_begin_catch first. + // CHECK: define linkonce_odr hidden void @__clang_call_terminate(i8*) noinline noreturn nounwind + // CHECK-NEXT: [[T0:%.*]] = call i8* @__cxa_begin_catch(i8* %0) nounwind + // CHECK-NEXT: call void @_ZSt9terminatev() noreturn nounwind + // CHECK-NEXT: unreachable + A *d() { // CHECK: define [[A:%.*]]* @_ZN5test11dEv() // CHECK: [[ACTIVE:%.*]] = alloca i1 @@ -157,7 +164,7 @@ namespace test2 { // CHECK-NEXT: invoke void @_ZN5test21AC1Ei([[A]]* [[CAST]], i32 5) // CHECK: ret [[A]]* [[CAST]] // CHECK: invoke void @_ZN5test21AdlEPvm(i8* [[NEW]], i64 8) - // CHECK: call void @_ZSt9terminatev() + // CHECK: call void @__clang_call_terminate(i8* {{%.*}}) noreturn nounwind return new A(5); } } @@ -183,7 +190,7 @@ namespace test3 { // CHECK-NEXT: invoke void @_ZN5test31AC1Ei([[A]]* [[CAST]], i32 5) // CHECK: ret [[A]]* [[CAST]] // CHECK: invoke void @_ZN5test31AdlEPvS1_d(i8* [[NEW]], i8* [[FOO]], double [[BAR]]) - // CHECK: call void @_ZSt9terminatev() + // CHECK: call void @__clang_call_terminate(i8* {{%.*}}) noreturn nounwind return new(foo(),bar()) A(5); } diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp index 8ff7dd7d09..3d4b6f9740 100644 --- a/test/CodeGenCXX/nrvo.cpp +++ b/test/CodeGenCXX/nrvo.cpp @@ -100,9 +100,10 @@ X test2(bool B) { // CHECK-EH: resume { i8*, i32 } // %terminate.lpad: terminate landing pad. - // CHECK-EH: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-EH: [[T0:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) // CHECK-EH-NEXT: catch i8* null - // CHECK-EH-NEXT: call void @_ZSt9terminatev() + // CHECK-EH-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0 + // CHECK-EH-NEXT: call void @__clang_call_terminate(i8* [[T1]]) noreturn nounwind // CHECK-EH-NEXT: unreachable }