diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -37,6 +37,7 @@ CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments. CODEGENOPT(AssumeSaneOperatorNew , 1, 1) ///< implicit __attribute__((malloc)) operator new CODEGENOPT(AssumeUniqueVTables , 1, 1) ///< Assume a class has only one vtable. +CODEGENOPT(AssumeNothrowExceptionDtor , 1, 0) ///< Assume __cxa_end_catch is nothrow. CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink CODEGENOPT(AutoImport , 1, 1) ///< -fno-auto-import CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1988,6 +1988,10 @@ Visibility<[ClangOption, CC1Option]>, HelpText<"Enable support for ignoring exception handling constructs">, MarshallingInfoFlag>; +defm assume_nothrow_exception_dtor: BoolFOption<"assume-nothrow-exception-dtor", + CodeGenOpts<"AssumeNothrowExceptionDtor">, DefaultFalse, + PosFlag, + NegFlag>; def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group, Visibility<[ClangOption, CLOption]>, HelpText<"Allows control over excess precision on targets where native " diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -4508,7 +4508,9 @@ } /// Emits a call to __cxa_begin_catch and enters a cleanup to call -/// __cxa_end_catch. +/// __cxa_end_catch. If -fassume-nothrow-exception-dtor is specified, we assume +/// that the exception object's dtor is nothrow, therefore the __cxa_end_catch +/// call can be marked as nounwind even if EndMightThrow is true. /// /// \param EndMightThrow - true if __cxa_end_catch might throw static llvm::Value *CallBeginCatch(CodeGenFunction &CGF, @@ -4517,7 +4519,9 @@ llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn); - CGF.EHStack.pushCleanup(NormalAndEHCleanup, EndMightThrow); + CGF.EHStack.pushCleanup( + NormalAndEHCleanup, + EndMightThrow && !CGF.CGM.getCodeGenOpts().AssumeNothrowExceptionDtor); return call; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -385,6 +385,9 @@ // So we do not set EH to false. Args.AddLastArg(CmdArgs, options::OPT_fignore_exceptions); + Args.addOptInFlag(CmdArgs, options::OPT_fassume_nothrow_exception_dtor, + options::OPT_fno_assume_nothrow_exception_dtor); + if (EH) CmdArgs.push_back("-fexceptions"); return EH; diff --git a/clang/test/CodeGenCXX/eh.cpp b/clang/test/CodeGenCXX/eh.cpp --- a/clang/test/CodeGenCXX/eh.cpp +++ b/clang/test/CodeGenCXX/eh.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.13.99 -std=c++11 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=UNALIGNED %s -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.14 -std=c++11 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ALIGNED %s +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.13.99 -std=c++11 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,UNALIGNED,THROWEND %s +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.14 -std=c++11 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,ALIGNED,THROWEND %s +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-macosx10.14 -std=c++11 -emit-llvm -o - %s -fassume-nothrow-exception-dtor | FileCheck --check-prefixes=CHECK,ALIGNED,NOTHROWEND %s struct test1_D { double d; @@ -218,13 +219,16 @@ } catch (B a) { // CHECK: call ptr @__cxa_begin_catch // CHECK-NEXT: call void @llvm.memcpy - // CHECK-NEXT: invoke void @__cxa_end_catch() + // THROWEND-NEXT: invoke void @__cxa_end_catch() + // NOTHROWEND-NEXT: call void @__cxa_end_catch() [[NUW]] } catch (...) { // CHECK: call ptr @__cxa_begin_catch - // CHECK-NEXT: invoke void @__cxa_end_catch() + // THROWEND-NEXT: invoke void @__cxa_end_catch() + // NOTHROWEND-NEXT: call void @__cxa_end_catch() [[NUW]] } - // CHECK: call void @_ZN6test101AD1Ev( + // THROWEND: call void @_ZN6test101AD1Ev( + // NOTHROWEND-NOT: call void @_ZN6test101AD1Ev( } } diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp --- a/clang/test/CodeGenCXX/exceptions.cpp +++ b/clang/test/CodeGenCXX/exceptions.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -no-enable-noundef-analysis %s -triple=x86_64-linux-gnu -emit-llvm -std=c++98 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK -check-prefix=CHECK98 %s -// RUN: %clang_cc1 -no-enable-noundef-analysis %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck -check-prefix=CHECK -check-prefix=CHECK11 %s +// RUN: %clang_cc1 -no-enable-noundef-analysis %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions | FileCheck --check-prefixes=CHECK,CHECK11,THROWEND11 %s +// RUN: %clang_cc1 -no-enable-noundef-analysis %s -triple=x86_64-linux-gnu -emit-llvm -std=c++11 -o - -fcxx-exceptions -fexceptions -fassume-nothrow-exception-dtor | FileCheck --check-prefixes=CHECK,CHECK11,NOTHROWEND11 %s // CHECK: %[[STRUCT_TEST13_A:.*]] = type { i32, i32 } @@ -479,11 +480,16 @@ // CHECK98: call void @__cxa_end_catch() // CHECK98-NEXT: br label - // CHECK11: invoke void @__cxa_end_catch() - // CHECK11-NEXT: to label + // THROWEND11: invoke void @__cxa_end_catch() + // THROWEND11-NEXT: to label %invoke.cont[[#]] unwind label %terminate.lpad + // NOTHROWEND11: call void @__cxa_end_catch() + // NOTHROWEND11-NEXT: br label // CHECK: invoke void @__cxa_rethrow() // CHECK: unreachable + + // THROWEND11: terminate.lpad: + // THROWEND11: call void @__clang_call_terminate( } // Ensure that an exception in a constructor destroys diff --git a/clang/test/CodeGenCoroutines/coro-cleanup.cpp b/clang/test/CodeGenCoroutines/coro-cleanup.cpp --- a/clang/test/CodeGenCoroutines/coro-cleanup.cpp +++ b/clang/test/CodeGenCoroutines/coro-cleanup.cpp @@ -1,5 +1,6 @@ // Verify that coroutine promise and allocated memory are freed up on exception. -// RUN: %clang_cc1 -std=c++20 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -disable-llvm-passes | FileCheck %s --check-prefixes=CHECK,THROWEND +// RUN: %clang_cc1 -std=c++20 -triple=x86_64-unknown-linux-gnu -emit-llvm -o - %s -fexceptions -fcxx-exceptions -fassume-nothrow-exception-dtor -disable-llvm-passes | FileCheck %s --check-prefixes=CHECK,NOTHROWEND namespace std { template struct coroutine_traits; @@ -49,7 +50,9 @@ // CHECK: [[DeallocPad]]: // CHECK-NEXT: landingpad // CHECK-NEXT: cleanup - // CHECK: br label %[[Dealloc:.+]] + // THROWEND: br label %[[Dealloc:.+]] + // NOTHROWEND: icmp ne ptr %[[#]], null + // NOTHROWEND-NEXT: br i1 %[[#]], label %[[Dealloc:.+]], label Cleanup cleanup; may_throw(); @@ -64,17 +67,18 @@ // CHECK-NEXT: catch ptr null // CHECK: call void @_ZN7CleanupD1Ev( // CHECK: br label %[[Catch:.+]] - // CHECK: [[Catch]]: // CHECK: call ptr @__cxa_begin_catch( // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type19unhandled_exceptionEv( - // CHECK: invoke void @__cxa_end_catch() - // CHECK-NEXT: to label %[[Cont:.+]] unwind + // THROWEND: invoke void @__cxa_end_catch() + // THROWEND-NEXT: to label %[[Cont:.+]] unwind + // NOTHROWEND: call void @__cxa_end_catch() + // NOTHROWEND-NEXT: br label %[[Cont2:.+]] - // CHECK: [[Cont]]: - // CHECK-NEXT: br label %[[Cont2:.+]] - // CHECK: [[Cont2]]: - // CHECK-NEXT: br label %[[Cleanup:.+]] + // THROWEND: [[Cont]]: + // THROWEND-NEXT: br label %[[Cont2:.+]] + // CHECK: [[Cont2]]: + // CHECK-NEXT: br label %[[Cleanup:.+]] // CHECK: [[Cleanup]]: // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_typeD1Ev( @@ -82,8 +86,8 @@ // CHECK: call void @_ZdlPv(ptr noundef %[[Mem0]] // CHECK: [[Dealloc]]: - // CHECK: %[[Mem:.+]] = call ptr @llvm.coro.free( - // CHECK: call void @_ZdlPv(ptr noundef %[[Mem]]) + // THROWEND: %[[Mem:.+]] = call ptr @llvm.coro.free( + // THROWEND: call void @_ZdlPv(ptr noundef %[[Mem]]) co_return; } diff --git a/clang/test/Driver/clang-exception-flags.cpp b/clang/test/Driver/clang-exception-flags.cpp --- a/clang/test/Driver/clang-exception-flags.cpp +++ b/clang/test/Driver/clang-exception-flags.cpp @@ -27,3 +27,6 @@ // RUN: %clang -### -target x86_64-scei-ps4 %s 2>&1 | FileCheck %s -check-prefix=PS-OFF // RUN: %clang -### -target x86_64-sie-ps5 %s 2>&1 | FileCheck %s -check-prefix=PS-OFF // PS-OFF-NOT: "-cc1" {{.*}} "-f{{(cxx-)?}}exceptions" + +// RUN: %clang -### -fexceptions -fno-assume-nothrow-exception-dtor -fassume-nothrow-exception-dtor %s 2>&1 | FileCheck %s --check-prefix=NOTHROW-DTOR +// NOTHROW-DTOR: "-cc1"{{.*}} "-fcxx-exceptions" "-fassume-nothrow-exception-dtor"