https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94357
Bug ID: 94357 Summary: Inline assembly with memory operand is considered nothrow with `-fnon-call-exceptions` Product: gcc Version: 9.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- Created attachment 48130 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=48130&action=edit Issue demonstration The documentation of `-fnon-call-exceptions` (https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fnon-call-exceptions) states that any instruction with a "memory references" is allowed to throw a c++ exception (or in other words: do what essentially boils down to performing a CFI unwind, and calling `__gxx_personality_v0()` without that function calling `std::terminate()` because the faulting PC isn't allowed to trap) However, from what I can tell by looking at the GCC sources (gcc/tree-eh.c:tree_could_trap_p(); case ASM_EXPR), GCC only considers an `asm()` statement as being able to cause a non-call-exception (i.e. trap) when written as `asm volatile()`. Given the fact that "memory references" is listed as one of the possible reasons for an instruction to be trapable, it stands reason that any inline assembly statement that uses memory operands (i.e. `asm("..." : "=m" (...))` or `asm("..." : : "m" (...))`), as well as any assembly statement that specifies "memory" as part of its clobber list (i.e. `asm("..." : : : "memory")`) should also be considered as potentially containing instructions that may trap. Note also that during my investigation I've noticed that the catch(...) block is fully optimized away in the following case ... (`gcc -S` does contain `/* Hello */`, but doesn't contain `/* World! */`): ```c void foo() { try { __asm__ __volatile__("/* Hello */"); } catch (...) { __asm__("/* World! */"); } } ``` ... but isn't optimized away when the first `__asm__ __volatile__` is placed in an inline function (`gcc -S` does contains both `/* Hello */` and `/* World! */`): ```c inline void bar() { __asm__ __volatile__("/* Hello */"); } void foo() { try { bar(); } catch (...) { __asm__("/* World! */"); } } ``` The attached file shows the different cases where `__asm__` appears in `try ... catch`, and should be compiled as follows (note that -O* flags don't have any affect on which catch-statements get deleted; -O0 has the same output as -O3): $ g++ -S -x c++ -fnon-call-exceptions attaced-file.cc -o - | grep "reference" The current output is:``` call must_reference_1 ``` A consistent output (with the current rules concerning __volatile__) would look like:``` call must_reference_1 call must_reference_2 call must_reference_3 ``` And an output consistent with published documentation would look like:``` call must_reference_1 call must_reference_2 call must_reference_3 call must_reference_4 call must_reference_5 call must_reference_6 ```