diff options
author | Martin Liska <mliska@suse.cz> | 2022-10-28 10:02:34 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-10-28 10:02:34 +0200 |
commit | 1eb021edb27e26f95cda63df121f6bc951647599 (patch) | |
tree | 7f132fded85bd7d05d81cd4c1227da2fd0c3c2d5 /gcc/c | |
parent | 62e475bad0d668c432bb97113cbf73fa281b8b55 (diff) | |
parent | 0607307768b66a90e27c5bc91a247acc938f070e (diff) | |
download | gcc-1eb021edb27e26f95cda63df121f6bc951647599.zip gcc-1eb021edb27e26f95cda63df121f6bc951647599.tar.gz gcc-1eb021edb27e26f95cda63df121f6bc951647599.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/c-convert.cc | 8 | ||||
-rw-r--r-- | gcc/c/c-decl.cc | 325 | ||||
-rw-r--r-- | gcc/c/c-objc-common.cc | 8 | ||||
-rw-r--r-- | gcc/c/c-parser.cc | 139 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 25 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 56 |
6 files changed, 402 insertions, 159 deletions
diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc index 6e74913..8a43e5f 100644 --- a/gcc/c/c-convert.cc +++ b/gcc/c/c-convert.cc @@ -110,8 +110,13 @@ c_convert (tree type, tree expr, bool init_const) case VOID_TYPE: return fold_convert_loc (loc, type, e); - case INTEGER_TYPE: case ENUMERAL_TYPE: + if (ENUM_UNDERLYING_TYPE (type) != NULL_TREE + && TREE_CODE (ENUM_UNDERLYING_TYPE (type)) == BOOLEAN_TYPE) + goto convert_to_boolean; + gcc_fallthrough (); + + case INTEGER_TYPE: if (sanitize_flags_p (SANITIZE_FLOAT_CAST) && current_function_decl != NULL_TREE && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE @@ -129,6 +134,7 @@ c_convert (tree type, tree expr, bool init_const) goto maybe_fold; case BOOLEAN_TYPE: + convert_to_boolean: return fold_convert_loc (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 4746e31..2b83900 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -4817,7 +4817,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) else if (declspecs->typespec_kind != ctsk_tagdef && declspecs->typespec_kind != ctsk_tagfirstref && declspecs->typespec_kind != ctsk_tagfirstref_attrs - && code == ENUMERAL_TYPE) + && code == ENUMERAL_TYPE + && !declspecs->enum_type_specifier_ref_p) { bool warned_enum = false; if (warned != 1) @@ -4883,6 +4884,38 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) warned = 1; } + if (declspecs->enum_type_specifier_ref_p && !warned) + { + if (declspecs->storage_class != csc_none) + { + error ("storage class specifier in empty declaration with %<enum%> " + "underlying type"); + warned = 1; + } + else if (declspecs->thread_p) + { + error ("%qs in empty declaration with %<enum%> underlying type", + declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); + warned = 1; + } + else if (declspecs->const_p + || declspecs->volatile_p + || declspecs->atomic_p + || declspecs->restrict_p + || declspecs->address_space) + { + error ("type qualifier in empty declaration with %<enum%> " + "underlying type"); + warned = 1; + } + else if (declspecs->alignas_p) + { + error ("%<alignas%> in empty declaration with %<enum%> " + "underlying type"); + warned = 1; + } + } + if (!warned && !in_system_header_at (input_location) && declspecs->storage_class != csc_none) { @@ -6496,6 +6529,16 @@ grokdeclarator (const struct c_declarator *declarator, } } + /* An enum type specifier (": specifier-qualifier-list") may only be + specified when the enum is being defined or in an empty + declaration of the form "enum identifier enum-type-specifier;". + Except for the case of an empty declaration that has additional + declaration specifiers, all invalid contexts (declarations that + aren't empty, type names, parameter declarations, member + declarations) pass through grokdeclarator. */ + if (declspecs->enum_type_specifier_ref_p) + error_at (loc, "%<enum%> underlying type may not be specified here"); + /* A function definition's declarator must have the form of a function declarator. */ @@ -8285,12 +8328,15 @@ get_parm_info (bool ellipsis, tree expr) Define the tag as a forward-reference with location LOC if it is not defined. HAVE_STD_ATTRS says whether any standard attributes were present after the struct, union or enum keyword; ATTRS are the - standard attributes present there. Return a c_typespec structure - for the type specifier. */ + standard attributes present there. HAS_ENUM_TYPE_SPECIFIER says + whether an enum type specifier (": specifier-qualifier-list") is + present; if so, this is called before that specifier is parsed, so + that the tag is in scope for that specifier. Return a c_typespec + structure for the type specifier. */ struct c_typespec parser_xref_tag (location_t loc, enum tree_code code, tree name, - bool have_std_attrs, tree attrs) + bool have_std_attrs, tree attrs, bool has_enum_type_specifier) { struct c_typespec ret; tree ref; @@ -8298,11 +8344,13 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = has_enum_type_specifier; - /* If a cross reference is requested, look up the type - already defined for this tag and return it. */ + /* If a cross reference is requested, look up the type already + defined for this tag and return it. If an enum type specifier is + present, only a definition in the current scope is relevant. */ - ref = lookup_tag (code, name, false, &refloc); + ref = lookup_tag (code, name, has_enum_type_specifier, &refloc); /* If this is the right type of tag, return what we found. (This reference will be shadowed by shadow_tag later if appropriate.) If this is the wrong type of tag, do not return it. If it was the @@ -8371,6 +8419,7 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); + ENUM_FIXED_UNDERLYING_TYPE_P (ref) = has_enum_type_specifier; } pushtag (loc, name, ref); @@ -8387,7 +8436,8 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, tree xref_tag (enum tree_code code, tree name) { - return parser_xref_tag (input_location, code, name, false, NULL_TREE).spec; + return parser_xref_tag (input_location, code, name, false, NULL_TREE, + false).spec; } /* Make sure that the tag NAME is defined *in the current scope* @@ -9288,12 +9338,15 @@ layout_array_type (tree t) /* Begin compiling the definition of an enumeration type. NAME is its name (or null if anonymous). LOC is the enum's location. + FIXED_UNDERLYING_TYPE is the (C2x) underlying type specified in the + definition. Returns the type object, as yet incomplete. Also records info about it so that build_enumerator may be used to declare the individual values as they are read. */ tree -start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) +start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, + tree fixed_underlying_type) { tree enumtype = NULL_TREE; location_t enumloc = UNKNOWN_LOCATION; @@ -9309,6 +9362,23 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) { enumtype = make_node (ENUMERAL_TYPE); pushtag (loc, name, enumtype); + if (fixed_underlying_type != NULL_TREE) + { + /* For an enum definition with a fixed underlying type, the + type is complete during the definition and the + enumeration constants have that type. If there was a + tag, the type was completed in c_parser_enum_specifier. + If not, it must be completed here. */ + ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = true; + TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (fixed_underlying_type); + TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (fixed_underlying_type); + TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (fixed_underlying_type); + SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (fixed_underlying_type)); + TYPE_SIZE (enumtype) = NULL_TREE; + TYPE_PRECISION (enumtype) = TYPE_PRECISION (fixed_underlying_type); + ENUM_UNDERLYING_TYPE (enumtype) = fixed_underlying_type; + layout_type (enumtype); + } } /* Update type location to the one of the definition, instead of e.g. a forward declaration. */ @@ -9336,10 +9406,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) TYPE_VALUES (enumtype) = NULL_TREE; } + if (ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) + && fixed_underlying_type == NULL_TREE) + error_at (loc, "%<enum%> declared with but defined without " + "fixed underlying type"); + the_enum->enum_next_value = integer_zero_node; + the_enum->enum_type = enumtype; the_enum->enum_overflow = 0; - if (flag_short_enums) + if (flag_short_enums && !ENUM_FIXED_UNDERLYING_TYPE_P (enumtype)) for (tree v = TYPE_MAIN_VARIANT (enumtype); v; v = TYPE_NEXT_VARIANT (v)) TYPE_PACKED (v) = 1; @@ -9403,54 +9479,61 @@ finish_enum (tree enumtype, tree values, tree attributes) (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)) + + if (!ENUM_FIXED_UNDERLYING_TYPE_P (enumtype)) { - if (precision > TYPE_PRECISION (enumtype)) + /* 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)) { - TYPE_PRECISION (enumtype) = 0; - error ("specified mode too small for enumerated values"); + if (precision > TYPE_PRECISION (enumtype)) + { + TYPE_PRECISION (enumtype) = 0; + error ("specified mode too small for enumerated values"); + } + else + precision = TYPE_PRECISION (enumtype); } else - precision = TYPE_PRECISION (enumtype); - } - else - TYPE_PRECISION (enumtype) = 0; - - if (TYPE_PACKED (enumtype) - || precision > TYPE_PRECISION (integer_type_node) - || TYPE_PRECISION (enumtype)) - { - tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); - if (tem == NULL) - { - /* 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; + TYPE_PRECISION (enumtype) = 0; + + if (TYPE_PACKED (enumtype) + || precision > TYPE_PRECISION (integer_type_node) + || TYPE_PRECISION (enumtype)) + { + tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); + if (tem == NULL) + { + /* 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; - TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); - TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); - TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); - SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (tem)); - TYPE_SIZE (enumtype) = NULL_TREE; - TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); + TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); + TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); + SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (tem)); + TYPE_SIZE (enumtype) = NULL_TREE; + TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + ENUM_UNDERLYING_TYPE (enumtype) = + c_common_type_for_size (TYPE_PRECISION (tem), TYPE_UNSIGNED (tem)); - layout_type (enumtype); + layout_type (enumtype); + } if (values != error_mark_node) { @@ -9477,8 +9560,10 @@ finish_enum (tree enumtype, tree values, tree attributes) 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) + enumerators fit in int. If the enum has a fixed + underlying type, the correct type was also given in + build_enumerator. */ + if (!ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) && wider_than_int) ini = convert (enumtype, ini); DECL_INITIAL (enu) = ini; @@ -9516,6 +9601,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); + ENUM_UNDERLYING_TYPE (tem) = ENUM_UNDERLYING_TYPE (enumtype); } /* Finish debugging output for this type. */ @@ -9595,56 +9681,89 @@ build_enumerator (location_t decl_loc, location_t loc, if (the_enum->enum_overflow) error_at (loc, "overflow in enumeration values"); } - /* 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). 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", + if (ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) + { + /* Enumeration constants must fit in the fixed underlying type. */ + if (!int_fits_type_p (value, ENUM_UNDERLYING_TYPE (the_enum->enum_type))) + error_at (loc, + "enumerator value outside the range of underlying type"); + /* Enumeration constants for an enum with fixed underlying type + have the enum type, both inside and outside the + definition. */ + value = convert (the_enum->enum_type, value); + } + else + { + /* 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). 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_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); + ? 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); + } /* Set basis for default for next value. */ - the_enum->enum_next_value - = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), - PLUS_EXPR, value, integer_one_node, false); + if (ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) + { + tree underlying_type = ENUM_UNDERLYING_TYPE (the_enum->enum_type); + if (TREE_CODE (underlying_type) == BOOLEAN_TYPE) + /* A value of 2 following a value of 1 overflows bool, but we + cannot carry out addition directly on bool without + promotion, and converting the result of arithmetic in a + wider type back to bool would not produce the right result + for this overflow check. */ + the_enum->enum_next_value = invert_truthvalue_loc (loc, value); + else + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), + PLUS_EXPR, convert (underlying_type, value), + convert (underlying_type, integer_one_node), + false); + } + else + the_enum->enum_next_value + = 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) + if (the_enum->enum_overflow + && !ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) { /* Choose a wider type with the same signedness if available. */ @@ -9691,7 +9810,8 @@ c_simulate_enum_decl (location_t loc, const char *name, input_location = loc; struct c_enum_contents the_enum; - tree enumtype = start_enum (loc, &the_enum, get_identifier (name)); + tree enumtype = start_enum (loc, &the_enum, get_identifier (name), + NULL_TREE); tree value_chain = NULL_TREE; string_int_pair *value; @@ -11980,6 +12100,9 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, } } specs->type = type; + if (spec.has_enum_type_specifier + && spec.kind != ctsk_tagdef) + specs->enum_type_specifier_ref_p = true; } return specs; diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index b468091..1a8b162 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -387,13 +387,7 @@ c_get_alias_set (tree t) /* Allow aliasing between enumeral types and the underlying integer type. This is required since those are compatible types. */ if (TREE_CODE (t) == ENUMERAL_TYPE) - { - tree t1 = c_common_type_for_size (tree_to_uhwi (TYPE_SIZE (t)), - /* short-cut commoning to signed - type. */ - false); - return get_alias_set (t1); - } + return get_alias_set (ENUM_UNDERLYING_TYPE (t)); return c_common_get_alias_set (t); } diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 602e023..5bdcd93 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -3011,6 +3011,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, } t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; declspecs_add_type (name_token->location, specs, t); continue; } @@ -3027,6 +3028,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; declspecs_add_type (loc, specs, t); continue; } @@ -3087,6 +3089,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, t.spec = c_parser_peek_token (parser)->value; t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; declspecs_add_type (loc, specs, t); c_parser_consume_token (parser); break; @@ -3151,6 +3154,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, t.spec = error_mark_node; t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; if (type != NULL) t.spec = groktypename (type, &t.expr, &t.expr_const_operands); @@ -3218,17 +3222,20 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, /* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2). enum-specifier: - enum gnu-attributes[opt] identifier[opt] { enumerator-list } - gnu-attributes[opt] - enum gnu-attributes[opt] identifier[opt] { enumerator-list , } - gnu-attributes[opt] + enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt] + { enumerator-list } gnu-attributes[opt] + enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt] + { enumerator-list , } gnu-attributes[opt] enum-type-specifier[opt] enum gnu-attributes[opt] identifier - The form with trailing comma is new in C99. The forms with - gnu-attributes are GNU extensions. In GNU C, we accept any expression - without commas in the syntax (assignment expressions, not just - conditional expressions); assignment expressions will be diagnosed - as non-constant. + The form with trailing comma is new in C99; enum-type-specifiers + are new in C2x. The forms with gnu-attributes are GNU extensions. + In GNU C, we accept any expression without commas in the syntax + (assignment expressions, not just conditional expressions); + assignment expressions will be diagnosed as non-constant. + + enum-type-specifier: + : specifier-qualifier-list enumerator-list: enumerator @@ -3256,6 +3263,7 @@ c_parser_enum_specifier (c_parser *parser) tree std_attrs = NULL_TREE; tree attrs; tree ident = NULL_TREE; + tree fixed_underlying_type = NULL_TREE; location_t enum_loc; location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); @@ -3274,6 +3282,83 @@ c_parser_enum_specifier (c_parser *parser) enum_loc = ident_loc; c_parser_consume_token (parser); } + if (c_parser_next_token_is (parser, CPP_COLON) + /* Distinguish an enum-type-specifier from a bit-field + declaration of the form "enum e : constant-expression;". */ + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + pedwarn_c11 (enum_loc, OPT_Wpedantic, + "ISO C does not support specifying %<enum%> underlying " + "types before C2X"); + if (ident) + { + /* The tag is in scope during the enum-type-specifier (which + may refer to the tag inside typeof). */ + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, + have_std_attrs, std_attrs, true); + if (!ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec)) + error_at (enum_loc, "%<enum%> declared both with and without " + "fixed underlying type"); + } + else + { + /* There must be an enum definition, so this initialization + (to avoid possible warnings about uninitialized data) + will be replaced later (either with the results of that + definition, or with the results of error handling for the + case of no tag and no definition). */ + ret.spec = NULL_TREE; + ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + ret.has_enum_type_specifier = true; + } + c_parser_consume_token (parser); + struct c_declspecs *specs = build_null_declspecs (); + c_parser_declspecs (parser, specs, false, true, false, false, false, + false, true, cla_prefer_id); + finish_declspecs (specs); + if (specs->default_int_p) + error_at (enum_loc, "no %<enum%> underlying type specified"); + else if (TREE_CODE (specs->type) != INTEGER_TYPE + && TREE_CODE (specs->type) != BOOLEAN_TYPE) + { + error_at (enum_loc, "invalid %<enum%> underlying type"); + specs->type = integer_type_node; + } + else if (specs->restrict_p) + error_at (enum_loc, "invalid use of %<restrict%>"); + fixed_underlying_type = TYPE_MAIN_VARIANT (specs->type); + if (ident) + { + /* The type specified must be consistent with any previously + specified underlying type. If this is a newly declared + type, it is now a complete type. */ + if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) + && ENUM_UNDERLYING_TYPE (ret.spec) == NULL_TREE) + { + TYPE_MIN_VALUE (ret.spec) = + TYPE_MIN_VALUE (fixed_underlying_type); + TYPE_MAX_VALUE (ret.spec) = + TYPE_MAX_VALUE (fixed_underlying_type); + TYPE_UNSIGNED (ret.spec) = TYPE_UNSIGNED (fixed_underlying_type); + SET_TYPE_ALIGN (ret.spec, TYPE_ALIGN (fixed_underlying_type)); + TYPE_SIZE (ret.spec) = NULL_TREE; + TYPE_PRECISION (ret.spec) = + TYPE_PRECISION (fixed_underlying_type); + ENUM_UNDERLYING_TYPE (ret.spec) = fixed_underlying_type; + layout_type (ret.spec); + } + else if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) + && !comptypes (fixed_underlying_type, + ENUM_UNDERLYING_TYPE (ret.spec))) + { + error_at (enum_loc, "%<enum%> underlying type incompatible with " + "previous declaration"); + fixed_underlying_type = ENUM_UNDERLYING_TYPE (ret.spec); + } + } + } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { /* Parse an enum definition. */ @@ -3284,7 +3369,7 @@ c_parser_enum_specifier (c_parser *parser) forward order at the end. */ tree values; timevar_push (TV_PARSE_ENUM); - type = start_enum (enum_loc, &the_enum, ident); + type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type); values = NULL_TREE; c_parser_consume_token (parser); while (true) @@ -3368,6 +3453,7 @@ c_parser_enum_specifier (c_parser *parser) ret.kind = ctsk_tagdef; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = fixed_underlying_type != NULL_TREE; timevar_pop (TV_PARSE_ENUM); return ret; } @@ -3378,6 +3464,7 @@ c_parser_enum_specifier (c_parser *parser) ret.kind = ctsk_tagref; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; return ret; } /* Attributes may only appear when the members are defined or in @@ -3386,15 +3473,18 @@ c_parser_enum_specifier (c_parser *parser) standard C). */ if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON)) c_parser_error (parser, "expected %<;%>"); - ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, - std_attrs); - /* In ISO C, enumerated types can be referred to only if already - defined. */ - if (pedantic && !COMPLETE_TYPE_P (ret.spec)) + if (fixed_underlying_type == NULL_TREE) { - gcc_assert (ident); - pedwarn (enum_loc, OPT_Wpedantic, - "ISO C forbids forward references to %<enum%> types"); + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, + std_attrs, false); + /* In ISO C, enumerated types without a fixed underlying type + can be referred to only if already defined. */ + if (pedantic && !COMPLETE_TYPE_P (ret.spec)) + { + gcc_assert (ident); + pedwarn (enum_loc, OPT_Wpedantic, + "ISO C forbids forward references to %<enum%> types"); + } } return ret; } @@ -3590,6 +3680,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) ret.kind = ctsk_tagdef; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; timevar_pop (TV_PARSE_STRUCT); return ret; } @@ -3600,6 +3691,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) ret.kind = ctsk_tagref; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; return ret; } /* Attributes may only appear when the members are defined or in @@ -3608,7 +3700,8 @@ c_parser_struct_or_union_specifier (c_parser *parser) c_parser_error (parser, "expected %<;%>"); /* ??? Existing practice is that GNU attributes are ignored after the struct or union keyword when not defining the members. */ - ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs); + ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs, + false); return ret; } @@ -3817,6 +3910,7 @@ c_parser_typeof_specifier (c_parser *parser) ret.spec = error_mark_node; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; if (c_parser_next_token_is_keyword (parser, RID_TYPEOF)) { is_unqual = false; @@ -19153,15 +19247,14 @@ restart: && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND - (TREE_OPERAND (lhs, 1), 0), 0))) - == BOOLEAN_TYPE) + && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND + (TREE_OPERAND (lhs, 1), 0), 0)))) /* Undo effects of boolean_increment for post {in,de}crement. */ lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); /* FALLTHRU */ case MODIFY_EXPR: if (TREE_CODE (lhs) == MODIFY_EXPR - && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) + && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (lhs, 0)))) { /* Undo effects of boolean_increment. */ if (integer_onep (TREE_OPERAND (lhs, 1))) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index e7cdd2f..d787dd4 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -122,6 +122,14 @@ along with GCC; see the file COPYING3. If not see been folded. */ #define SAVE_EXPR_FOLDED_P(EXP) TREE_LANG_FLAG_1 (SAVE_EXPR_CHECK (EXP)) +/* Whether a type has boolean semantics: either a boolean type or an + enumeration type with a boolean type as its underlying type. */ +#define C_BOOLEAN_TYPE_P(TYPE) \ + (TREE_CODE (TYPE) == BOOLEAN_TYPE \ + || (TREE_CODE (TYPE) == ENUMERAL_TYPE \ + && ENUM_UNDERLYING_TYPE (TYPE) != NULL_TREE \ + && TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE)) + /* Record parser information about an expression that is irrelevant for code generation alongside a tree representing its value. */ struct c_expr @@ -216,6 +224,10 @@ struct c_typespec { /* Whether the expression has operands suitable for use in constant expressions. */ bool expr_const_operands; + /* Whether the type specifier includes an enum type specifier (that + is, ": specifier-qualifier-list" in a declaration using + "enum"). */ + bool has_enum_type_specifier; /* The specifier itself. */ tree spec; /* An expression to be evaluated before the type specifier, in the @@ -412,6 +424,12 @@ struct c_declspecs { /* Whether any alignment specifier (even with zero alignment) was specified. */ BOOL_BITFIELD alignas_p : 1; + /* Whether an enum type specifier (": specifier-qualifier-list") was + specified other than in a definition of that enum (if so, this is + invalid unless it is an empty declaration "enum identifier + enum-type-specifier;", but such an empty declaration is valid in + C2x when "enum identifier;" would not be). */ + BOOL_BITFIELD enum_type_specifier_ref_p : 1; /* The address space that the declaration belongs to. */ addr_space_t address_space; }; @@ -525,6 +543,9 @@ struct c_enum_contents constant value. */ tree enum_next_value; + /* The enumeration type itself. */ + tree enum_type; + /* Nonzero means that there was overflow computing enum_next_value. */ int enum_overflow; }; @@ -625,7 +646,7 @@ extern void c_warn_unused_attributes (tree); extern tree c_warn_type_attributes (tree); extern void shadow_tag (const struct c_declspecs *); extern void shadow_tag_warned (const struct c_declspecs *, int); -extern tree start_enum (location_t, struct c_enum_contents *, tree); +extern tree start_enum (location_t, struct c_enum_contents *, tree, tree); extern bool start_function (struct c_declspecs *, struct c_declarator *, tree); extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool, tree, location_t * = NULL); @@ -637,7 +658,7 @@ extern void temp_store_parm_decls (tree, tree); extern void temp_pop_parm_decls (void); extern tree xref_tag (enum tree_code, tree); extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree, - bool, tree); + bool, tree, bool); extern struct c_parm *build_c_parm (struct c_declspecs *, tree, struct c_declarator *, location_t); extern struct c_declarator *build_attrs_declarator (tree, diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 92f3afc..6c16647 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -420,9 +420,11 @@ composite_type (tree t1, tree t2) (DR#013 question 3). For consistency, use the enumerated type as the composite type. */ - if (code1 == ENUMERAL_TYPE && code2 == INTEGER_TYPE) + if (code1 == ENUMERAL_TYPE + && (code2 == INTEGER_TYPE || code2 == BOOLEAN_TYPE)) return t1; - if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE) + if (code2 == ENUMERAL_TYPE + && (code1 == INTEGER_TYPE || code1 == BOOLEAN_TYPE)) return t2; gcc_assert (code1 == code2); @@ -1025,9 +1027,9 @@ tree common_type (tree t1, tree t2) { if (TREE_CODE (t1) == ENUMERAL_TYPE) - t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1); + t1 = ENUM_UNDERLYING_TYPE (t1); if (TREE_CODE (t2) == ENUMERAL_TYPE) - t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1); + t2 = ENUM_UNDERLYING_TYPE (t2); /* If both types are BOOLEAN_TYPE, then return boolean_type_node. */ if (TREE_CODE (t1) == BOOLEAN_TYPE @@ -1125,7 +1127,7 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, && COMPLETE_TYPE_P (t1) && TREE_CODE (t2) != ENUMERAL_TYPE) { - t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1)); + t1 = ENUM_UNDERLYING_TYPE (t1); if (TREE_CODE (t2) != VOID_TYPE) { if (enum_and_int_p != NULL) @@ -1138,7 +1140,7 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, && COMPLETE_TYPE_P (t2) && TREE_CODE (t1) != ENUMERAL_TYPE) { - t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2)); + t2 = ENUM_UNDERLYING_TYPE (t2); if (TREE_CODE (t1) != VOID_TYPE) { if (enum_and_int_p != NULL) @@ -2193,15 +2195,19 @@ perform_integral_promotions (tree exp) gcc_assert (INTEGRAL_TYPE_P (type)); - /* Normally convert enums to int, - but convert wide enums to something wider. */ + /* Convert enums to the result of applying the integer promotions to + their underlying type. */ if (code == ENUMERAL_TYPE) { - 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))); + type = ENUM_UNDERLYING_TYPE (type); + if (c_promoting_integer_type_p (type)) + { + if (TYPE_UNSIGNED (type) + && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) + type = unsigned_type_node; + else + type = integer_type_node; + } return convert (type, exp); } @@ -3932,7 +3938,7 @@ parser_build_binary_op (location_t location, enum tree_code code, } while (1); } - if (TREE_CODE (TREE_TYPE (t)) != BOOLEAN_TYPE) + if (!C_BOOLEAN_TYPE_P (TREE_TYPE (t))) warn_logical_not_parentheses (location, code, arg1.value, arg2.value); } @@ -4537,7 +4543,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, while (TREE_CODE (e) == COMPOUND_EXPR) e = TREE_OPERAND (e, 1); - if ((TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (TREE_TYPE (arg)) || truth_value_p (TREE_CODE (e)))) { auto_diagnostic_group d; @@ -4669,7 +4675,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, "decrement of enumeration value is invalid in C++"); } - if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) { if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) warning_at (location, OPT_Wbool_operation, @@ -4831,7 +4837,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, goto return_build_unary_op; } - if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) val = boolean_increment (code, arg); else val = build2 (code, TREE_TYPE (arg), arg, inc); @@ -7087,7 +7093,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, rhstype); bool save = in_late_binary_op; - if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE + if (C_BOOLEAN_TYPE_P (type) || codel == COMPLEX_TYPE || (coder == REAL_TYPE && (codel == INTEGER_TYPE || codel == ENUMERAL_TYPE) && sanitize_flags_p (SANITIZE_FLOAT_CAST))) @@ -7734,7 +7740,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, return convert (type, rhs); } - else if (codel == BOOLEAN_TYPE + else if (C_BOOLEAN_TYPE_P (type) /* The type nullptr_t may be converted to bool. The result is false. */ && (coder == POINTER_TYPE || coder == NULLPTR_TYPE)) @@ -11002,7 +11008,7 @@ c_finish_return (location_t loc, tree retval, tree origtype) return NULL_TREE; save = in_late_binary_op; - if (TREE_CODE (TREE_TYPE (res)) == BOOLEAN_TYPE + if (C_BOOLEAN_TYPE_P (TREE_TYPE (res)) || TREE_CODE (TREE_TYPE (res)) == COMPLEX_TYPE || (TREE_CODE (TREE_TYPE (t)) == REAL_TYPE && (TREE_CODE (TREE_TYPE (res)) == INTEGER_TYPE @@ -11164,7 +11170,7 @@ c_start_switch (location_t switch_loc, while (TREE_CODE (e) == COMPOUND_EXPR) e = TREE_OPERAND (e, 1); - if ((TREE_CODE (type) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (type) || truth_value_p (TREE_CODE (e))) /* Explicit cast to int suppresses this warning. */ && !(TREE_CODE (type) == INTEGER_TYPE @@ -12493,9 +12499,9 @@ build_binary_op (location_t location, enum tree_code code, else if (code1 == NULLPTR_TYPE && null_pointer_constant_p (orig_op0)) result_type = (INTEGRAL_TYPE_P (type0) ? build_pointer_type (type0) : type0); - if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op0)) || truth_value_p (TREE_CODE (orig_op0))) - ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE + ^ (C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op1)) || truth_value_p (TREE_CODE (orig_op1)))) maybe_warn_bool_compare (location, code, orig_op0, orig_op1); break; @@ -12638,9 +12644,9 @@ build_binary_op (location_t location, enum tree_code code, instrument_expr = build_call_expr_loc (location, tt, 2, op0, op1); } - if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op0)) || truth_value_p (TREE_CODE (orig_op0))) - ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE + ^ (C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op1)) || truth_value_p (TREE_CODE (orig_op1)))) maybe_warn_bool_compare (location, code, orig_op0, orig_op1); break; |