From cfd17534ab92fdf93bdb35d2f4023ff375d81d46 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 20 Dec 2019 18:00:02 +0100 Subject: [PATCH] backport: re PR c++/61414 (enum class bitfield size-checking needs a separate warning flag controlling it) Backported from mainline 2019-11-26 Jakub Jelinek 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: r279654 --- gcc/c-family/ChangeLog | 6 ++++ gcc/c-family/c-attribs.c | 1 + gcc/cp/ChangeLog | 7 ++++ gcc/cp/class.c | 56 ++++++++++++++++++++++++++++- gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/g++.dg/cpp0x/enum23.C | 2 +- gcc/testsuite/g++.dg/cpp0x/enum38.C | 25 +++++++++++++ 7 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/enum38.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 47b03901a574..f077a7dc503e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,6 +1,12 @@ 2019-12-20 Jakub Jelinek Backported from mainline + 2019-11-26 Jakub Jelinek + + PR c++/61414 + * c-attribs.c (handle_mode_attribute): Add mode attribute to + ENUMERAL_TYPEs. + 2019-11-22 Jakub Jelinek PR c/90677 diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 93b210eed9ca..0275dc0245cf 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -1843,6 +1843,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 26d109c6d758..98aada542593 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,6 +1,13 @@ 2019-12-20 Jakub Jelinek Backported from mainline + 2019-11-26 Jakub Jelinek + + PR c++/61414 + * class.c (enum_to_min_precision): New hash_map. + (enum_min_precision): New function. + (check_bitfield_decl): Use it. + 2019-11-22 Jakub Jelinek PR c/90677 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f7059fb7341b..35b75580c333 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3198,6 +3198,60 @@ add_implicitly_declared_members (tree t, tree* access_decls, } } +/* Cache of enum_min_precision values. */ +static GTY((deletable)) hash_map *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::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. */ @@ -3259,7 +3313,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 a37e0b3a1f65..54cf7e5feb81 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -3,6 +3,10 @@ Backported from mainline 2019-11-26 Jakub Jelinek + 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 b2378e1b366b..53ad990bf93d 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 000000000000..f0dd8a1fc6bb --- /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'" } +}; -- 2.47.2