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/cp/class.c | |
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/cp/class.c')
-rw-r--r-- | gcc/cp/class.c | 56 |
1 files changed, 55 insertions, 1 deletions
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", |