Hi Paul, Thanks for explaining.
> > What is the semantic difference between _Noreturn and > > __attribute_noreturn__? > > __attribute__ ((__noreturn__)), which the latter expands to, also works with > function pointers, whereas _Noreturn does not. The distinction can matter > when a > function's address is assigned to a function pointer. Clang checks for > __attribute__ ((__noreturn__)) compatibility when assigning function > pointers; > GCC does not, which can lead to weird results. For example: > > _Noreturn void nr (void) { for (;;); } > __attribute__ ((__noreturn__)) void anr (void) { for (;;); } > > /* Valid. */ > void (*a) (void) = nr; > void (*b) (void) = anr; > __attribute__ ((__noreturn__)) void (*c) (void) = anr; > > /* Invalid, as _Noreturn applies only to function definitions. */ > _Noreturn void (*d) (void) = nr; > _Noreturn void (*e) (void) = anr; > > /* Allowed by GCC, but weirdly disallowed by clang because f is not declared > with > __attribute__ ((__noreturn__)). */ > __attribute__ ((__noreturn__)) void (*f) (void) = nr; > > GCC does a better job in this area I agree with your findings. In C mode I get this: =============================================================================== void func1 (void) { for (;;); } _Noreturn void func2 (void) { for (;;); } __attribute__ ((__noreturn__)) void func3 (void) { for (;;); } void (*fptr11) (void) = func1; /* GCC: OK clang: OK */ void (*fptr12) (void) = func2; /* GCC: OK clang: OK */ void (*fptr13) (void) = func3; /* GCC: OK clang: OK */ _Noreturn void (*fptr21) (void) = func1; /* GCC: warning clang: error */ _Noreturn void (*fptr22) (void) = func2; /* GCC: warning clang: error */ _Noreturn void (*fptr23) (void) = func3; /* GCC: warning clang: error */ __attribute__ ((__noreturn__)) void (*fptr31) (void) = func1; /* GCC: warning clang: warning */ __attribute__ ((__noreturn__)) void (*fptr32) (void) = func2; /* GCC: OK clang: warning */ __attribute__ ((__noreturn__)) void (*fptr33) (void) = func3; /* GCC: OK clang: OK */ =============================================================================== In C++ mode, you have to write '[[noreturn]]' instead of _Noreturn, and GCC has a number of bugs in this area: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79604 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80495 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80496 > it's not clear that it's worth catering to clang's idiosyncracies here. I disagree: 1) If _Noreturn does not apply to function pointers, only to functions, we should better avoid it. It's an ill-defined standard's feature. 2) What you call "clang's idiosyncracies" is triggered by our inconsistent use in obstack.c: In one place we use _Noreturn, in the other place we use __attribute__ ((__noreturn__)). In fact, even the GCC documentation does not state that _Noreturn on a function is equivalent to __attribute__ ((__noreturn__)). So, at least for obstack.c, I propose to be consistent: use only __attribute__ ((__noreturn__)). 2017-04-23 Bruno Haible <br...@clisp.org> obstack: Avoid clang warning due to inconsistent use of _Noreturn. The code was assuming that _Noreturn and __attribute__((__noreturn__)) are equivalent on function definitions, which happens to be true (but undocumented) for GCC, but not for clang. * lib/obstack.c (print_and_abort): Use __attribute_noreturn__. diff --git a/lib/obstack.c b/lib/obstack.c index 1c7e069..49a846c 100644 --- a/lib/obstack.c +++ b/lib/obstack.c @@ -326,7 +326,7 @@ int obstack_exit_failure = EXIT_FAILURE; # include <libio/iolibio.h> # endif -static _Noreturn void +static __attribute_noreturn__ void print_and_abort (void) { /* Don't change any of these strings. Yes, it would be possible to add