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
[email protected]