diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -232,6 +232,8 @@ preserving ``#include`` directives for "system" headers instead of copying the preprocessed text to the output. This can greatly reduce the size of the preprocessed output, which can be helpful when trying to reduce a test case. +* ``-fassume-nothrow-exception-dtor`` is added to assume that the destructor of + an thrown exception object will not throw. The generated code will be smaller. Deprecated Compiler Flags ------------------------- diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -2134,6 +2134,18 @@ new operator will always return a pointer that does not alias any other pointer when the function returns. +.. option:: -fassume-nothrow-exception-dtor + + Assume that an exception object' destructor does not throw, and generate + less code for catch handlers. + + By default, Clang assumes that the exception object may have a throwing + destructor. For the Itanium C++ ABI, Clang generates a landing pad to + destroy local variables and call ``_Unwind_Resume`` for the code + ``catch (...) { ... }``. This option tells Clang that an exception object's + destructor does not throw, even if the destructor is annotated as + ``noexcept(false)``. + .. option:: -ftrap-function=[name] Instruct code generator to emit a function call to the specified 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 @@ -1993,6 +1993,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 @@ -4505,7 +4505,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, @@ -4514,7 +4516,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 %try.cont // CHECK: invoke void @__cxa_rethrow() // CHECK: unreachable + + // CHECK: terminate.lpad: + // CHECK: 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(); @@ -68,13 +71,15 @@ // 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 +87,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"