aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-10-28 10:02:34 +0200
committerMartin Liska <mliska@suse.cz>2022-10-28 10:02:34 +0200
commit1eb021edb27e26f95cda63df121f6bc951647599 (patch)
tree7f132fded85bd7d05d81cd4c1227da2fd0c3c2d5 /gcc/c
parent62e475bad0d668c432bb97113cbf73fa281b8b55 (diff)
parent0607307768b66a90e27c5bc91a247acc938f070e (diff)
downloadgcc-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.cc8
-rw-r--r--gcc/c/c-decl.cc325
-rw-r--r--gcc/c/c-objc-common.cc8
-rw-r--r--gcc/c/c-parser.cc139
-rw-r--r--gcc/c/c-tree.h25
-rw-r--r--gcc/c/c-typeck.cc56
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;