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

Reply via email to