diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-11-26 22:57:27 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-11-26 22:57:27 +0100 |
commit | 05d6cb1a858151016dbd368fd8b0792f73423d19 (patch) | |
tree | 635c4e4e72fcee7a26baab3ee60c186fc36a56a5 /gcc | |
parent | 1f7ed00ebf23f881421f302e5371bd0957deb1ef (diff) | |
download | gcc-05d6cb1a858151016dbd368fd8b0792f73423d19.zip gcc-05d6cb1a858151016dbd368fd8b0792f73423d19.tar.gz gcc-05d6cb1a858151016dbd368fd8b0792f73423d19.tar.bz2 |
re PR c++/61414 (enum class bitfield size-checking needs a separate warning flag controlling it)
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/c-family/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/c-family/c-attribs.c | 1 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/class.c | 56 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/enum23.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/enum38.C | 25 |
7 files changed, 99 insertions, 2 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index a836858..8929217 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 cc006f3..35388e8 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 fe912c6..be36daa 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 ef1d513..f36f75f 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 6fb13fe..6a77732 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 b2378e1..53ad990 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 0000000..f0dd8a1 --- /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'" } +}; |