On Thu, 15 Dec 2011, Ed Schouten wrote:

Hello Bruce,

After reading through your email, I think it's best to fix things using
the following patch. Essentially it does the following:

- It makes sure __alignof() is always present, by defining it as a macro
 for GCC < 2.95.

I tested this with a K&R compiler.  It worked (since it is similar to
the fallback for offsetof() which always worked) after fixing 2 bugs
that prevented the fallback working with any compiler.

From your patch (quoted below):

| +#if !__GNUC_PREREQ__(2, 95)
| +#define      __alignof(x)    __offsetof(struct { char __a; e __b; }, __b)
| +#endif

The 2 bugs are:
1. Even __offsetof() is broken in the fallback case (that's all cases
   where it uses a struct like the above and doesn't use a gccish builtin).
   This is because __offsetof() uses size_t, but size_t is not necessarily
   in declared.  offsetof() in <stddef.h>, etc. works because size_t is
   necessarily declared there.  BTW, the ifdef for __offsetof in
   <stddef.h> is bogus since <sys/cdefs.h> is always included so
   __offsetof is always defined.

   __size_t could be used, but that would give lots of pollution for
   cdefs.h, and the file that declares __size_t, namely
   <machine/types.h> is broken in fallback cases:
   - recently broken for K&R since it now uses signed instead of __signed
   - broken for longer for K&R and C90 since it uses long long.  In working
     versions, the __int64_t declarations were hacked for 32-bit machines
     on to make them compile (but not work).  Non-hacked versions should
     simply not declare the 64-bit types if the compiler doesn't support
     them.
2. The macro parameter x is now mispelled, so it is never used, and the
   non-misspelled macro parameter e gives a syntax error when it is
   used in the macro body.

Test program:

% #include <sys/cdefs.h>
% % typedef unsigned size_t; /* XXX */ % % #define __alignof(e) __offsetof(struct { char __a; e __b; }, __b) % % int c = __alignof(char);
% int s = __alignof(short);
% int i = __alignof(int);
% int l = __alignof(long);
% int f = __alignof(float);
% int d = __alignof(double);

Fixes:
1. Just a hack to make __offsetof() work.  I don't know a good way to
   declare __size_t.  Of course, size_t should not be used.
2. Change the spelling back to e.  I prefer x, but all the other
   definitions use e.

- All the C1X macros can now be implemented using the ones we already
 had (__dead2, etc). This means we don't need to repeat all the
 compiler version specific checks.
- While there, add struct __hack to the _Static_assert, as it always
 requires a semicolon.

Good.

| Index: sys/sys/cdefs.h
| ===================================================================
| --- sys/sys/cdefs.h   (revision 228504)
| +++ sys/sys/cdefs.h   (working copy)
| @@ -230,27 +230,24 @@
|  #elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 201000L
|  /* Do nothing.  They are language keywords. */
|  #else
| -/* Not supported.  Implement them manually. */
| -#ifdef __GNUC__
| -#define      _Alignas(e)             __attribute__((__aligned__(e)))
| -#define      _Alignof(e)             __alignof__(e)
| -#define      _Noreturn               __attribute__((__noreturn__))
| +/* Not supported.  Implement them using our versions. */

It may be worth emphasizing that in some cases, "our version" doesn't
exist, and that this is intentional (we omit the definition when none
is possible, and this results in __aligned() sometimes not being defined
and __thread never being defined).

| +#define      _Alignas(e)             __aligned(e)
| +#define      _Alignof(e)             __alignof(e)

I prefer to always spell the parameter as x.  Most older macros in this
file, and CTASSERT() in another file, spell their parameters (x, y, ...).

| +#define      _Noreturn               __dead2
|  #define      _Thread_local           __thread
| -#else
| -#define      _Alignas(e)
| -#define      _Alignof(e)             __offsetof(struct { char __a; e __b; }, 
__b)
| -#define      _Noreturn
| -#define      _Thread_local
| -#endif
|  #ifdef __COUNTER__
|  #define      _Static_assert(e, s)    __Static_assert(e, __COUNTER__)
|  #define      __Static_assert(e, c)   ___Static_assert(e, c)
|  #define      ___Static_assert(e, c)  typedef char __assert ## c[(e) ? 1 : -1]
|  #else
| -#define      _Static_assert(e, s)
| +#define      _Static_assert(e, s)    struct __hack

CTASSERT() has regressed for compilers that don't support __COUNTER__,
since it uses this.  Previously:
- CTASSERT() never worked for K&R compilers, since it uses C90 token pasting
- CTASSERT() worked for all C90 and later compilers.

|  #endif
|  #endif
|
| +#if !__GNUC_PREREQ__(2, 95)
| +#define      __alignof(x)    __offsetof(struct { char __a; e __b; }, __b)
| +#endif

Needs the spelling fix.

| +
|  #if __GNUC_PREREQ__(2, 96)
|  #define      __malloc_like   __attribute__((__malloc__))
|  #define      __pure          __attribute__((__pure__))

Check the sorting of the new macros, especially __alignof().  I think
the ordering should be mostly on the gcc and standards version, not on
the order in which the macros were added to cdefs.h.  You sorted the 2.95
ifdef before a 2.96 ifdef, but this 2.96 ifdef is especially disordered
according to my rule.  Even if the order is "logical" instead of historical,
it makes more sense to define basic macros like __alignof() before using
them.

Bruce
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to