Stop using enums in bitfields

The C standard does not specify whether the underlying type of an enum
is signed or unsigned, and until C23 there was no way to control this
explicitly. GCC appears to make enums unsigned unless there is a
negative value among cases of the enum, in which case it becomes signed.
MSCV appears to make enums signed by default.

A bitfield of an enum type (which is not specificied in the C standard
either) behaves as if it was an instance of a numeric type with a
reduced value range. Specifically, a 'signed int val : 2;' bitfield will
have the possible values of -2, -1, 0, and 1, with the usual wraparound
behavior for the values that don't fit (although this too is
implementation-defined).

This causes the following issue, if we have:

typedef enum
{
  G_ZERO,
  G_ONE,
  G_TWO
} GFoo;

struct _GBar
{
  GFoo foo : 2;
};

and then assign bar.foo = G_TWO and read it back, it will have the
expected value of 2 (aka G_TWO) on GCC, but a value of -2 (not matching
any of the enum variants) on MSVC.

There does not seem to be any way to influence signedness of an enum
prior to C23, nor is there a 'unsigned GFoo foo : 2;' syntax. The only
remaining options seems to be never using enums in bitfields, which is
what this change implements.

This corresponds to https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6467
in GTK.

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
This commit is contained in:
Sergey Bugaev 2023-10-11 14:13:16 +03:00
parent 2f5088b7b6
commit 2ec660b2ea

View File

@ -29,8 +29,8 @@
#define G_FILE_ATTRIBUTE_VALUE_INIT {0}
typedef struct {
GFileAttributeType type : 8;
GFileAttributeStatus status : 8;
guint type : 8; /* GFileAttributeType */
guint status : 8; /* GFileAttributeStatus */
union {
gboolean boolean;
gint32 int32;