The following code has different executions in O0 and O3. It looks like GCC is able to optimize the `throw s` in `test()` by calling `terminate()` directly as it knows the destructor will raise an exception: ``` terminate called after throwing an instance of 'int' Aborted ``` But without optimization, the destructor will be executed and the `set_terminate` function will hook `my_term` and the program will return 0. I'm not sure if this is a valid optimization and the original code is wrong, or if the code is valid. I've tried with various GCC version from 7.5 to 10.1.0. #include <exception> #include <unistd.h> int test ( void ); void my_term ( void ) { // only way to exit SUCCESS _exit(0); } int main(void) { test (); // unreachable return 1; } struct S1 { public: ~S1 ( ) noexcept (false) { // moving this outside of ~S1 (eg. in main()) makes the program behave // consistently for O0~O3 std::set_terminate(&my_term); // this should trigger the terminate() as we are throwing in a dtor called // during exception handling ? throw 1; }; }; int test(void) { try { int s = 0; S1 ss; // this should trigger the dtor for ss throw s; // unreachable return -1; } catch ( ... ) { // unreachable return -1; } }
[except.terminate] allows std::terminate to be called without stack unwinding in some cases, but I don't think that applies here. The standard specifically says "An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to std::terminate()." That seems to be what's happening here.
I assume the bug summary is a typo, and you meant to say "Optimization skips destructor and calls terminate directly", right?
Yes you are right, sorry. Mistake caused by previous change in the title...
Related to PR 34258 and PR 83400 . there might be a few others.