On Wed, 24 Feb 2016, Martin Sebor wrote:

> > That can be avoided simply by using unary + in the controlling expression
> > of _Generic (just as using unary + will avoid an error from sizeof, if you
> > want to be able to apply that to expressions that might be bit-fields) -
> > or any of the other techniques for achieving promotions of selected types.
> 
> Unfortunately, the + n trick is far too limited to be generally
> usable.  Since GCC allows bit-fields of other integers types
> besides those described by the standard (e.g., long long), the
> plus expression would have to be converted to the widest possible
> type (e.g., by (x + 0LL)) which would defeat the purpose of
> _Generic.  The trick of course work at all for type-generic
> macro intended to also accept non- scalar arguments.

There are lots of variants of the trick (including the conditional 
expression one), depending on which types you care about distinguishing 
and which are valid arguments to the macro.  If you want, you can even 
distinguish each bit-field width wider than int individually using typeof, 
via writing expressions with typeof to determine the width of the type.

I suspect many attempts to use _Generic with non-arithmetic types would 
run into usability problems in practice because every expression in the 
generic association list must still pass the Constraints whatever the type 
of the controlling expression - so you can select a function name based on 
that type, but putting more complicated expressions directly inside 
_Generic would be problematic in many cases if a wide range of types is to 
be allowed.

There is a basic question: is _Generic supposed to be arbitrarily 
expressive, or is it meant to cover cases like <tgmath.h>?  The answer in 
the context of questions about qualifiers and array-to-pointer decay was 
that it is meant to cover cases like <tgmath.h>, not to be arbitrarily 
expressive for hypothetical cases.  Maximal expressiveness would allow 
distinguishing all bit-field widths, but that would fall down on 
usability.

Integer types narrower than int are effectively second-class entities in 
C; you can't write constants of those types, for example, and they get 
promoted before used in arithmetic or being passed in variable arguments; 
while you *can* select on them with _Generic, the utility of doing so may 
be limited.  Bit-fields are effectively third-class entities, and 
bit-fields with implementation-defined declared types other than int or 
signed int or unsigned int are fourth-class (not required by the standard 
at all, and have their own problems of specification - and the final 
choice for DR#315 was to leave pretty much everything about such 
bit-fields implementation-defined - see the minutes for Portland 2006, 
London 2007, Kona 2007).

> GCC's handling of bit-fields in __typeof__  is also a problem
> and causes bugs in <tgmath.h>.  For example, the following is
> rejected by GCC (with not just one but 42 errors) as a result:
> 
>   struct S { unsigned b: 31; } s;
>   carg (s.b);

That should be reported as an ordinary bug in <tgmath.h>, that can easily 
be addressed by using unary + so that typeof isn't applied to a bit-field 
(<tgmath.h> treats all integer types the same and non-arithmetic types are 
irrelevant to it, so unary + is absoletely fine there).

> If it isn't clear it should be brought up in WG14 and clarified.
> It's clear enough in C++ for bit-fields to be used as arguments
> to overloaded functions or function templates.  I can't imagine

C++ has long diverged from C regarding bit-fields (allowing other declared 
types, allowing widths wider than the width of the underlying type, now 
requiring plain int bit-fields to be signed, ...).  Whereas C has its line 
of textual history going back to various C90 DRs and showing that:

(a) whether a bit-field width counts of part of the type doesn't generally 
matter within the standard except for integer promotions, so can safely be 
left unspecified with just special wording for promotions (modulo the new 
_Generic issue);

(b) everything about such matters for bit-fields of nonstandard types can 
be left implementation-defined;

(c) nothing defines semantics of conversion of out-of-range values to 
bit-fields other than treating the width as part of the type (or in the 
case of _Bool bit-fields, having the special wording to make it explicit 
that those have the semantics of _Bool not the semantics of an ordinary 
unsigned integer type with the specified number of bits).

-- 
Joseph S. Myers
jos...@codesourcery.com

Reply via email to