Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Dec 2011 08:19:46 +1100 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        David Schultz <das@FreeBSD.org>
Cc:        svn-src-head@FreeBSD.org, svn-src-all@FreeBSD.org, src-committers@FreeBSD.org, David Chisnall <theraven@FreeBSD.org>
Subject:   Re: svn commit: r228322 - in head: include lib/libc/stdlib sys/sys
Message-ID:  <20111208071024.J2931@besplex.bde.org>
In-Reply-To: <20111207191134.GA20850@zim.MIT.EDU>
References:  <201112071525.pB7FPmkH044896@svn.freebsd.org> <20111207191134.GA20850@zim.MIT.EDU>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 7 Dec 2011, David Schultz wrote:

> On Wed, Dec 07, 2011, David Chisnall wrote:
>> Log:
>>   Implement quick_exit() / at_quick_exit() from C++11 / C1x.  Also add a
>>   __noreturn macro and modify the other exiting functions to use it.
>>
>>   The __noreturn macro, unlike __dead2, must be used BEFORE the function.
>>   This is in line with the C and C++ specifications that place _Noreturn (c1x)
>>   and [[noreturn]] (C++11) in front of the functions.  As with __dead2, this
>>   macro falls back to using the GCC attribute.
>>
>>   Unfortunately, clang currently sets the same value for the C version macro
>>   in C99 and C1x modes, so these functions are hidden by default.  At some
>>   point before 10.0, I need to go through the headers and clean up the C1x /
>>   C++11 visibility.
>
> Nice.
>
> Why not use the standard spelling, '_Noreturn'?  In pre-C1X modes,
> _Noreturn is a reserved identifier since it starts with an underscore
> and capital letter, so it's not considered namespace pollution.

There is also the __dead attribute for gcc-1 and some versions of
gcc-2.  It has the same syntax as __noreturn, since it was implemented
as `volatile' in gcc-1, and `volatile' must be in the declarator BEFORE
the function name.  This was changed in gcc-2 because it was determined
that `volatile' for a function has some defined meaning that of course
can't be the gcc-1 one.  FreeBSD introduced __dead2 for newer versions
of gcc-2 and kept __dead for a while.  __dead remains dead (reserved for
gcc-1, or perhaps anything that uses the same syntax).  Not quite
similarly for __pure.  Someone broke its reservedness by using it for
gcc-2.96+'s new __pure__ attribute, which is subtly different from
the old __pure and the current __pure2 FreeBSD macros.

NetBSD still had the old __dead and __pure, and no __dead2 or __pure2, as
late as 2005.  It still use[d] (as well as defining) __dead in a few
places, and uses a hard __attribute__((__noreturn__)) instead of
__dead2.  Sometimes both.

This change seems to break compatibility cruft related to this in the
critical header <stdlib.h>, since __Noreturn is actually used there
and replaces __dead2 and has a different syntax that might not work
with old compilers (sys/cdefs.h still has mounds of compatibility cruft
for old compilers, although this doesn't include __dead for gcc-1, and
probably mostly doesn't actually work).  Here is the change in cdefs.h:

% Index: cdefs.h
% ===================================================================
% RCS file: /home/ncvs/src/sys/sys/cdefs.h,v
% retrieving revision 1.117
% retrieving revision 1.118
% diff -u -2 -r1.117 -r1.118
% --- cdefs.h	12 Nov 2011 23:17:54 -0000	1.117
% +++ cdefs.h	7 Dec 2011 15:25:48 -0000	1.118
% @@ -219,4 +219,15 @@
%  #endif
% 
% +

Style bug (extra blank line).

% +#if defined(__cplusplus) && __cplusplus >= 201103L
% +#define	__noreturn		[[noreturn]]
% +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 201000L
% +#define	__noreturn		_Noreturn
% +#elif defined(__GNUC__)
% +#define	__noreturn		__attribute__((__noreturn__))

This assumes that all versions of gcc support the __noreturn__
attribute, and the new uses of this attribute assumes that
__attribute__(()) works BEFORE the function name when it is used
there, as it now is in <stdlib.h>.

The first assumption bogotifies the fussy ifdefs used later in cdefs.h.
__attribute__((__noreturn__)) is already used later, to define __dead2,
and this is under several ifdefs with ugly duplication:
- one for gcc-2.5 and 2.6 vs older gcc's
- one for gcc >= 2.7
- one for __INTEL_COMPILER (twisted by interaction with the ones for
   very old gcc's)
I don't trust most of the version numbers in the GNC_PREREQ()s, but
these have more chance than most of being correct since they are old
and detailed.  If they are correct, then we see that the above is
incorrect mainly for gcc-2.0 through 2.4.  gcc-1 is already fully
unsupported (except as a generic compiler).  gcc-2.0 through gcc-2.4
are old enough to unsupport, so this is mainly a style bug.

The second assumption is probably not satisfied by middle versions of
gcc-2.  IIRC, the reason for switching the syntax from __dead (placed
before the function name) to __dead2 (placed after) was that early
implementations of __attribute__() only worked if they were placed
after.  Otherwise, we would have just ifdefed another case for __dead.
I don't know when gcc fixed this.

% +#else
% +#define	__noreturn

Defaulting to nothing for a generic/unknown compiler is good, but this
combined with actually using __noreturn seems to break some previously
supported cases, in particular __INTEL_COMPILER sees a null __noreturn
for declarations in <stdlib.h> where it used to see a non-null __dead2.
Apparently it doesn't pretend to be gcc, but it supports most gcc
features so it mostly works, but it needs messy ifdefs to use these
features.  Perhaps __INTEL_COMPILER should be unsupported together
with gcc-2.  It is painful to maintain all these compatibilty ifdefs,
especially if they are required to actually work.  clang avoids most
problems in this area by claiming to be gcc-4.

% +#endif
% +
% ...

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20111208071024.J2931>