Discussion:
clang and _Noreturn
(too old to reply)
Bruno Haible
2017-04-22 12:05:59 UTC
Permalink
Raw Message
On Mac OS X 10.12 (with gcc -> clang), with CPPFLAGS=-Wall, I get this
warning:

obstack.c:351:31: warning: incompatible pointer types initializing 'void (*)(void) __attribute__((noreturn))' with an expression of type 'void (void)' [-Wincompatible-pointer-types]
__attribute_noreturn__ void (*obstack_alloc_failed_handler) (void)
^

This patch gets rid of the warning:

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


But I'm wondering: What is the semantic difference between _Noreturn and
__attribute_noreturn__?
In the "gcc -E" output, I can see that _Noreturn is present, i.e. is a keyword,
and __attribute_noreturn__ expands to __attribute__ ((__noreturn__)).

Bruno
Paul Eggert
2017-04-22 21:06:07 UTC
Permalink
Raw Message
Post by Bruno Haible
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, and it's not clear that it's worth catering
to clang's idiosyncracies here.
Bruno Haible
2017-04-23 10:45:54 UTC
Permalink
Raw Message
Hi Paul,

Thanks for explaining.
Post by Paul Eggert
Post by Bruno Haible
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;
_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
Post by Paul Eggert
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 <***@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
Paul Eggert
2017-04-23 19:06:33 UTC
Permalink
Raw Message
Post by Bruno Haible
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.
Hmm, well, we cannot avoid _Noreturn in general, since the standard requires it
for functions defined by the standard. Admittedly this incompatibility between
_Noreturn and __attribute__ ((__noreturn__)) is a pain.
Post by Bruno Haible
So, at least for obstack.c, I propose to be consistent: use only
__attribute__ ((__noreturn__)).
Although this will work for GCC and Clang, I suppose it might cause other
compilers to generate slightly-less-efficient code, because they won't know that
print_and_abort does not return. To avoid that problem, how about this further
patch? If we run into this problem elsewhere we can move the Noreturn macro to a
more-public location.

2017-04-23 Paul Eggert <***@cs.ucla.edu>

obstack: tweak noreturn for non-GCC
* lib/obstack.c (Noreturn): New macro.
(print_and_abort): Use it.

diff --git a/lib/obstack.c b/lib/obstack.c
index 49a846c..9399d4e 100644
--- a/lib/obstack.c
+++ b/lib/obstack.c
@@ -326,7 +326,18 @@ int obstack_exit_failure = EXIT_FAILURE;
# include <libio/iolibio.h>
# endif

-static __attribute_noreturn__ void
+/* Attribute for defining a function that does not return and whose
+ address can be assigned to an __attribute_noreturn__ function
+ pointer. __attribute_noreturn__ is required for compilers that
+ grok __attribute__ ((__noreturn__)) and _Noreturn might help
+ compilers that do not. */
+#if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) || 0x5110 <= __SUNPRO_C
+# define Noreturn __attribute_noreturn__
+#else
+# define Noreturn _Noreturn
+#endif
+
+static Noreturn void
print_and_abort (void)
{
/* Don't change any of these strings. Yes, it would be possible to add
Bruno Haible
2017-04-23 20:58:57 UTC
Permalink
Raw Message
Hi Paul,
Post by Paul Eggert
Although this will work for GCC and Clang, I suppose it might cause other
compilers to generate slightly-less-efficient code, because they won't know that
print_and_abort does not return.
Good point. Yes.
Post by Paul Eggert
To avoid that problem, how about this further patch?
Yes, this fits my bill too. Thanks!

Once this is in, how about generalizing it? For other uses than in the module
'obstack', I would like to have a module that one can use without #ifdef,
without surprises, and that produces best efficient code for all compilers.

It should define two macros:
1) a macro for use with function declarations and definitions only,
2) a macro for use with function pointers (variables, struct elements etc.).
1) would be the __attribute_noreturn__ that we have in obstack.h.
2) would be the 'Noreturn' that you define in obstack.c.

And a consistent naming. _GL_NORETURN_FUNC and _GL_NORETURN_FUNCPTR maybe?

Ideally, one should be able to define the same thing, in the same header file,
for C++ as well. If the compiler supports C++11 or newer, one can use
'[[noreturn]]' instead of '_Noreturn'; otherwise use an empty definition
instead of '_Noreturn'.

There is one complication, though: In C++, you cannot write
extern [[noreturn]] void foo (void);
You have to write
[[noreturn]] extern void foo (void);
or
extern void foo [[noreturn]] (void);

On the other hand, in C, the valid positions of the _Noreturn keyword are
_Noreturn extern void foo (void);
extern _Noreturn void foo (void);
extern void _Noreturn foo (void);
So, the only position that works for both C and C++ is the first one:
_GL_NORETURN_FUNC extern void foo (void);

Bruno
Paul Eggert
2017-04-23 23:35:48 UTC
Permalink
Raw Message
Post by Bruno Haible
_GL_NORETURN_FUNC extern void foo (void);
Maybe a shorter name for this usage: _GL_NORETURN, perhaps?

Don't some compilers complain if the storage class ('extern', here) is
not first? If so, I suppose we could work around that problem by
omitting the 'extern'. As I vaguely recall, the 'extern' is there only
for less-important reasons.
Bruno Haible
2017-04-24 20:38:51 UTC
Permalink
Raw Message
Hi Paul,
Post by Paul Eggert
Post by Bruno Haible
_GL_NORETURN_FUNC extern void foo (void);
Maybe a shorter name for this usage: _GL_NORETURN, perhaps?
If we want to offer a short macro name, such as _GL_NORETURN, it should
be usable in both places, function declarations and function pointers.
That is, make it an alias of _GL_NORETURN_FUNCPTR.
Post by Paul Eggert
Don't some compilers complain if the storage class ('extern', here) is
not first?
GCC and clang, at least, prefer 'extern' after '[[noreturn]]'.

Bruno
Paul Eggert
2017-04-25 01:08:18 UTC
Permalink
Raw Message
Post by Bruno Haible
Hi Paul,
Post by Paul Eggert
Post by Bruno Haible
_GL_NORETURN_FUNC extern void foo (void);
Maybe a shorter name for this usage: _GL_NORETURN, perhaps?
If we want to offer a short macro name, such as _GL_NORETURN, it should
be usable in both places, function declarations and function pointers.
That is, make it an alias of _GL_NORETURN_FUNCPTR.
But that may not work best for function definitions and declarations,
for compilers that don't support __attribute__ ((__noreturn__)).
Function pointers are relatively rare compared to function definitions
and declarations, so a short name is more-important for the latter.
Post by Bruno Haible
Post by Paul Eggert
Don't some compilers complain if the storage class ('extern', here) is
not first?
GCC and clang, at least, prefer 'extern' after '[[noreturn]]'.
Bruno
I vaguely recall problems with putting _Noreturn first, maybe for
compilers that lacked native _Noreturn. Why, for example, was this patch
made to clisp in 2011?

http://hg.code.sf.net/p/clisp/clisp/rev/c5ba2cfdd7fd?revcount=480
Bruno Haible
2017-04-25 05:26:31 UTC
Permalink
Raw Message
Hi Paul,
Post by Paul Eggert
Post by Bruno Haible
If we want to offer a short macro name, such as _GL_NORETURN, it should
be usable in both places, function declarations and function pointers.
That is, make it an alias of _GL_NORETURN_FUNCPTR.
...
Function pointers are relatively rare compared to function definitions
and declarations, so a short name is more-important for the latter.
When designing the naming conventions in an API, it's better ignore which
parts of the API will be used frequently or rarely. Better think only at
how easy it is to remember each item.

I buy "frequent" vs. "rare" considerations only for the function prototypes
and the implementation of an API.
Post by Paul Eggert
Post by Bruno Haible
GCC and clang, at least, prefer 'extern' after '[[noreturn]]'.
I vaguely recall problems with putting _Noreturn first, maybe for
compilers that lacked native _Noreturn. Why, for example, was this patch
made to clisp in 2011?
http://hg.code.sf.net/p/clisp/clisp/rev/c5ba2cfdd7fd?revcount=480
Good point. This patch was a followup of
http://hg.code.sf.net/p/clisp/clisp/rev/84e10af84db9
I guess I need to test things with some older versions of gcc and g++ as well,
and with MSVC, before we can jump to conclusions.

Bruno
Paul Eggert
2017-04-25 07:49:36 UTC
Permalink
Raw Message
Post by Bruno Haible
it's better ignore which
parts of the API will be used frequently or rarely. Better think only at
how easy it is to remember each item.
Even if that's the criterion, I find it easier to remember "use _GL_NORETURN for
most noreturn cases, and use _GL_ATTRIBUTE_NORETURN for when you want just the
noreturn attribute" than to remember "use _GL_NORETURN_FUNC for most noreturn
cases, and use _GL_NORETURN_FUNCPTR for when you want just the noreturn
attribute". Partly, I suspect, this is because _GL_ATTRIBUTE_NORETURN follows
the naming convention that _GL_ATTRIBUTE_MALLOC etc. already use.
Bruno Haible
2017-04-26 21:48:43 UTC
Permalink
Raw Message
Hi Paul,
Post by Paul Eggert
Post by Bruno Haible
it's better ignore which
parts of the API will be used frequently or rarely. Better think only at
how easy it is to remember each item.
Even if that's the criterion, I find it easier to remember "use _GL_NORETURN for
most noreturn cases, and use _GL_ATTRIBUTE_NORETURN for when you want just the
noreturn attribute" than to remember "use _GL_NORETURN_FUNC for most noreturn
cases, and use _GL_NORETURN_FUNCPTR for when you want just the noreturn
attribute".
I disagree again. The user should not need to know about whether the macros
expand to a keyword, an attribute, or whatever. That's part of their
implementation, which is meant to be opaque.

Seems we can't agree. Therefore I won't propose a short name '_GL_NORETURN'.

Bruno

Bruno Haible
2017-04-26 18:02:13 UTC
Permalink
Raw Message
Post by Bruno Haible
I guess I need to test things with some older versions of gcc and g++ as well,
and with MSVC, before we can jump to conclusions.
Here are the results. Let 1, 2, 3, 4, 5 denote the respective positions:
XX extern void foo1 (void);
extern XX void foo2 (void);
extern void XX foo3 (void);
extern void foo4 XX (void);
extern void foo5 (void) XX;


Valid positions of _Noreturn in GCC (C mode):
1 2 3 starting with gcc 4.7

Valid positions of __attribute__((__noreturn__)) in GCC (C mode):
1 2 3 5 since 2.95.3 at least

Valid positions of __attribute__((__noreturn__)) in g++:
1 2 3 5 since 3.1 at least

Valid positions of [[noreturn]] in g++:
1 4 starting with gcc 6 or g++ -std=c++11 4.8
The positions 2 3 5 generate warnings "ignored", starting with gcc 6 or g++ -std=c++11 4.8


Valid positions of _Noreturn in clang (C mode):
1 2 3

Valid positions of __attribute__((__noreturn__)) in clang (C mode):
1 2 3 5

Valid positions of __attribute__((__noreturn__)) in clang (C++ mode):
1 2 3 5

Valid positions of [[noreturn]] in clang (C++ mode):
1 4 but only with option -std=c++11


Valid positions of __declspec(noreturn) in MSVC 15 (C mode):
1 2 3

Valid positions of __declspec(noreturn) in MSVC 15 (C++ mode):
1 2 3

Valid positions of [[noreturn]] in MSVC 15 (C++ mode):
1 4


Bruno
Loading...