The following minimal test case fails with -funsigned-bitfields: struct { int32_t x:1 } foo; foo.x = -1; assert(foo.x < 0); This is because __INT32_TYPE__, etc. are defined as plain "int" rather than "signed int", and C specifies that, when the implementation interprets plain int as unsigned in a bitfield context, it must also do this for typedefs (see footnote 125 in n1570). Presumably changing __INT32_TYPE__ and related macros to an explicit "signed int" will fix the problem.
I'm not aware of a standard requirement not to use plain int for int32_t (even with unsigned bit-fields), though it may well be useful to make the signedness explicit. After all, int is a signed integer type with 32 bits in the cases where it's used for int32_t. (However, plain char is never OK as int8_t / uint8_t etc. because char is an integer type but not a signed integer type or unsigned integer type.) On most platforms, except with -ffreestanding GCC just wraps libc's stdint.h, so this is mostly a libc quality-of-implementation issue, not just a GCC one.
I agree it's not clear if there's a conformance distinction or just a QoI issue, but it seems really unfortunate for int32_t not to be usable in bitfields if -funsigned-bitfields might be passed to GCC, since the exact-sized types from stdint.h are ideally suited to the same sort of "fixed memory layout" situations where people like to use bitfields, and since there's no other portable way to request a 32-bit signed type. So I think it would be nice to "fix" this either way.
FWIW, current glibc already uses signed int for int32_t (via using it for __int32_t which is used to define int32_t), entirely as an accident following a header refactoring, but not for other types such as int_least32_t or int_fast32_t (so a glibc issue would still be appropriate for those other types).
Further examination shows that this GCC feature (-funsigned-bitfields) is actually buggy/non-conforming. It changes the default signedness of all integer types in bitfields, not just plain int. This behavior seems consistent with the documentation, but not with the C standard, which only permits it for plain int; see C11 6.7.2 ¶5: "Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier int designates the same type as signed int or the same type as unsigned int." Should this be opened as a separate bug?
Reading the relevant part of the standard in more detail, it seems like it's a GCC bug that GCC is applying the exception for plain int to typedefs. ¶5: "Each of the comma-separated multisets designates the same type, except that for bit-fields, it is implementation-defined whether the specifier int designates the same type as signed int or the same type as unsigned int." This text is referring to an above (¶3) list of types, containing "int, signed, or signed int" as one line item and "typedef name" as another. The exception is written explicitly in terms of the former, and makes no mention of the latter.
The response to C99 DR#315 says that for all the types not specifying "signed" or "unsigned" explicitly, if an implementation accepts them as bit-field types it's implementation-defined what the signedness is. That's compatible with C++ up to C++11 (C++14 removed the special-casing allowing plain int etc. bit-fields to be unsigned). C11 footnote 125 explicitly refers to "typedef-name defined as int", so the intent is clear even if that's not explicit in normative text.
Thanks. I think between footnote 125 and DR#315 the intent is clear and this bug report stands as written.
FWIW C++ Core DR 739 is a DR against C++11 and C++98, so should be considered to apply pre-C++14 too. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#739 This has no bearing on the C behaviour though.
https://inbox.sourceware.org/gcc-patches/7a5ec7af-fdbf-470f-9414-bf4110331d0a@ventanamicro.com/