aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-11-26 21:57:27 +0000
committerJakub Jelinek <jakub@redhat.com>2019-11-26 21:57:27 +0000
commitc60372380ae9426eedcf7cf38af58983d49a747a (patch)
tree635c4e4e72fcee7a26baab3ee60c186fc36a56a5
parent1d1513ef969388c711b9d4c37d7c4093e5332043 (diff)
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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@278736 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/c-family/ChangeLog6
-rw-r--r--gcc/c-family/c-attribs.c1
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/class.c56
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/enum23.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/enum38.C25
7 files changed, 99 insertions, 2 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index a83685858f9..89292175846 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -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
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index cc006f38366..35388e83a83 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -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))
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index fe912c66af0..be36daaa516 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index ef1d5136963..f36f75fa0db 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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",
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6fb13fee9d9..6a777328d50 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum23.C b/gcc/testsuite/g++.dg/cpp0x/enum23.C
index b2378e1b366..53ad990bf93 100644
--- a/gcc/testsuite/g++.dg/cpp0x/enum23.C
+++ b/gcc/testsuite/g++.dg/cpp0x/enum23.C
@@ -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
index 00000000000..f0dd8a1fc6b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum38.C
@@ -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'" }
+};