On 11/25/19 6:32 PM, Jakub Jelinek wrote:
Hi!
On Mon, Nov 25, 2019 at 03:46:23PM +0100, Jakub Jelinek wrote:
On Mon, Nov 25, 2019 at 03:39:32PM +0100, Jakub Jelinek wrote:
I guess the question is, shall we store the minimum precision needed
somewhere by finish_enum_value_list (perhaps only bother if the precision
of the underlying type is not the same) or compute it each time again
(which would mean for each bitfield of enum type walk the list of all the
enum values)? And, if we should store it somewhere, any preferences where?
These days C++ FE has TYPE_LANG_SPECIFIC just for classes, so options are
just use the class TYPE_LANG_SPECIFIC and just stick the min/max values in
some trees in there, restore having different lang specific variants and
store just minimum precision in there, add hash map from tree (hashed using
TYPE_UID) to precision, something else?
Or yet another possibility, only compute it on demand and use a hash map as
cache.
Here is that option implemented, bootstrapped/regtested on x86_64-linux and
i686-linux, ok for trunk?
OK, thanks.
2019-11-26 Jakub Jelinek <ja...@redhat.com>
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.
--- gcc/c-family/c-attribs.c.jj 2019-11-23 11:05:50.813492164 +0100
+++ gcc/c-family/c-attribs.c 2019-11-25 16:47:35.317750531 +0100
@@ -1866,6 +1866,7 @@ handle_mode_attribute (tree *node, tree
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))
--- gcc/cp/class.c.jj 2019-11-16 18:13:42.844606979 +0100
+++ gcc/cp/class.c 2019-11-25 16:42:15.050633229 +0100
@@ -3265,6 +3265,60 @@ add_implicitly_declared_members (tree t,
}
}
+/* 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",
--- gcc/testsuite/g++.dg/cpp0x/enum23.C.jj 2013-02-16 09:31:06.400506406
+0100
+++ gcc/testsuite/g++.dg/cpp0x/enum23.C 2019-11-25 16:51:19.532332223 +0100
@@ -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" }
};
--- gcc/testsuite/g++.dg/cpp0x/enum38.C.jj 2019-11-25 16:50:56.323686060
+0100
+++ gcc/testsuite/g++.dg/cpp0x/enum38.C 2019-11-25 16:52:28.466281278 +0100
@@ -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'" }
+};
Jakub