aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2022-10-28 00:37:28 +0000
committerJoseph Myers <joseph@codesourcery.com>2022-10-28 00:37:28 +0000
commite0997c14af5e8bc4d26e28549cbce99364a1601f (patch)
tree84fb0f36a0673df481028555dc3da83a12cf9e63 /gcc/c
parent96069d8433775769804b5fa5576d6f59a723a6b6 (diff)
downloadgcc-e0997c14af5e8bc4d26e28549cbce99364a1601f.zip
gcc-e0997c14af5e8bc4d26e28549cbce99364a1601f.tar.gz
gcc-e0997c14af5e8bc4d26e28549cbce99364a1601f.tar.bz2
c: C2x enums with fixed underlying type [PR61469]
C2x adds support for enums with a fixed underlying type specified ("enum e : long long;" and similar). Implement this in the C front end. The same representation is used for these types as in C++, with two macros moved from cp-tree.h to c-common.h. Such enums can have bool as the underlying type, and various C front-end code checking for boolean types is adjusted to use a new C_BOOLEAN_TYPE_P to handle such enums the same way as bool. (Note that for C++ we have bug 96496 that enums with underlying type bool don't work correctly there.) There are various issues with the wording for such enums in the current C2x working draft (including but not limited to wording in the accepted paper that failed to make it into the working draft), which I intend to raise in NB comments. I think what I've implemented and added tests for matches the intent. Bootstrapped with no regressions for x86_64-pc-linux-gnu. PR c/61469 gcc/c-family/ * c-common.h (ENUM_UNDERLYING_TYPE, ENUM_FIXED_UNDERLYING_TYPE_P): New. Moved from cp/cp-tree.h. * c-warn.cc (warnings_for_convert_and_check): Do not consider conversions to enum with underlying type bool to overflow. gcc/c/ * c-convert.cc (c_convert): Handle enums with underlying boolean type like bool. * c-decl.cc (shadow_tag_warned): Allow shadowing declarations for enums with enum type specifier, but give errors for storage class specifiers, qualifiers or alignment specifiers in non-definition declarations of such enums. (grokdeclarator): Give error for non-definition use of type specifier with an enum type specifier. (parser_xref_tag): Add argument has_enum_type_specifier. Pass it to lookup_tag and use it to set ENUM_FIXED_UNDERLYING_TYPE_P. (xref_tag): Update call to parser_xref_tag. (start_enum): Add argument fixed_underlying_type. Complete enum type with a fixed underlying type given in the definition. Give error for defining without a fixed underlying type in the definition if one was given in a prior declaration. Do not mark enums with fixed underlying type as packed for -fshort-enums. Store the enum type in the_enum. (finish_enum): Do not adjust types of values or check their range for an enum with a fixed underlying type. Set underlying type of enum and variants. (build_enumerator): Check enumeration constants for enum with fixed underlying type against that type and convert to that type. Increment in the underlying integer type, with handling for bool. (c_simulate_enum_decl): Update call to start_enum. (declspecs_add_type): Set specs->enum_type_specifier_ref_p. * c-objc-common.cc (c_get_alias_set): Use ENUM_UNDERLYING_TYPE rather than recomputing an underlying type based on size. * c-parser.cc (c_parser_declspecs) (c_parser_struct_or_union_specifier, c_parser_typeof_specifier): Set has_enum_type_specifier for type specifiers. (c_parser_enum_specifier): Handle enum type specifiers. (c_parser_struct_or_union_specifier): Update call to parser_xref_tag. (c_parser_omp_atomic): Check for boolean increment or decrement using C_BOOLEAN_TYPE_P. * c-tree.h (C_BOOLEAN_TYPE_P): New. (struct c_typespec): Add has_enum_type_specifier. (struct c_declspecs): Add enum_type_specifier_ref_p. (struct c_enum_contents): Add enum_type. (start_enum, parser_xref_tag): Update prototypes. * c-typeck.cc (composite_type): Allow for enumerated types compatible with bool. (common_type, comptypes_internal, perform_integral_promotions): Use ENUM_UNDERLYING_TYPE. (parser_build_binary_op, build_unary_op, convert_for_assignment) (c_finish_return, c_start_switch, build_binary_op): Check for boolean types using C_BOOLEAN_TYPE_P. gcc/cp/ * cp-tree.h (ENUM_FIXED_UNDERLYING_TYPE_P, ENUM_UNDERLYING_TYPE): Remove. Moved to c-common.h. gcc/testsuite/ * gcc.dg/c11-enum-4.c, gcc.dg/c11-enum-5.c, gcc.dg/c11-enum-6.c, gcc.dg/c2x-enum-6.c, gcc.dg/c2x-enum-7.c, gcc.dg/c2x-enum-8.c, gcc.dg/gnu2x-enum-1.c: New tests.
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..2b83900e 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;