Bug 83294 - int32_t & related definitions wrong with -funsigned-bitfields
Summary: int32_t & related definitions wrong with -funsigned-bitfields
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-12-05 20:54 UTC by Rich Felker
Modified: 2024-03-12 22:10 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rich Felker 2017-12-05 20:54:54 UTC
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.
Comment 1 jsm-csl@polyomino.org.uk 2017-12-05 21:21:44 UTC
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.
Comment 2 Rich Felker 2017-12-05 21:29:00 UTC
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.
Comment 3 jsm-csl@polyomino.org.uk 2017-12-05 21:51:13 UTC
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).
Comment 4 Rich Felker 2018-03-11 02:01:34 UTC
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?
Comment 5 Rich Felker 2018-03-11 02:12:33 UTC
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.
Comment 6 jsm-csl@polyomino.org.uk 2018-03-12 23:39:44 UTC
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.
Comment 7 Rich Felker 2018-03-12 23:56:34 UTC
Thanks. I think between footnote 125 and DR#315 the intent is clear and this bug report stands as written.
Comment 8 Jonathan Wakely 2018-03-13 00:07:57 UTC
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.