diff options
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/c/c-decl.cc | 151 |
2 files changed, 133 insertions, 39 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index d28585b..7cb2e9c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,24 @@ +2022-10-18 Joseph Myers <joseph@codesourcery.com> + + PR c/107164 + * c-decl.cc (shadow_tag_warned): If pedantic, diagnose "enum tag;" + with previous declaration visible. + +2022-10-18 Joseph Myers <joseph@codesourcery.com> + + PR c/36113 + * c-decl.cc (finish_enum): If any enumerators do not fit in int, + convert all to the type of the enumeration. pedwarn if no integer + type fits all enumerators and default to + widest_integer_literal_type_node in that case. Otherwise pedwarn + for type wider than intmax_t. + (build_enumerator): pedwarn for enumerators outside the range of + uintmax_t or intmax_t, and otherwise use pedwarn_c11 for + enumerators outside the range of int. On overflow, attempt to + find a wider type that can hold the value of the next enumerator. + Do not convert value to type determined with + c_common_type_for_size. + 2022-10-14 Jakub Jelinek <jakub@redhat.com> * c-typeck.cc (convert_arguments): Don't promote __bf16 to diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index a7571cc..80f6e91 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -4814,6 +4814,20 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) warned = 1; pending_xref_error (); } + else if (declspecs->typespec_kind != ctsk_tagdef + && declspecs->typespec_kind != ctsk_tagfirstref + && declspecs->typespec_kind != ctsk_tagfirstref_attrs + && code == ENUMERAL_TYPE) + { + bool warned_enum = false; + if (warned != 1) + warned_enum = pedwarn (input_location, OPT_Wpedantic, + "empty declaration of %<enum%> type " + "does not redeclare tag"); + if (warned_enum) + warned = 1; + pending_xref_error (); + } else { pending_invalid_xref = NULL_TREE; @@ -9385,6 +9399,10 @@ finish_enum (tree enumtype, tree values, tree attributes) precision = MAX (tree_int_cst_min_precision (minnode, sign), tree_int_cst_min_precision (maxnode, sign)); + bool wider_than_int = + (tree_int_cst_lt (minnode, TYPE_MIN_VALUE (integer_type_node)) + || tree_int_cst_lt (TYPE_MAX_VALUE (integer_type_node), maxnode)); + /* If the precision of the type was specified with an attribute and it was too small, give an error. Otherwise, use it. */ if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes)) @@ -9407,9 +9425,20 @@ finish_enum (tree enumtype, tree values, tree attributes) tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); if (tem == NULL) { - warning (0, "enumeration values exceed range of largest integer"); - tem = long_long_integer_type_node; - } + /* This should only occur when both signed and unsigned + values of maximum precision occur among the + enumerators. */ + pedwarn (input_location, 0, + "enumeration values exceed range of largest integer"); + tem = widest_integer_literal_type_node; + } + else if (precision > TYPE_PRECISION (intmax_type_node) + && !tree_int_cst_lt (minnode, TYPE_MIN_VALUE (intmax_type_node)) + && !tree_int_cst_lt (TYPE_MAX_VALUE (uintmax_type_node), + maxnode)) + pedwarn (input_location, OPT_Wpedantic, + "enumeration values exceed range of %qs", + sign == UNSIGNED ? "uintmax_t" : "intmax_t"); } else tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node; @@ -9439,17 +9468,17 @@ finish_enum (tree enumtype, tree values, tree attributes) TREE_TYPE (enu) = enumtype; - /* The ISO C Standard mandates enumerators to have type int, - even though the underlying type of an enum type is - unspecified. However, GCC allows enumerators of any - integer type as an extensions. build_enumerator() - converts any enumerators that fit in an int to type int, - to avoid promotions to unsigned types when comparing - integers with enumerators that fit in the int range. - When -pedantic is given, build_enumerator() would have - already warned about those that don't fit. Here we - convert the rest to the enumerator type. */ - if (TREE_TYPE (ini) != integer_type_node) + /* Before C2X, the ISO C Standard mandates enumerators to + have type int, even though the underlying type of an enum + type is unspecified. However, C2X allows enumerators of + any integer type, and if an enumeration has any + enumerators wider than int, all enumerators have the + enumerated type after it is parsed. Any enumerators that + fit in int are given type int in build_enumerator (which + is the correct type while the enumeration is being + parsed), so no conversions are needed here if all + enumerators fit in int. */ + if (wider_than_int) ini = convert (enumtype, ini); DECL_INITIAL (enu) = ini; @@ -9517,7 +9546,7 @@ tree build_enumerator (location_t decl_loc, location_t loc, struct c_enum_contents *the_enum, tree name, tree value) { - tree decl, type; + tree decl; /* Validate and default VALUE. */ @@ -9568,21 +9597,45 @@ build_enumerator (location_t decl_loc, location_t loc, } /* Even though the underlying type of an enum is unspecified, the type of enumeration constants is explicitly defined as int - (6.4.4.3/2 in the C99 Standard). GCC allows any integer type as - an extension. */ - else if (!int_fits_type_p (value, integer_type_node)) - pedwarn (loc, OPT_Wpedantic, - "ISO C restricts enumerator values to range of %<int%>"); - - /* The ISO C Standard mandates enumerators to have type int, even - though the underlying type of an enum type is unspecified. - However, GCC allows enumerators of any integer type as an - extensions. Here we convert any enumerators that fit in an int - to type int, to avoid promotions to unsigned types when comparing - integers with enumerators that fit in the int range. When - -pedantic is given, we would have already warned about those that - don't fit. We have to do this here rather than in finish_enum - because this value may be used to define more enumerators. */ + (6.4.4.3/2 in the C99 Standard). C2X allows any integer type, and + GCC allows such types for older standards as an extension. */ + bool warned_range = false; + if (!int_fits_type_p (value, + (TYPE_UNSIGNED (TREE_TYPE (value)) + ? uintmax_type_node + : intmax_type_node))) + /* GCC does not consider its types larger than intmax_t to be + extended integer types (although C2X would permit such types to + be considered extended integer types if all the features + required by <stdint.h> and <inttypes.h> macros, such as support + for integer constants and I/O, were present), so diagnose if + such a wider type is used. (If the wider type arose from a + constant of such a type, that will also have been diagnosed, + but this is the only diagnostic in the case where it arises + from choosing a wider type automatically when adding 1 + overflows.) */ + warned_range = pedwarn (loc, OPT_Wpedantic, + "enumerator value outside the range of %qs", + (TYPE_UNSIGNED (TREE_TYPE (value)) + ? "uintmax_t" + : "intmax_t")); + if (!warned_range && !int_fits_type_p (value, integer_type_node)) + pedwarn_c11 (loc, OPT_Wpedantic, + "ISO C restricts enumerator values to range of %<int%> " + "before C2X"); + + /* The ISO C Standard mandates enumerators to have type int before + C2X, even though the underlying type of an enum type is + unspecified. C2X allows enumerators of any integer type. During + the parsing of the enumeration, C2X specifies that constants + representable in int have type int, constants not representable + in int have the type of the given expression if any, and + constants not representable in int and derived by adding 1 to the + previous constant have the type of that constant unless the + addition would overflow or wraparound, in which case a wider type + of the same signedness is chosen automatically; after the + enumeration is parsed, all the constants have the type of the + enumeration if any do not fit in int. */ if (int_fits_type_p (value, integer_type_node)) value = convert (integer_type_node, value); @@ -9591,18 +9644,38 @@ build_enumerator (location_t decl_loc, location_t loc, = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), PLUS_EXPR, value, integer_one_node, false); the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value); + if (the_enum->enum_overflow) + { + /* Choose a wider type with the same signedness if + available. */ + int prec = TYPE_PRECISION (TREE_TYPE (value)) + 1; + bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (value)); + tree new_type = (unsignedp + ? long_unsigned_type_node + : long_integer_type_node); + if (prec > TYPE_PRECISION (new_type)) + new_type = (unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node); + if (prec > TYPE_PRECISION (new_type)) + new_type = (unsignedp + ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node); + if (prec <= TYPE_PRECISION (new_type)) + { + the_enum->enum_overflow = false; + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), + PLUS_EXPR, convert (new_type, value), + integer_one_node, false); + gcc_assert (!tree_int_cst_lt (the_enum->enum_next_value, value)); + } + } /* Now create a declaration for the enum value name. */ - type = TREE_TYPE (value); - type = c_common_type_for_size (MAX (TYPE_PRECISION (type), - TYPE_PRECISION (integer_type_node)), - (TYPE_PRECISION (type) - >= TYPE_PRECISION (integer_type_node) - && TYPE_UNSIGNED (type))); - - decl = build_decl (decl_loc, CONST_DECL, name, type); - DECL_INITIAL (decl) = convert (type, value); + decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value)); + DECL_INITIAL (decl) = value; pushdecl (decl); return tree_cons (decl, value, NULL_TREE); |