Re: [C PATCH 4/6] c23: tag compatibility rules for enums

2023-11-07 Thread Joseph Myers
On Sat, 26 Aug 2023, Martin Uecker via Gcc-patches wrote:

> Allow redefinition of enum types and enumerators.
> 
> gcc/c:
>   * c-decl.cc (start_num): Allow redefinition.

start_enum not start_num.

> @@ -9606,9 +9624,15 @@ start_enum (location_t loc, struct c_enum_contents 
> *the_enum, tree name,
>if (name != NULL_TREE)
>  enumtype = lookup_tag (ENUMERAL_TYPE, name, true, );
>  
> +  if (flag_isoc2x && enumtype != NULL_TREE
> +  && TREE_CODE (enumtype) == ENUMERAL_TYPE
> +  && TYPE_VALUES (enumtype) != NULL_TREE)
> +enumtype = NULL_TREE;

Much the same comment applies as on the struct/union patch regarding 
ensuring nested redefinitions are detected when there's a previous 
definition outside the two nested definitions, in addition to the point 
there about making sure that a definition nested inside an enum type 
specifier for another definition of the same enum gets detected.

-- 
Joseph S. Myers
jos...@codesourcery.com


[C PATCH 4/6] c23: tag compatibility rules for enums

2023-08-26 Thread Martin Uecker via Gcc-patches



Allow redefinition of enum types and enumerators.

gcc/c:
* c-decl.cc (start_num): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.

gcc/testsuide/:
* gcc.dg/c2x-tag-enum-1.c: New test.
* gcc.dg/c2x-tag-enum-2.c: New test.
* gcc.dg/c2x-tag-enum-3.c: New test.
* gcc.dg/c2x-tag-enum-4.c: New test.
---
 gcc/c/c-decl.cc   | 47 --
 gcc/c/c-typeck.cc |  5 ++-
 gcc/testsuite/gcc.dg/c2x-tag-enum-1.c | 56 +++
 gcc/testsuite/gcc.dg/c2x-tag-enum-2.c | 23 +++
 gcc/testsuite/gcc.dg/c2x-tag-enum-3.c |  7 
 gcc/testsuite/gcc.dg/c2x-tag-enum-4.c | 22 +++
 6 files changed, 155 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index c5c6a853fa9..b514e8a35ee 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2064,9 +2064,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
 {
-  auto_diagnostic_group d;
-  error ("redeclaration of enumerator %q+D", newdecl);
-  locate_old_decl (olddecl);
+  if (flag_isoc2x
+ && TYPE_NAME (DECL_CONTEXT (newdecl))
+ && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
+ && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT 
(olddecl)))
+   {
+ if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL 
(newdecl)))
+   {
+ auto_diagnostic_group d;
+ error ("conflicting redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
+   }
+  else
+   {
+ auto_diagnostic_group d;
+ error ("redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
   return false;
 }
 
@@ -3227,8 +3242,11 @@ pushdecl (tree x)
 
   /* Must set DECL_CONTEXT for everything not at file scope or
  DECL_FILE_SCOPE_P won't work.  Local externs don't count
- unless they have initializers (which generate code).  */
+ unless they have initializers (which generate code).  We
+ also exclude CONST_DECLs because enumerators will get the
+ type of the enum as context.  */
   if (current_function_decl
+  && TREE_CODE (x) != CONST_DECL
   && (!VAR_OR_FUNCTION_DECL_P (x)
  || DECL_INITIAL (x) || !TREE_PUBLIC (x)))
 DECL_CONTEXT (x) = current_function_decl;
@@ -9606,9 +9624,15 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
   if (name != NULL_TREE)
 enumtype = lookup_tag (ENUMERAL_TYPE, name, true, );
 
+  if (flag_isoc2x && enumtype != NULL_TREE
+  && TREE_CODE (enumtype) == ENUMERAL_TYPE
+  && TYPE_VALUES (enumtype) != NULL_TREE)
+enumtype = NULL_TREE;
+
   if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
 {
   enumtype = make_node (ENUMERAL_TYPE);
+  TYPE_SIZE (enumtype) = NULL_TREE;
   pushtag (loc, name, enumtype);
   if (fixed_underlying_type != NULL_TREE)
{
@@ -9868,6 +9892,20 @@ finish_enum (tree enumtype, tree values, tree attributes)
   && !in_sizeof && !in_typeof && !in_alignof)
 struct_parse_info->struct_types.safe_push (enumtype);
 
+  /* Check for consistency with previous definition */
+  if (flag_isoc2x)
+{
+  tree vistype = previous_tag (enumtype);
+  if (vistype
+ && TREE_CODE (vistype) == TREE_CODE (enumtype)
+ && !C_TYPE_BEING_DEFINED (vistype))
+   {
+ TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (enumtype);
+ if (!comptypes_same_p (enumtype, vistype))
+   error("conflicting redefinition of enum %qT", enumtype);
+   }
+}
+
   C_TYPE_BEING_DEFINED (enumtype) = 0;
 
   return enumtype;
@@ -10047,6 +10085,7 @@ build_enumerator (location_t decl_loc, location_t loc,
 
   decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value));
   DECL_INITIAL (decl) = value;
+  DECL_CONTEXT (decl) = the_enum->enum_type;
   pushdecl (decl);
 
   return tree_cons (decl, value, NULL_TREE);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 802c727d9d3..2b79cbba950 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1396,6 +1396,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
 {
 case ENUMERAL_TYPE:
   {
+   if (!comptypes (ENUM_UNDERLYING_TYPE (t1), ENUM_UNDERLYING_TYPE (t2)))
+ return false;
+
/* Speed up the case where the type values are in the same order.  */
tree tv1 = TYPE_VALUES (t1);
tree