gdb: allow duplicate enumerators in flag enums
authorSimon Marchi <simon.marchi@efficios.com>
Tue, 18 Feb 2020 22:29:23 +0000 (17:29 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Tue, 18 Feb 2020 22:32:57 +0000 (17:32 -0500)
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.

gdb/ChangeLog
gdb/dwarf2/read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/printcmds.c
gdb/valprint.c

index ca9f36474535fe1cbe6d27d3304d64497b1bc121..6ea59592fac194329f6a67dfc8249db559f49d22 100644 (file)
@@ -1,3 +1,9 @@
+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".
index 5a77b62b5a053ee73357e6c43c896453f4fdc419..ee220ab70b33f371a206b4ee841026f26c9ea4e3 100644 (file)
@@ -15495,7 +15495,6 @@ update_enumeration_type_from_children (struct die_info *die,
   struct die_info *child_die;
   int unsigned_enum = 1;
   int flag_enum = 1;
-  ULONGEST mask = 0;
 
   auto_obstack obstack;
 
@@ -15531,10 +15530,6 @@ update_enumeration_type_from_children (struct die_info *die,
        {
          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
index 5aaf5feecdfee0e421bc3efafdb026d2c1c46d2e..4f63dde12a906c937631710acafd091e228a50a3 100644 (file)
@@ -1,3 +1,8 @@
+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
index acb3cb3ad25ea4802a5bdd2b4e2550ebbdcd2e49..ed1e26b12a9c8d3c925c8a334ca574bf1b7d02b3 100644 (file)
@@ -99,9 +99,10 @@ volatile enum some_volatile_enum some_volatile_enum = enumvolval1;
 /* 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;
index 77b9a4993d79306b5fa5ba1367f4ee24445fc3b7..888c9cdb577820b124e58298ddc2978bdd5d0924 100644 (file)
@@ -631,9 +631,10 @@ generic_val_print_enum_1 (struct type *type, LONGEST val,
     {
       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)
        {