public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C PATCH, v3] Fix for redeclared enumerator initialized with different type [PR115109]
@ 2024-06-01 15:02 Martin Uecker
  2024-06-03 17:37 ` Joseph Myers
  0 siblings, 1 reply; 4+ messages in thread
From: Martin Uecker @ 2024-06-01 15:02 UTC (permalink / raw)
  To: gcc-patches; +Cc: Joseph Myers


This is a new version of the patch.  I changed the overflow warning to
an error and added your other example to the test case.

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  <uecker@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 64924b87a91..38a4e842307 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10262,6 +10262,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.  */
 
@@ -10321,6 +10322,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
@@ -10387,9 +10405,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..0fa5d7534f3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-6.c
@@ -0,0 +1,20 @@
+/* { 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-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..0634c0aa698
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-enum-7.c
@@ -0,0 +1,41 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23" } */
+
+#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..961197d0c71
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr115109.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+#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) };
+


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-06-17 18:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-01 15:02 [C PATCH, v3] Fix for redeclared enumerator initialized with different type [PR115109] Martin Uecker
2024-06-03 17:37 ` Joseph Myers
2024-06-15 15:11   ` Martin Uecker
2024-06-17 18:54     ` Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).