I have come across some uses cases where it would be desirable to treat
an enum that has duplicate values as a "flag enum". For example, this
one here [1]:
enum membarrier_cmd {
MEMBARRIER_CMD_QUERY = 0,
MEMBARRIER_CMD_GLOBAL = (1 << 0),
MEMBARRIER_CMD_GLOBAL_EXPEDITED = (1 << 1),
MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = (1 << 2),
MEMBARRIER_CMD_PRIVATE_EXPEDITED = (1 << 3),
MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4),
MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 5),
MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 6),
/* Alias for header backward compatibility. */
MEMBARRIER_CMD_SHARED = MEMBARRIER_CMD_GLOBAL,
};
The last enumerator is kept for backwards compatibility. Without this
patch, this enumeration wouldn't be considered a flag enum, because two
enumerators collide. With this patch, it would be considered a flag
enum, and the value 3 would be printed as:
MEMBARRIER_CMD_GLOBAL | MEMBARRIER_CMD_GLOBAL_EXPEDITED
Although if people prefer, we could display both MEMBARRIER_CMD_GLOBAL
and MEMBARRIER_CMD_SHARED in the result. It wouldn't be wrong, and
could perhaps be useful in case a bit may have multiple meanings
(depending on some other bit value).
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/membarrier.h?id=
0bf999f9c5e74c7ecf9dafb527146601e5c848b9#n125
gdb/ChangeLog:
* dwarf2/read.c (update_enumeration_type_from_children): Allow
flag enums to contain duplicate enumerators.
* valprint.c (generic_val_print_enum_1): Update comment.
gdb/testsuite/ChangeLog:
* gdb.base/printcmds.c (enum flag_enum): Add FE_TWO_LEGACY
enumerator.
+2020-02-18 Simon Marchi <simon.marchi@efficios.com>
+
+ * dwarf2/read.c (update_enumeration_type_from_children): Allow
+ flag enums to contain duplicate enumerators.
+ * valprint.c (generic_val_print_enum_1): Update comment.
+
2020-02-18 Simon Marchi <simon.marchi@efficios.com>
* dwarf2/read.c: Include "count-one-bits.h".
struct die_info *child_die;
int unsigned_enum = 1;
int flag_enum = 1;
- ULONGEST mask = 0;
auto_obstack obstack;
{
if (count_one_bits_ll (value) >= 2)
flag_enum = 0;
- else if ((mask & value) != 0)
- flag_enum = 0;
- else
- mask |= value;
}
/* If we already know that the enum type is neither unsigned, nor
+2020-02-18 Simon Marchi <simon.marchi@efficios.com>
+
+ * gdb.base/printcmds.c (enum flag_enum): Add FE_TWO_LEGACY
+ enumerator.
+
2020-02-18 Simon Marchi <simon.marchi@efficios.com>
* gdb.base/printcmds.c (enum flag_enum): Prefix enumerators with
/* An enum considered as a "flag enum". */
enum flag_enum
{
- FE_NONE = 0x00,
- FE_ONE = 0x01,
- FE_TWO = 0x02,
+ FE_NONE = 0x00,
+ FE_ONE = 0x01,
+ FE_TWO = 0x02,
+ FE_TWO_LEGACY = 0x02,
};
enum flag_enum three = FE_ONE | FE_TWO;
{
int first = 1;
- /* We have a "flag" enum, so we try to decompose it into
- pieces as appropriate. A flag enum has disjoint
- constants by definition. */
+ /* We have a "flag" enum, so we try to decompose it into pieces as
+ appropriate. The enum may have multiple enumerators representing
+ the same bit, in which case we choose to only print the first one
+ we find. */
fputs_filtered ("(", stream);
for (i = 0; i < len; ++i)
{