+2020-02-18  Simon Marchi  <simon.marchi@efficios.com>
+
+       * dwarf2/read.c: Include "count-one-bits.h".
+       (update_enumeration_type_from_children): If an enumerator has
+       multiple bits set, don't treat the enumeration as a "flag enum".
+       * valprint.c (generic_val_print_enum_1): Assert that enumerators
+       of flag enums have 0 or 1 bit set.
+
 2020-02-18  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * aarch64-tdep.c (aarch64_displaced_step_copy_insn): Use an explicit
 
 #include "gdbsupport/selftest.h"
 #include "rust-lang.h"
 #include "gdbsupport/pathstuff.h"
+#include "count-one-bits.h"
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
          unsigned_enum = 0;
          flag_enum = 0;
        }
-      else if ((mask & value) != 0)
-       flag_enum = 0;
       else
-       mask |= value;
+       {
+         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
         a flag type, no need to look at the rest of the enumerates.  */
 
+2020-02-18  Simon Marchi  <simon.marchi@efficios.com>
+
+       * gdb.base/printcmds.c (enum flag_enum): Prefix enumerators with
+       FE_, add FE_NONE.
+       (three): Update.
+       (enum flag_enum_without_zero): New enum.
+       (flag_enum_without_zero): New variable.
+       (enum not_flag_enum): New enum.
+       (three_not_flag): New variable.
+       * gdb.base/printcmds.exp (test_artificial_arrays): Update.
+       (test_print_enums): Add more tests for printing flag enums.
+
 2020-02-18  Tom de Vries  <tdevries@suse.de>
 
        * lib/ada.exp (gdb_compile_ada_1): Factor out of ...
 
    name.  See PR11827.  */
 volatile enum some_volatile_enum some_volatile_enum = enumvolval1;
 
-enum flag_enum { ONE = 1, TWO = 2 };
+/* An enum considered as a "flag enum".  */
+enum flag_enum
+{
+  FE_NONE = 0x00,
+  FE_ONE  = 0x01,
+  FE_TWO  = 0x02,
+};
+
+enum flag_enum three = FE_ONE | FE_TWO;
+
+/* Another enum considered as a "flag enum", but with no enumerator with value
+   0.  */
+enum flag_enum_without_zero
+{
+  FEWZ_ONE = 0x01,
+  FEWZ_TWO = 0x02,
+};
+
+enum flag_enum_without_zero flag_enum_without_zero = 0;
+
+/* Not a flag enum, an enumerator value has multiple bits sets.  */
+enum not_flag_enum
+{
+  NFE_ONE = 0x01,
+  NFE_TWO = 0x02,
+  NFE_F0  = 0xf0,
+};
 
-enum flag_enum three = ONE | TWO;
+enum not_flag_enum three_not_flag = NFE_ONE | NFE_TWO;
 
 /* A structure with an embedded array at an offset > 0.  The array has
    all elements with the same repeating value, which must not be the
 
     gdb_test_escape_braces "p int1dim\[0\]${ctrlv}@2${ctrlv}@3" \
        "({{0, 1}, {2, 3}, {4, 5}}|\[Cc\]annot.*)" \
        {p int1dim[0]@2@3}
-    gdb_test_escape_braces "p int1dim\[0\]${ctrlv}@TWO" " = {0, 1}" \
+    gdb_test_escape_braces "p int1dim\[0\]${ctrlv}@FE_TWO" " = {0, 1}" \
         {p int1dim[0]@TWO}
-    gdb_test_escape_braces "p int1dim\[0\]${ctrlv}@TWO${ctrlv}@three" \
+    gdb_test_escape_braces "p int1dim\[0\]${ctrlv}@FE_TWO${ctrlv}@three" \
        "({{0, 1}, {2, 3}, {4, 5}}|\[Cc\]annot.*)" \
        {p int1dim[0]@TWO@three}
     gdb_test_escape_braces {p/x (short [])0x12345678} \
     # Regression test for PR11827.
     gdb_test "print some_volatile_enum" "enumvolval1"
 
-    gdb_test "print three" " = \\\(ONE \\| TWO\\\)"
+    # Print a flag enum.
+    gdb_test "print three" [string_to_regexp " = (FE_ONE | FE_TWO)"]
+
+    # Print a flag enum with value 0, where an enumerator has value 0.
+    gdb_test "print (enum flag_enum) 0x0" [string_to_regexp " = FE_NONE"]
+
+    # Print a flag enum with value 0, where no enumerator has value 0.
+    gdb_test "print flag_enum_without_zero" [string_to_regexp " = (unknown: 0)"]
+
+    # Print a flag enum with unknown bits set.
+    gdb_test "print (enum flag_enum) 0xf1" [string_to_regexp " = (FE_ONE | unknown: 240)"]
+
+    # Test printing an enum not considered a "flag enum" (because one of its
+    # enumerators has multiple bits set).
+    gdb_test "print three_not_flag" [string_to_regexp " = 3"]
 }
 
 proc test_printf {} {
 
 #include "cli/cli-option.h"
 #include "gdbarch.h"
 #include "cli/cli-style.h"
+#include "count-one-bits.h"
 
 /* Maximum number of wchars returned from wchar_iterate.  */
 #define MAX_WCHARS 4
        {
          QUIT;
 
-         if ((val & TYPE_FIELD_ENUMVAL (type, i)) != 0)
+         ULONGEST enumval = TYPE_FIELD_ENUMVAL (type, i);
+         int nbits = count_one_bits_ll (enumval);
+
+         gdb_assert (nbits == 0 || nbits == 1);
+
+         if ((val & enumval) != 0)
            {
              if (!first)
                fputs_filtered (" | ", stream);