[all-commits] [llvm/llvm-project] c0a739: [ItaniumCXXABI] Add -fassume-nothrow-exception-dto...

Fangrui Song via All-commits all-commits at lists.llvm.org
Sun Nov 5 00:39:54 PDT 2023


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: c0a73918bfddc6a04a897aab57fb95e8d2da7ec0
      https://github.com/llvm/llvm-project/commit/c0a73918bfddc6a04a897aab57fb95e8d2da7ec0
  Author: Fangrui Song <i at maskray.me>
  Date:   2023-11-05 (Sun, 05 Nov 2023)

  Changed paths:
    M clang/docs/ReleaseNotes.rst
    M clang/docs/UsersManual.rst
    M clang/include/clang/Basic/DiagnosticSemaKinds.td
    M clang/include/clang/Basic/LangOptions.def
    M clang/include/clang/Driver/Options.td
    M clang/lib/CodeGen/ItaniumCXXABI.cpp
    M clang/lib/Driver/ToolChains/Clang.cpp
    M clang/lib/Sema/SemaExprCXX.cpp
    M clang/test/CodeGenCXX/eh.cpp
    M clang/test/CodeGenCXX/exceptions.cpp
    M clang/test/CodeGenCoroutines/coro-cleanup.cpp
    M clang/test/Driver/clang-exception-flags.cpp
    A clang/test/SemaCXX/assume-nothrow-exception-dtor.cpp

  Log Message:
  -----------
  [ItaniumCXXABI] Add -fassume-nothrow-exception-dtor to assume that all exception objects' destructors are non-throwing

Link: https://lists.llvm.org/pipermail/cfe-dev/2021-August/068740.html ("[Exception Handling] Could we mark __cxa_end_catch as nounwind conditionally?"
Link: https://github.com/llvm/llvm-project/issues/57375

A catch handler calls `__cxa_begin_catch` and `__cxa_end_catch`. For a catch-all
clause or a catch clause matching a record type, we:

* assume that the exception object may have a throwing destructor
* emit `invoke void @__cxa_end_catch` (as the call is not marked as the `nounwind` attribute).
* emit a landing pad to destroy local variables and call `_Unwind_Resume`

```
struct A { ~A(); };
struct B { int x; };
void opaque();
void foo() {
  A a;
  try { opaque(); } catch (...) { } // the exception object has an unknown type and may throw
  try { opaque(); } catch (B b) { } // B::~B is nothrow, but we do not utilize this
}
```

Per C++ [dcl.fct.def.coroutine], a coroutine's function body implies a `catch (...)`.
Our code generation pessimizes even simple code, like:
```
UserFacing foo() {
  A a;
  opaque();
  co_return;
  // For `invoke void @__cxa_end_catch()`, the landing pad destroys the
  // promise_type and deletes the coro frame.
}
```

Throwing destructors are typically discouraged. In many environments, the
destructors of exception objects are guaranteed to never throw, making our
conservative code generation approach seem wasteful.

Furthermore, throwing destructors tend not to work well in practice:

* GCC does not emit call site records for the region containing `__cxa_end_catch`. This has been a long time, since 2000.
* If a catch-all clause catches an exception object that throws, both GCC and Clang using libstdc++ leak the allocated exception object.

To avoid code generation pessimization, add an opt-in driver option
-fassume-nothrow-exception-dtor to assume that `__cxa_end_catch` calls have the
`nounwind` attribute. This implies that thrown exception objects' destructors
will never throw.

To detect misuses, diagnose throw expressions with a potentially-throwing
destructor. Technically, it is possible that a potentially-throwing destructor
never throws when called transitively by `__cxa_end_catch`, but these cases seem
rare enough to justify a relaxed mode.

Reviewed By: ChuanqiXu

Differential Revision: https://reviews.llvm.org/D108905




More information about the All-commits mailing list