diff mbox series

[C] Fix for redeclared enumerator initialized with different type [PR115109]

Message ID 45067a3258e0ec1677ed95f62ac21c1353d66355.camel@tugraz.at
State New
Headers show
Series [C] Fix for redeclared enumerator initialized with different type [PR115109] | expand

Commit Message

Martin Uecker May 18, 2024, 8:18 p.m. UTC
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 add -Woverflow warning.
    
    2024-05-18 Martin Uecker  <uecker@tugraz.at>
    
    PR c/115109
    
    gcc/c/
            * c-decl.cc (build_enumerator): When redeclaring an
              enumerator convert value to previous type.
    
    gcc/testsuite/
            * gcc.dg/pr115109.c: New test.
            * gcc.dg/c23-tag-enum-6.c: New test.
diff mbox series

Patch

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b691b91b3db..08a51c7ad50 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10209,6 +10209,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.  */
 
@@ -10268,6 +10269,25 @@  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)
+    {
+      tree previous_type = TREE_TYPE (TREE_TYPE (old_decl));
+
+      if (!int_fits_type_p (value, previous_type))
+	{
+	  warning_at (loc, OPT_Woverflow,
+		      "value of redeclared enumerator outside the range of "
+		      "the previous type %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
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..ff9ec89775e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
@@ -0,0 +1,14 @@ 
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+#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-warning "outside the range" } */
+
+enum K : int { z = 1 };
+enum K : int { z = 2UL + UINT_MAX };	/* { dg-error "outside the range" } */
+
diff --git a/gcc/testsuite/gcc.dg/pr115109.c b/gcc/testsuite/gcc.dg/pr115109.c
new file mode 100644
index 00000000000..0c327ce1697
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr115109.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+enum E { a = 1L, b = 2 };
+enum E { a = 1L, b = _Generic(a, enum E: 2) };
+