[committed] c: Fix ICE for nested enum redefinitions with/without fixed underlying type [PR112571]

Message ID e1257018-a84a-5eaa-66fa-ce23f7cbd33a@redhat.com
State Accepted
Headers
Series [committed] c: Fix ICE for nested enum redefinitions with/without fixed underlying type [PR112571] |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Joseph Myers Jan. 31, 2024, 9:42 p.m. UTC
  Bug 112571 reports an ICE-on-invalid for cases where an enum is
defined, without a fixed underlying type, inside the enum type
specifier for a definition of that same enum with a fixed underlying
type.

The ultimate cause is attempting to access ENUM_UNDERLYING_TYPE in a
case where it is NULL.  Avoid this by clearing
ENUM_FIXED_UNDERLYING_TYPE_P in thie case of inconsistent definitions.

Bootstrapped wth no regressions for x86_64-pc-linux-gnu.

	PR c/112571

gcc/c/
	* c-decl.cc (start_enum): Clear ENUM_FIXED_UNDERLYING_TYPE_P when
	defining without a fixed underlying type an enumeration previously
	declared with a fixed underlying type.

gcc/testsuite/
	* gcc.dg/c23-enum-9.c, gcc.dg/c23-enum-10.c: New tests.

---

Applied to mainline.  Should also be backported to GCC 13 branch (the
oldest version with support for enums with fixed underlying types),
after waiting to see if any problems arise with the patch on mainline,
subject to changing -std=c23 to -std=c2x for the older version and
making sure the patch does indeed work on the older version (there
have been significant changes renaming to redefinitions of tagged
types in GCC 14 as part of Martin's tag compatibility work).
  

Patch

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 8d18a3e11f4..934e557dc3b 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9905,8 +9905,11 @@  start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
 
   if (ENUM_FIXED_UNDERLYING_TYPE_P (enumtype)
       && fixed_underlying_type == NULL_TREE)
-    error_at (loc, "%<enum%> declared with but defined without "
-	      "fixed underlying type");
+    {
+      error_at (loc, "%<enum%> declared with but defined without "
+		"fixed underlying type");
+      ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = false;
+    }
 
   the_enum->enum_next_value = integer_zero_node;
   the_enum->enum_type = enumtype;
diff --git a/gcc/testsuite/gcc.dg/c23-enum-10.c b/gcc/testsuite/gcc.dg/c23-enum-10.c
new file mode 100644
index 00000000000..dd5f3453b1f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-enum-10.c
@@ -0,0 +1,6 @@ 
+/* PR c/112571.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+enum X : typeof (enum X { A }); /* { dg-error "declared with but defined without fixed underlying type" } */
+/* { dg-error "invalid 'enum' underlying type" "invalid" { target *-*-* } .-1 } */
diff --git a/gcc/testsuite/gcc.dg/c23-enum-9.c b/gcc/testsuite/gcc.dg/c23-enum-9.c
new file mode 100644
index 00000000000..10bb493ca3c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-enum-9.c
@@ -0,0 +1,8 @@ 
+/* PR c/112571.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+enum h : typeof (enum h { D }) { D }; /* { dg-error "declared with but defined without fixed underlying type" } */
+/* { dg-error "invalid 'enum' underlying type" "invalid" { target *-*-* } .-1 } */
+/* { dg-error "nested redefinition" "nested" { target *-*-* } .-2 } */
+/* { dg-error "conflicting redefinition" "conflicting" { target *-*-* } .-3 } */