https://gcc.gnu.org/g:beca4454ff9990d8fa1ba4e7c30b18af0e6cca2b

commit r16-9089-gbeca4454ff9990d8fa1ba4e7c30b18af0e6cca2b
Author: Martin Uecker <[email protected]>
Date:   Sat Feb 28 17:12:43 2026 +0100

    c: Fix recursive structure / union redeclaration with qualifiers [PR124303]
    
    We reject correct recursive redeclarations when qualifiers are involved.
    The reason is that the check is done before the variants are completed.
    
            PR c/124303
    
    gcc/c/ChangeLog:
            * c-decl.cc (finish_struct): Check for consistency of
            declarations after completing variants.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/pr124303.c: New test.
    
    (cherry picked from commit 7c3e6df8ae01a473fba63e12efe2c82bd50ad502)

Diff:
---
 gcc/c/c-decl.cc                 | 34 +++++++++++++++++-----------------
 gcc/testsuite/gcc.dg/pr124303.c |  7 +++++++
 2 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index ddcf06bf5d65..98765710e090 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9971,6 +9971,23 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
       warning_at (loc, 0, "union cannot be made transparent");
     }
 
+  tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
+  for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
+    {
+      TYPE_FIELDS (x) = TYPE_FIELDS (t);
+      TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
+      TYPE_TRANSPARENT_AGGR (x) = TYPE_TRANSPARENT_AGGR (t);
+      TYPE_TYPELESS_STORAGE (x) = TYPE_TYPELESS_STORAGE (t);
+      C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
+      C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
+      C_TYPE_FIELDS_NON_CONSTEXPR (x) = C_TYPE_FIELDS_NON_CONSTEXPR (t);
+      C_TYPE_FIELDS_HAS_COUNTED_BY (x) = C_TYPE_FIELDS_HAS_COUNTED_BY (t);
+      C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
+      C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t);
+      C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE;
+      TYPE_INCLUDES_FLEXARRAY (x) = TYPE_INCLUDES_FLEXARRAY (t);
+    }
+
   /* Check for consistency with previous definition.  */
   if (flag_isoc23 && NULL != enclosing_struct_parse_info)
     {
@@ -10025,23 +10042,6 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
       c_update_type_canonical (t);
     }
 
-  tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
-  for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
-    {
-      TYPE_FIELDS (x) = TYPE_FIELDS (t);
-      TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
-      TYPE_TRANSPARENT_AGGR (x) = TYPE_TRANSPARENT_AGGR (t);
-      TYPE_TYPELESS_STORAGE (x) = TYPE_TYPELESS_STORAGE (t);
-      C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
-      C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
-      C_TYPE_FIELDS_NON_CONSTEXPR (x) = C_TYPE_FIELDS_NON_CONSTEXPR (t);
-      C_TYPE_FIELDS_HAS_COUNTED_BY (x) = C_TYPE_FIELDS_HAS_COUNTED_BY (t);
-      C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
-      C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t);
-      C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE;
-      TYPE_INCLUDES_FLEXARRAY (x) = TYPE_INCLUDES_FLEXARRAY (t);
-    }
-
   /* Update type location to the one of the definition, instead of e.g.
      a forward declaration.  */
   if (TYPE_STUB_DECL (t))
diff --git a/gcc/testsuite/gcc.dg/pr124303.c b/gcc/testsuite/gcc.dg/pr124303.c
new file mode 100644
index 000000000000..e7075875108b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr124303.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+struct s { void (*p)(const struct s*); };
+struct s { void (*p)(const struct s*); };
+
+

Reply via email to