re PR c++/61414 (enum class bitfield size-checking needs a separate warning flag...
authorJakub Jelinek <jakub@redhat.com>
Tue, 26 Nov 2019 21:57:27 +0000 (22:57 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 26 Nov 2019 21:57:27 +0000 (22:57 +0100)
PR c++/61414
* c-attribs.c (handle_mode_attribute): Add mode attribute to
ENUMERAL_TYPEs.

* class.c (enum_to_min_precision): New hash_map.
(enum_min_precision): New function.
(check_bitfield_decl): Use it.

* g++.dg/cpp0x/enum23.C: Remove xfail.
* g++.dg/cpp0x/enum28.C: New test.

From-SVN: r278736

gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/enum23.C
gcc/testsuite/g++.dg/cpp0x/enum38.C [new file with mode: 0644]

index a836858..8929217 100644 (file)
@@ -1,3 +1,9 @@
+2019-11-26  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/61414
+       * c-attribs.c (handle_mode_attribute): Add mode attribute to
+       ENUMERAL_TYPEs.
+
 2019-11-25  Joseph Myers  <joseph@codesourcery.com>
 
        PR c/91985
index cc006f3..35388e8 100644 (file)
@@ -1866,6 +1866,7 @@ handle_mode_attribute (tree *node, tree name, tree args,
                typefm = make_signed_type (TYPE_PRECISION (typefm));
              TREE_TYPE (typefm) = type;
            }
+         *no_add_attrs = false;
        }
       else if (VECTOR_MODE_P (mode)
               ? TREE_CODE (type) != TREE_CODE (TREE_TYPE (typefm))
index fe912c6..be36daa 100644 (file)
@@ -1,3 +1,10 @@
+2019-11-26  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/61414
+       * class.c (enum_to_min_precision): New hash_map.
+       (enum_min_precision): New function.
+       (check_bitfield_decl): Use it.
+
 2019-11-25  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * typeck.c (cp_build_indirect_ref_1): Add location_t parameter
index ef1d513..f36f75f 100644 (file)
@@ -3265,6 +3265,60 @@ add_implicitly_declared_members (tree t, tree* access_decls,
     }
 }
 
+/* Cache of enum_min_precision values.  */
+static GTY((deletable)) hash_map<tree, int> *enum_to_min_precision;
+
+/* Return the minimum precision of a bit-field needed to store all
+   enumerators of ENUMERAL_TYPE TYPE.  */
+
+static int
+enum_min_precision (tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+  /* For unscoped enums without fixed underlying type and without mode
+     attribute we can just use precision of the underlying type.  */
+  if (UNSCOPED_ENUM_P (type)
+      && !ENUM_FIXED_UNDERLYING_TYPE_P (type)
+      && !lookup_attribute ("mode", TYPE_ATTRIBUTES (type)))
+    return TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type));
+
+  if (enum_to_min_precision == NULL)
+    enum_to_min_precision = hash_map<tree, int>::create_ggc (37);
+
+  bool existed;
+  int prec = enum_to_min_precision->get_or_insert (type, &existed);
+  if (existed)
+    return prec;
+
+  tree minnode, maxnode;
+  if (TYPE_VALUES (type))
+    {
+      minnode = maxnode = NULL_TREE;
+      for (tree values = TYPE_VALUES (type);
+          values; values = TREE_CHAIN (values))
+       {
+         tree decl = TREE_VALUE (values);
+         tree value = DECL_INITIAL (decl);
+         if (value == error_mark_node)
+           value = integer_zero_node;
+         if (!minnode)
+           minnode = maxnode = value;
+         else if (tree_int_cst_lt (maxnode, value))
+           maxnode = value;
+         else if (tree_int_cst_lt (value, minnode))
+           minnode = value;
+       }
+    }
+  else
+    minnode = maxnode = integer_zero_node;
+
+  signop sgn = tree_int_cst_sgn (minnode) >= 0 ? UNSIGNED : SIGNED;
+  int lowprec = tree_int_cst_min_precision (minnode, sgn);
+  int highprec = tree_int_cst_min_precision (maxnode, sgn);
+  prec = MAX (lowprec, highprec);
+  return prec;
+}
+
 /* FIELD is a bit-field.  We are finishing the processing for its
    enclosing type.  Issue any appropriate messages and set appropriate
    flags.  Returns false if an error has been diagnosed.  */
@@ -3326,7 +3380,7 @@ check_bitfield_decl (tree field)
                    "width of %qD exceeds its type", field);
       else if (TREE_CODE (type) == ENUMERAL_TYPE)
        {
-         int prec = TYPE_PRECISION (ENUM_UNDERLYING_TYPE (type));
+         int prec = enum_min_precision (type);
          if (compare_tree_int (w, prec) < 0)
            warning_at (DECL_SOURCE_LOCATION (field), 0,
                        "%qD is too small to hold all values of %q#T",
index 6fb13fe..6a77732 100644 (file)
@@ -1,5 +1,9 @@
 2019-11-26  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/61414
+       * g++.dg/cpp0x/enum23.C: Remove xfail.
+       * g++.dg/cpp0x/enum28.C: New test.
+
        PR tree-optimization/92644
        * g++.dg/opt/pr92644.C: New test.
 
index b2378e1..53ad990 100644 (file)
@@ -5,5 +5,5 @@ enum class MyEnum { A = 1 };
 
 struct MyClass
 {
-  MyEnum Field1 : 3; // { dg-bogus "warning: 'MyClass::Field1' is too small" "" { xfail *-*-* } }
+  MyEnum Field1 : 3; // { dg-bogus "warning: 'MyClass::Field1' is too small" }
 };
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum38.C b/gcc/testsuite/g++.dg/cpp0x/enum38.C
new file mode 100644 (file)
index 0000000..f0dd8a1
--- /dev/null
@@ -0,0 +1,25 @@
+// PR c++/61414
+// { dg-do compile { target c++11 } }
+
+enum C { C0 = -4, C1 = 3 };
+enum D { D0 = 0, D1 = 15 };
+enum class E { E0 = -4, E1 = 3 };
+enum F : unsigned { F0 = 0, F1 = 15 };
+enum __attribute__((__mode__ (__QI__))) G { G0 = -4, G1 = 3 };
+enum __attribute__((__mode__ (__HI__))) H { H0 = 0, H1 = 15 };
+
+struct S
+{
+  C a : 2;     // { dg-warning "'S::a' is too small to hold all values of 'enum C'" }
+  C b : 3;     // { dg-bogus "'S::b' is too small to hold all values of 'enum C'" }
+  D c : 3;     // { dg-warning "'S::c' is too small to hold all values of 'enum D'" }
+  D d : 4;     // { dg-bogus "'S::d' is too small to hold all values of 'enum D'" }
+  E e : 2;     // { dg-warning "'S::e' is too small to hold all values of 'enum class E'" }
+  E f : 3;     // { dg-bogus "'S::f' is too small to hold all values of 'enum class E'" }
+  F g : 3;     // { dg-warning "'S::g' is too small to hold all values of 'enum F'" }
+  F h : 4;     // { dg-bogus "'S::h' is too small to hold all values of 'enum F'" }
+  G i : 2;     // { dg-warning "'S::i' is too small to hold all values of 'enum G'" }
+  G j : 3;     // { dg-bogus "'S::j' is too small to hold all values of 'enum G'" }
+  H k : 3;     // { dg-warning "'S::k' is too small to hold all values of 'enum H'" }
+  H l : 4;     // { dg-bogus "'S::l' is too small to hold all values of 'enum H'" }
+};