[conv.prom] paragraph 3 says that bit-fields are converted to int by the integral promotions if int can represent all the values of the bit-field. The following testcase was discussed on the WG14 reflector in January as illustrating a difference between C compilers (where an unsigned:3 bit-field has a special 3-bit type, so is promoted to int) and C++ compilers (where an unsigned:3 bit-field has type unsigned, per [class.bit]), but [conv.prom] wasn't mentioned in that discussion and as far as I can tell it means that C++ compilers too should promote the unsigned:3 bit-field to int. If not, what's wrong in my reading of [conv.prom]? #include <stdio.h> int main(void){ struct bits { unsigned int ui3 : 3; } bits; int i = -1; /* is a very large positive number as unsigned */ bits.ui3 = 1u; if( bits.ui3 < i ){ (void)printf("ui3 treated as unsigned, i promoted to unsigned\n"); }else{ (void)printf("ui3 promoted to int (value preserving)\n"); } return 0; } My reading of [conv.prom] is that bits.ui3 should have been promoted to int, though the statistics from the WG14 reflector were that 29 C++ compilers converted i to unsigned and only 1 promoted bits.ui3 to int. There are still differences between C and C++ for bit-fields of types wider than int.
That was my reading of the C and C++ standards too. FWIW the ARM C/C++ compiler agrees with you too!
I just checked and this was fixed by: 2006-04-23 Mark Mitchell <mark@codesourcery.com> PR c++/26534 * cp-tree.h (is_bitfield_expr_with_lowered_type): New function. * typeck.c (is_bitfield_expr_with_lowered_type): New function. (decay_conversion): Convert bitfield expressions to the correct type. (build_modify_expr): Remove spurious conversions. * class.c (layout_class_type): Modify the type of bitfields to indicate a limited range. * call.c (standard_conversion): Adjust the type of bitfield expressions used in an rvalue context. (build_conditional_expr): Likewise. In that we now get: ui3 promoted to int (value preserving)
I agree that the C++ standard requires the behavior suggested by Joseph in Comment #1. However, my patch was not intended to fix this bug, and only does so by accident. In particular, the last lines of decay_conversion convert the expression to the TYPE_MAIN_VARIANT of the limited-precision type, rather than to the TYPE_MAIN_VARIANT of the declared type of the bitfield, as I had intended, although the original conversion from limited-precision type to declared type is present in the expression by this point. I am not sure if that original conversion is actually required, given that the testsuite is passing with the code in its current state. In earlier forms of the patch, it was definitely required; otherwise, for example, bitfields of enumeration type did not have the correct type elsewhere in the compiler. It may be that because of the changes I made to the conversion machinery in call.c, this is no longer a problem.
Subject: Re: Bit-field promotions On Sun, 23 Apr 2006, mmitchel at gcc dot gnu dot org wrote: > However, my patch was not intended to fix this bug, and only does so by > accident. In particular, the last lines of decay_conversion convert the > expression to the TYPE_MAIN_VARIANT of the limited-precision type, rather than > to the TYPE_MAIN_VARIANT of the declared type of the bitfield, as I had > intended, although the original conversion from limited-precision type to > declared type is present in the expression by this point. > > I am not sure if that original conversion is actually required, given that the > testsuite is passing with the code in its current state. In earlier forms of > the patch, it was definitely required; otherwise, for example, bitfields of > enumeration type did not have the correct type elsewhere in the compiler. It > may be that because of the changes I made to the conversion machinery in > call.c, this is no longer a problem. The sort of case where you need to convert to the declared type is #include <stdlib.h> struct S { unsigned long a : 33, b : 33; } s = { 1UL << 32, 1UL << 32 }; int main(void) { if (s.a + s.b != (1UL << 33)) abort(); } (supposing 32-bit int, 64-bit long). But given that C++ doesn't define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS, even if the addition is done on the reduced types that might not reliably cause the test to fail.