MaskRay updated this revision to Diff 557976. MaskRay marked an inline comment as done. MaskRay added a comment.
remove unused err_ arguments. fix and test `throw new B` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D108905/new/ https://reviews.llvm.org/D108905 Files: clang/docs/ReleaseNotes.rst clang/docs/UsersManual.rst clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/LangOptions.def clang/include/clang/Driver/Options.td clang/lib/CodeGen/ItaniumCXXABI.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Sema/SemaExprCXX.cpp clang/test/CodeGenCXX/eh.cpp clang/test/CodeGenCXX/exceptions.cpp clang/test/CodeGenCoroutines/coro-cleanup.cpp clang/test/Driver/clang-exception-flags.cpp clang/test/SemaCXX/assume-nothrow-exception-dtor.cpp
Index: clang/test/SemaCXX/assume-nothrow-exception-dtor.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/assume-nothrow-exception-dtor.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only %s -fcxx-exceptions -fassume-nothrow-exception-dtor -verify + +namespace test1 { +template <typename T> struct A { A(); ~A(); }; +struct B { ~B() noexcept(false); }; +struct B1 : B {}; +struct B2 { B b; }; +struct C { virtual void f(); } c; +struct MoveOnly { MoveOnly(); MoveOnly(MoveOnly&&); }; +void run() { + throw A<int>(); + throw B(); // expected-error{{cannot throw object of type 'B' with a potentially-throwing destructor}} + throw new B; + throw B1(); // expected-error{{cannot throw object of type 'B1' with a potentially-throwing destructor}} + B2 b2; + throw b2; // expected-error{{cannot throw object of type 'B2' with a potentially-throwing destructor}} + throw c; + MoveOnly m; + throw m; +} +} Index: clang/test/Driver/clang-exception-flags.cpp =================================================================== --- clang/test/Driver/clang-exception-flags.cpp +++ 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" Index: clang/test/CodeGenCoroutines/coro-cleanup.cpp =================================================================== --- clang/test/CodeGenCoroutines/coro-cleanup.cpp +++ 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 <typename... T> 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; } Index: clang/test/CodeGenCXX/exceptions.cpp =================================================================== --- clang/test/CodeGenCXX/exceptions.cpp +++ 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 Index: clang/test/CodeGenCXX/eh.cpp =================================================================== --- clang/test/CodeGenCXX/eh.cpp +++ 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 -DNOTHROWEND | 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( } } @@ -391,40 +395,42 @@ // CHECK-LABEL: define{{.*}} void @_ZN6test163barEv() void bar() { - // CHECK: [[EXN_SAVE:%.*]] = alloca ptr - // CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1 - // CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]], - // CHECK-NEXT: [[EXNSLOT:%.*]] = alloca ptr - // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 - // CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1 + // THROWEND: [[EXN_SAVE:%.*]] = alloca ptr + // THROWEND-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1 + // THROWEND-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]], + // THROWEND-NEXT: [[EXNSLOT:%.*]] = alloca ptr + // THROWEND-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 + // THROWEND-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1 +#ifndef NOTHROWEND cond() ? throw B(A()) : foo(); +#endif - // CHECK-NEXT: [[COND:%.*]] = call noundef zeroext i1 @_ZN6test164condEv() - // CHECK-NEXT: store i1 false, ptr [[EXN_ACTIVE]] - // CHECK-NEXT: store i1 false, ptr [[TEMP_ACTIVE]] - // CHECK-NEXT: br i1 [[COND]], + // THROWEND-NEXT: [[COND:%.*]] = call noundef zeroext i1 @_ZN6test164condEv() + // THROWEND-NEXT: store i1 false, ptr [[EXN_ACTIVE]] + // THROWEND-NEXT: store i1 false, ptr [[TEMP_ACTIVE]] + // THROWEND-NEXT: br i1 [[COND]], - // CHECK: [[EXN:%.*]] = call ptr @__cxa_allocate_exception(i64 4) - // CHECK-NEXT: store ptr [[EXN]], ptr [[EXN_SAVE]] - // CHECK-NEXT: store i1 true, ptr [[EXN_ACTIVE]] - // CHECK-NEXT: invoke void @_ZN6test161AC1Ev(ptr {{[^,]*}} [[TEMP]]) - // CHECK: store i1 true, ptr [[TEMP_ACTIVE]] - // CHECK-NEXT: invoke void @_ZN6test161BC1ERKNS_1AE(ptr {{[^,]*}} [[EXN]], ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[TEMP]]) - // CHECK: store i1 false, ptr [[EXN_ACTIVE]] - // CHECK-NEXT: invoke void @__cxa_throw(ptr [[EXN]], + // THROWEND: [[EXN:%.*]] = call ptr @__cxa_allocate_exception(i64 4) + // THROWEND-NEXT: store ptr [[EXN]], ptr [[EXN_SAVE]] + // THROWEND-NEXT: store i1 true, ptr [[EXN_ACTIVE]] + // THROWEND-NEXT: invoke void @_ZN6test161AC1Ev(ptr {{[^,]*}} [[TEMP]]) + // THROWEND: store i1 true, ptr [[TEMP_ACTIVE]] + // THROWEND-NEXT: invoke void @_ZN6test161BC1ERKNS_1AE(ptr {{[^,]*}} [[EXN]], ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[TEMP]]) + // THROWEND: store i1 false, ptr [[EXN_ACTIVE]] + // THROWEND-NEXT: invoke void @__cxa_throw(ptr [[EXN]], - // CHECK: invoke void @_ZN6test163fooEv() - // CHECK: br label + // THROWEND: invoke void @_ZN6test163fooEv() + // THROWEND: br label - // CHECK: invoke void @_ZN6test161AD1Ev(ptr {{[^,]*}} [[TEMP]]) - // CHECK: ret void + // THROWEND: invoke void @_ZN6test161AD1Ev(ptr {{[^,]*}} [[TEMP]]) + // THROWEND: ret void - // CHECK: [[T0:%.*]] = load i1, ptr [[EXN_ACTIVE]] - // CHECK-NEXT: br i1 [[T0]] - // CHECK: [[T1:%.*]] = load ptr, ptr [[EXN_SAVE]] - // CHECK-NEXT: call void @__cxa_free_exception(ptr [[T1]]) - // CHECK-NEXT: br label + // THROWEND: [[T0:%.*]] = load i1, ptr [[EXN_ACTIVE]] + // THROWEND-NEXT: br i1 [[T0]] + // THROWEND: [[T1:%.*]] = load ptr, ptr [[EXN_SAVE]] + // THROWEND-NEXT: call void @__cxa_free_exception(ptr [[T1]]) + // THROWEND-NEXT: br label } } Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -1101,6 +1101,16 @@ << (unsigned)ExnObjAlign.getQuantity(); } } + if (!isPointer && getLangOpts().AssumeNothrowExceptionDtor) { + if (CXXDestructorDecl *Dtor = RD->getDestructor()) { + auto Ty = Dtor->getType(); + if (auto *FT = Ty.getTypePtr()->getAs<FunctionProtoType>()) { + if (!isUnresolvedExceptionSpec(FT->getExceptionSpecType()) && + !FT->isNothrow()) + Diag(ThrowLoc, diag::err_throw_object_throwing_dtor) << RD; + } + } + } return false; } Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ 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; Index: clang/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- clang/lib/CodeGen/ItaniumCXXABI.cpp +++ 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<CallEndCatch>(NormalAndEHCleanup, EndMightThrow); + CGF.EHStack.pushCleanup<CallEndCatch>( + NormalAndEHCleanup, + EndMightThrow && !CGF.CGM.getLangOpts().AssumeNothrowExceptionDtor); return call; } Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1993,6 +1993,10 @@ Visibility<[ClangOption, CC1Option]>, HelpText<"Enable support for ignoring exception handling constructs">, MarshallingInfoFlag<LangOpts<"IgnoreExceptions">>; +defm assume_nothrow_exception_dtor: BoolFOption<"assume-nothrow-exception-dtor", + LangOpts<"AssumeNothrowExceptionDtor">, DefaultFalse, + PosFlag<SetTrue, [], [ClangOption, CC1Option], "Assume that all exception objects' destructors are non-throwing">, + NegFlag<SetFalse>>; def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">, Group<f_Group>, Visibility<[ClangOption, CLOption]>, HelpText<"Allows control over excess precision on targets where native " Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -145,6 +145,7 @@ ExceptionHandlingKind::None, "exception handling") LANGOPT(IgnoreExceptions , 1, 0, "ignore exceptions") LANGOPT(ExternCNoUnwind , 1, 0, "Assume extern C functions don't unwind") +LANGOPT(AssumeNothrowExceptionDtor , 1, 0, "Assume exception object's destructor is nothrow") LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation") LANGOPT(RTTI , 1, 1, "run-time type information") LANGOPT(RTTIData , 1, 1, "emit run-time type information data") Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7980,6 +7980,8 @@ def warn_cdtor_function_try_handler_mem_expr : Warning< "cannot refer to a non-static member from the handler of a " "%select{constructor|destructor}0 function try block">, InGroup<Exceptions>; +def err_throw_object_throwing_dtor : Error< + "cannot throw object of type %0 with a potentially-throwing destructor">; let CategoryName = "Lambda Issue" in { def err_capture_more_than_once : Error< Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ 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 will not throw, and generate + less code for catch handlers. A throw expression of a type with a + potentially-throwing destructor will lead to an error. + + 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 will not throw and code simplification is possible. + .. option:: -ftrap-function=[name] Instruct code generator to emit a function call to the specified Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -232,6 +232,10 @@ 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 for catch + handlers will be smaller. A throw expression of a type with a + potentially-throwing destructor will lead to an error. Deprecated Compiler Flags -------------------------
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits