Date: Thu, 15 Dec 2011 02:18:59 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Ed Schouten <ed@FreeBSD.org> Cc: svn-src-head@FreeBSD.org, svn-src-all@FreeBSD.org, src-committers@FreeBSD.org Subject: Re: svn commit: r228495 - head/sys/sys Message-ID: <20111214234615.B3839@besplex.bde.org> In-Reply-To: <201112140909.pBE99bS3090646@svn.freebsd.org> References: <201112140909.pBE99bS3090646@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 14 Dec 2011, Ed Schouten wrote: > Log: > Slightly alter the C1X definitions in in cdefs.h: > > - Add _Alignas(). Unfortunately this macro is only partially functional. > The C1X standard will allow both an integer and a type name to be > passed to this macro, while this macro only allows an integer. To be > portable, one must use _Alignas(_Alignof(double)) to use type names. This is still quite broken. > - Don't do _Static_assert() when __COUNTER__ is not supported. We'd > better keep this implementation robust and allow it to be used in > header files, without mysteriously breaking older compilers. Not sure about this. > Modified: head/sys/sys/cdefs.h > ============================================================================== > --- head/sys/sys/cdefs.h Wed Dec 14 08:52:27 2011 (r228494) > +++ head/sys/sys/cdefs.h Wed Dec 14 09:09:37 2011 (r228495) > @@ -222,6 +222,7 @@ > * Keywords added in C1X. > */ > #if defined(__cplusplus) && __cplusplus >= 201103L > +#define _Alignas(e) alignas(e) > #define _Alignof(e) alignof(e) > #define _Noreturn [[noreturn]] > #define _Static_assert(e, s) static_assert(e, s) > @@ -231,21 +232,23 @@ > #else > /* Not supported. Implement them manually. */ > #ifdef __GNUC__ > +#define _Alignas(e) __attribute__((__aligned__(e))) This breaks versions of gcc that don't have __attribute__ or __aligned__. Elsewhere in the same file, use of __attribute__ is restricted starting with the condition: #if __GNUC__ == 2 && __GNUC_MINOR__ >= 5 && __GNUC_MINOR__ < 7 && \ !defined(__INTEL_COMPILER) (this actually gives the starting point for 2 attributes, with many necessary and unnecessary convolutions -- see below). and use of __aligned__ is carefully restricted by the condition #if __GNUC_PREREQ__(2, 7) || defined(__INTEL_COMPILER) (now it starts with gcc-2.7 where the above starts with gcc-2.5, since __aligned__ apparently wasn't in the original set of attributes). The other places give a definition of __aligned() that can almost be used here. There is a bogus one for lint and a duplicate one for __INTEL_COMPILER. But there is none for !__GNUC_PREREQ__(2, 7) && !__INTEL_COMPILER. That is, all cases where the compiler is either gcc-before-2.6, or non-gcc other than lint and icc, are already broken. > #define _Alignof(e) __alignof__(e) This one mainly has a style bug. __alignof__ would be be spelled __alignof if this were FreeBSD code. gcc has accepted all of alignof(), __alignof() and __alignof__() for a long time. I checked this for some gccs back to gcc-2.95.4. It might even work for gcc-1. FreeBSD uses the extra trailing underscores for __attribute__(()) and individual attributes because unlike for __alignof() and __typeof(), gcc used to require them and changing this now would give style bugs. gcc-4.2.1 accepts the __aligned__ attribute, but gcc-3.3.3 doesn't. I don't know when __attribute(()) started working. I checked it for some gccs back to gcc-2.95.4, and all accepted it. > #define _Noreturn __attribute__((__noreturn__)) Elsewhere in this file, the __noreturn__ attribute is handled like the __aligned__ attribute, but more carefully, with many style bugs but no bugs as far as I can see: - For lint, the macro that uses it (__dead2) is bogusly defined as nothing. I thought that lint bogusly defines __GNUC__, but can't find this now. Lint should not define __GNUC__ since it only supports a tiny subsets of gcc features like __attribute__(), even with -g. If lint defined __GNUC__, then the extra ifdef for it would be be justified for some of the macros including __dead2/_Noreturn, since __dead2 has no semantic effect so it is safe to make it null for compilers that don't support it. If lint doesn't define __GNUC__ then for __dead2 and now hopefully for _Noreturn, an extra ifdef is not needed since lint is given a null definition in the section for nondescript non-gcc compilers. - For non-gcc, or gcc < 2.5, and not icc, __dead2 is defined as nothing under the condition: #if !__GNUC_PREREQ__(2, 5) && !defined(__INTEL_COMPILER) - For gcc-2.5 and gcc-2.6, and icc, __attribute__((__noreturn__)) is used to define __dead2 under the condition: #if __GNUC__ == 2 && __GNUC_MINOR__ >= 5 && __GNUC_MINOR__ < 7 && \ !defined(__INTEL_COMPILER) Note the style bug in this condition (it doesn't use GNUC_PREREQ()). - For gcc >= 2.7, the definition of __dead2 is duplicated under the condition: #if __GNUC_PREREQ(2, 7) - For icc, the definition of __dead2 is duplicated yet again, under the condition: #if defined(__INTEL_COMPILER) Note the style bug in this (defined() when ifdef would do). There are 2 other definitions under the gcc-2.5, gcc-2.6, or icc ifdef. Only the one for __unused belongs there, since its attribute is new in gcc-2.7. The others should be define without duplication for gcc >= 2.5. Under the the gcc >= 2.7 and separate icc condition, there are definitions to use 7 attributes. All of these have style bugs or worse: - __noreturn__ attribute. Shouldn't be duplicated. - __const__ attribute. Shouldn't be duplicated. - __unused__ attribute. May actually be correct. - __used__ attribute. Doesn't belong here, since it is much newer than gcc-2.7. It is in gcc-3.3.3 but not in gcc-3.2.2. - __packed__ attribute. Not defined for older gcc. - __aligned__ attribute. Not defined for older gcc. - __section attribute. Not defined for older gcc. These definitions have lots more of bugs: - random order - all duplicated verbatim for icc. > #define _Thread_local __thread This has similar problems. __thread doesn't work for at least gcc-2.95.4 and gcc-3.2.2, but works (compiles at least) for gcc-3.3.3. > #else > +#define _Alignas(e) > #define _Alignof(e) __offsetof(struct { char __a; e __b; }, __b) > #define _Noreturn > #define _Thread_local > #endif _Alignas() can be defined in terms of __align() for all cases without repeating the ifdefs, after fixing old bugs for __align(). _Noreturn can't be handled so simply. Its use has syntactic differences. I have already complained about using it in <stdlib.h> breaking portability in a critical header. All these messy ifdefs here are just obfuscations if they don't work for <stdlib.h>. After writing the above and running some more tests, the limits of the breakage are clearer: - the __noreturn__ attribute is apparently new in gcc-2.5. Before that, the old __pure macro presumably worked. __pure was implemented as __volatile, and has the same syntax as C1x _Noreturn (it must be before the function name). - the __noreturn__ attribute (and presumably other attributes) is a syntax errors if it is used before a function name (presumably the same for before a variable name) in gcc-2.95.4. It works before a function name in gcc-3.2.2. Thus to work with all compilers that it used to work with, <stdlib.h> must either use only __dead2 after function names like it used to, or if it wants to use _Noreturn then it must use both _Noreturn before function names (to support newer compilers) and __dead2 after function names (to support older compilers), and _Noreturn must be more carefully ifdefed here. There are the following compilers and ranges of compilers: - not gcc and not icc and not clang: both macros null - icc: hopefully like newer gcc - clang: hopefully like newer gcc - gcc-1: like gcc-2.early - gcc-2.early: define __dead2 as null; define _Noreturn as either __volatile (to bring back the special support for gcc-1 that I deprecated in 1996 and removed in 1998) or define _Noreturn as null (to preserve the removal, so that gcc-2.early is treated as a nondescript compiler). _Noreturn restores the syntax differences that made the gcc-2.early support touch much more than <sys/cdefs.h>. Now we have the syntax differences in another way, so restoring the gcc-2.early support only takes 1 line. - gcc-2.5 through gcc-3.2.2 or a little earlier: must define _Noreturn as null, and to restore functionality in <stdlib.h>, restore the uses of __dead2 there. Don't forget to fix the new style bugs there (see the 4.4BSD version for normal style with directives before function names). - post gcc-3.2.2: can define _Noreturn as non-null and __dead2 as null, or vice versa, or both non-null. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20111214234615.B3839>