https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96985
Bug ID: 96985 Summary: c++ `noexcept` is ignored for *known* functions Product: gcc Version: 9.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: sagebar at web dot de Target Milestone: --- g++ has a list of *special* function names that it recognizes as builtins. This includes things like `memcpy` or `strlen`. The problem is that this list includes information about a function being nothrow/noexcept, too, and there doesn't seem to be any way of preventing g++ from compiling/generating code based on these assumptions, even if they violate a previous, explicit declaration, and even when "-ffreestanding -fno-builtin" is passed on the commandline. See the following (compile as `g++ -ffreestanding -fno-builtin`): ``` extern "C" { extern void *cpymem(void *, void const *, unsigned long) noexcept(false); extern void *memcpy(void *, void const *, unsigned long) noexcept(false); } /* extern "C" */ static_assert(!noexcept(cpymem(0, 0, 0))); static_assert(!noexcept(memcpy(0, 0, 0))); ``` The second static_assertion (the one for `memcpy`) fails because despite asking g++ to compile without any assumptions in regards to *known* functions (-ffreestanding), it still makes use of its builtin assumptions regarding a function named `memcpy()`. (Note: I know the `noexcept(false)` are redundant, but they're there to emphasize my point) Work-around: ``` #define STRINGIFY2(x) #x #define STRINGIFY(x) STRINGIFY2(x) extern "C++" { extern void *memcpy(void *, void const *, unsigned long) __asm__(STRINGIFY(__USER_LABEL_PREFIX__) "memcpy"); } /* extern "C++" */ static_assert(!noexcept(memcpy(0, 0, 0))); ``` I assume this works because only functions with extern-c linkage are considered candidates for builtin functions, so declaring as extern-c++ and assigning the proper asm-name for extern-c manually, bypasses the is-a-builtin detector entirely. Proposed solution / expected behavior: - gcc/g++ should disregard whatever it believes to be the case in regards to nothrow/noexcept for any *known* function when `-ffreestanding` or `-fno-builtin` are given. - Similarly, when `-fnon-call-exceptions` is given, gcc/g++ should assume that the library variant of any of its builtin functions may throw an exception (example: `memcpy()` can trigger SIGSEGV) - iow: Handle `-fnon-call-exceptions` the same as `-ffreestanding` / `-fno-builtin` in regards to nothrow/noexcept