Call __cxa_begin_catch with the current exception before
authorJohn McCall <rjmccall@apple.com>
Tue, 12 Feb 2013 03:51:46 +0000 (03:51 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 12 Feb 2013 03:51:46 +0000 (03:51 +0000)
calling std::terminate().  rdar://11904428

llvm-svn: 174940

clang/lib/CodeGen/CGException.cpp
clang/test/CXX/except/except.spec/p9-noexcept.cpp
clang/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
clang/test/CodeGenCXX/exceptions.cpp
clang/test/CodeGenCXX/nrvo.cpp

index b232925..8dced63 100644 (file)
@@ -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<llvm::Function>(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.
index 7c8d0ef..0e592ce 100644 (file)
@@ -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)
index de739d0..e909f03 100644 (file)
@@ -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) {
index 06003c0..f972728 100644 (file)
@@ -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);
   }
 
index 8ff7dd7..3d4b6f9 100644 (file)
@@ -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
 
 }