yohhoyの日記

技術的メモをしていきたい日記

-fassume-nothrow-exception-dtorオプション

LLVM/Clangでは「C++例外オブジェクトのデストラクタで例外送出しないと仮定する」コンパイルオプション-fassume-nothrow-exception-dtorが提供される。こんな邪悪な例外クラスを扱うユースケースは無いだろうが、C++言語仕様上は禁止されていない。

// デストラクタで例外送出する例外オブジェクト
struct evil_exception {
  ~evil_exception() noexcept(false) { throw 42; }
};

void func()
{
  try { throw evil_exception{}; }
  catch (...) { std::puts("1st catch"); }
}

int main()
{
  try { func(); }
  catch (...) { std::puts("2nd catch"); }
}

Clangに-fassume-nothrow-exception-dtorオプション指定すると、上記evil_exceptionデストラクタはコンパイルエラーとして拒絶する。

error: cannot throw object of type 'evil_exception' with a potentially-throwing destructor

Clang 18で導入されたコンパイルオプション。

New Compiler Flags
-fassume-nothrow-exception-dtor is added to assume that the destructor of a 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.

Clang 18.1.1 Release Notes — Clang 18.1.1 documentation

-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.

Clang Compiler User’s Manual — Clang 18.1.1 documentation

おまけ

C++処理系毎に実行結果が異なる模様。いずれにせよ実用性は皆無。

GCC, Clang/libstdc++の実行結果:

1st catch
2nd catch

Clang/libc++の実行結果:

libc++abi: terminating due to uncaught exception of type int
Program terminated with signal: SIGSEGV

MSVC v19.50の実行結果:std::terminate呼び出し結果に相当する例外コード0xc0000409 STATUS_STACK_BUFFER_OVERRUNでプロセス異常終了する。*1

関連URL: