This is a new version of the patch. This adds the -fno-short-enums flagĀ to the tests. I will commit it if the CI for am does not claim this time.
Bootstrapped and regression tested on x86_64. c23: Fix for redeclared enumerator initialized with different type [PR115109] c23 specifies that the type of a redeclared enumerator is the one of the previous declaration. Convert initializers with different type accordingly and emit an error when the value does not fit. 2024-06-01 Martin Uecker <uec...@tugraz.at> PR c/115109 gcc/c/ * c-decl.cc (build_enumerator): When redeclaring an enumerator convert value to previous type. For redeclared enumerators use underlying type for computing the next value. gcc/testsuite/ * gcc.dg/pr115109.c: New test. * gcc.dg/c23-tag-enum-6.c: New test. * gcc.dg/c23-tag-enum-7.c: New test. commit c8a0ec5150299689e6e36b0044ea811b82d90b2f Author: Martin Uecker <uec...@tugraz.at> Date: Sat May 18 22:00:04 2024 +0200 c23: Fix for redeclared enumerator initialized with different type [PR115109] c23 specifies that the type of a redeclared enumerator is the one of the previous declaration. Convert initializers with different type accordingly and emit an error when the value does not fit. 2024-06-01 Martin Uecker <uec...@tugraz.at> PR c/115109 gcc/c/ * c-decl.cc (build_enumerator): When redeclaring an enumerator convert value to previous type. For redeclared enumerators use underlying type for computing the next value. gcc/testsuite/ * gcc.dg/pr115109.c: New test. * gcc.dg/c23-tag-enum-6.c: New test. * gcc.dg/c23-tag-enum-7.c: New test. diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 6c09eb73128..01326570e2b 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -10277,6 +10277,7 @@ build_enumerator (location_t decl_loc, location_t loc, struct c_enum_contents *the_enum, tree name, tree value) { tree decl; + tree old_decl; /* Validate and default VALUE. */ @@ -10336,6 +10337,23 @@ build_enumerator (location_t decl_loc, location_t loc, definition. */ value = convert (the_enum->enum_type, value); } + else if (flag_isoc23 + && (old_decl = lookup_name_in_scope (name, current_scope)) + && old_decl != error_mark_node + && TREE_TYPE (old_decl) + && TREE_TYPE (TREE_TYPE (old_decl)) + && TREE_CODE (old_decl) == CONST_DECL) + { + /* Enumeration constants in a redeclaration have the previous type. */ + tree previous_type = TREE_TYPE (DECL_INITIAL (old_decl)); + if (!int_fits_type_p (value, previous_type)) + { + error_at (loc, "value of redeclared enumerator outside the range " + "of %qT", previous_type); + locate_old_decl (old_decl); + } + value = convert (previous_type, value); + } else { /* Even though the underlying type of an enum is unspecified, the @@ -10402,9 +10420,14 @@ build_enumerator (location_t decl_loc, location_t loc, false); } else - the_enum->enum_next_value - = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), - PLUS_EXPR, value, integer_one_node, false); + { + /* In a redeclaration the type can already be the enumeral type. */ + if (TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE) + value = convert (ENUM_UNDERLYING_TYPE (TREE_TYPE (value)), value); + 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 && !ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-6.c b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c new file mode 100644 index 00000000000..29aef7ee3fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -fno-short-enums" } */ + +#include <limits.h> + +enum E : int { a = 1, b = 2 }; +enum E : int { b = _Generic(a, enum E: 2), a = 1 }; + +enum H { x = 1 }; +enum H { x = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */ + +enum K : int { z = 1 }; +enum K : int { z = 2UL + UINT_MAX }; /* { dg-error "outside the range" } */ + +enum F { A = 0, B = UINT_MAX }; +enum F { B = UINT_MAX, A }; /* { dg-error "outside the range" } */ + +enum G : unsigned int { C = 0, D = UINT_MAX }; +enum G : unsigned int { D = UINT_MAX, C }; /* { dg-error "overflow" } */ + diff --git a/gcc/testsuite/gcc.dg/c23-tag-enum-7.c b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c new file mode 100644 index 00000000000..d4c787c8f71 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c @@ -0,0 +1,41 @@ +/* { dg-do compile } + * { dg-options "-std=c23 -fno-short-enums" } */ + +#include <limits.h> + +// enumerators are all representable in int +enum E { a = 1UL, b = _Generic(a, int: 2) }; +static_assert(_Generic(a, int: 1)); +static_assert(_Generic(b, int: 1)); +enum E { a = 1UL, b = _Generic(a, int: 2) }; +static_assert(_Generic(a, int: 1)); +static_assert(_Generic(b, int: 1)); + +// enumerators are not representable in int +enum H { c = 1UL << (UINT_WIDTH + 1), d = 2 }; +static_assert(_Generic(c, enum H: 1)); +static_assert(_Generic(d, enum H: 1)); +enum H { c = 1UL << (UINT_WIDTH + 1), d = _Generic(c, enum H: 2) }; +static_assert(_Generic(c, enum H: 1)); +static_assert(_Generic(d, enum H: 1)); + +// there is an overflow in the first declaration +enum K { e = UINT_MAX, f, g = _Generic(e, unsigned int: 0) + _Generic(f, unsigned long: 1) }; +static_assert(_Generic(e, enum K: 1)); +static_assert(_Generic(f, enum K: 1)); +static_assert(_Generic(g, enum K: 1)); +enum K { e = UINT_MAX, f, g = _Generic(e, enum K: 0) + _Generic(f, enum K: 1) }; +static_assert(_Generic(e, enum K: 1)); +static_assert(_Generic(f, enum K: 1)); +static_assert(_Generic(g, enum K: 1)); + +// there is an overflow in the first declaration +enum U { k = INT_MAX, l, m = _Generic(k, int: 0) + _Generic(l, long: 1) }; +static_assert(_Generic(k, enum U: 1)); +static_assert(_Generic(l, enum U: 1)); +static_assert(_Generic(m, enum U: 1)); +enum U { k = INT_MAX, l, m = _Generic(k, enum U: 0) + _Generic(l, enum U: 1) }; +static_assert(_Generic(k, enum U: 1)); +static_assert(_Generic(l, enum U: 1)); +static_assert(_Generic(m, enum U: 1)); + diff --git a/gcc/testsuite/gcc.dg/pr115109.c b/gcc/testsuite/gcc.dg/pr115109.c new file mode 100644 index 00000000000..4baee0f3445 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr115109.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -fno-short-enums" } */ + +#include <limits.h> + +enum E { a = 1UL << (ULONG_WIDTH - 5), b = 2 }; +enum E { a = 1ULL << (ULONG_WIDTH - 5), b = _Generic(a, enum E: 2) }; +