aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-tree.h
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/c-tree.h
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/c-tree.h')
-rw-r--r--gcc/c/c-tree.h25
1 files changed, 23 insertions, 2 deletions
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,