This is a workaround for another issue related to PR118765.
I do not yet understand what goes wrong in merge_decls in
this case (somehow we end up with TYPE_DECLS where
DECL_ORIGINAL_TYPE is not set correctly, so we can not
determine the correct tag later), so I do not merge
these TYPE_DECLS in this specific case as a workaround
and add a "sorry" for the alignment case (or should this
simply become an error?).


Bootstrapped and regression tested on x86_64.


commit 56c2c96ef4ebd24290fbf8f66b277d420a68b032
Author: Martin Uecker <uec...@tugraz.at>
Date:   Sun Mar 16 10:54:17 2025 +0100

    c: Fix tagname confusion for typedef redefinitions [PR118765]
    
    When we redefine a typedef for a tagged type that has just been
    redefined, merge_decls may produce invalid TYPE_DECLS that are not
    consistent with what set_underlying_type produces.  Do not call
    merge_decls in this specific case for now and instead return the
    new declaration.  If the user used inconsistent alignment for
    different typedef declarations, emit a sorry message.
    
            PR c/118765
    
    gcc/ChangeLog:
            * c/c-decl.cc (diagnose_mismatched_decls): Return false
            for typedef redefinitions of redefined tagged types.
            * c/c-typeck.cc (tagged_types_tu_compatible_p): Add
            checking assertions.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/pr118765-2.c: New test.
            * gcc.dg/typedef-redecl3.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 1ae520828c3..58b1c41b961 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2360,6 +2360,21 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                            "redefinition of typedef %q+D", newdecl))
        locate_old_decl (olddecl);
 
+      /* FIXME: merge_decls produces incorrect TYPE_DECLS for redefinitions
+        that involve defined tagged types.  Use the new declaration for now. */
+      if (TYPE_MAIN_VARIANT (newtype) != TYPE_MAIN_VARIANT (oldtype)
+         && flag_isoc23
+         && (RECORD_OR_UNION_TYPE_P (newtype)
+             || ENUMERAL_TYPE == TREE_CODE (newtype)))
+       {
+         if (TYPE_ALIGN (newtype) != TYPE_ALIGN (oldtype))
+           {
+             sorry ("redefinition of typedef %q+D with different alignment "
+                    "is not supported for redefined tagged types", newdecl);
+             locate_old_decl (olddecl);
+           }
+         return false;
+       }
       return true;
     }
 
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 1a39cbb2009..c91b7dddae8 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1812,6 +1812,10 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
      to go look at the original type.  */
   t1 = c_type_original (t1);
   t2 = c_type_original (t2);
+  gcc_checking_assert (!TYPE_NAME (t1)
+                      || TREE_CODE (TYPE_NAME (t1)) == IDENTIFIER_NODE);
+  gcc_checking_assert (!TYPE_NAME (t2)
+                      || TREE_CODE (TYPE_NAME (t2)) == IDENTIFIER_NODE);
 
   if (TYPE_NAME (t1) != TYPE_NAME (t2))
     return false;
diff --git a/gcc/testsuite/gcc.dg/pr118765-2.c 
b/gcc/testsuite/gcc.dg/pr118765-2.c
new file mode 100644
index 00000000000..0c3e4988118
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr118765-2.c
@@ -0,0 +1,33 @@
+/* { dg-do "compile" } */
+/* { dg-options "-std=gnu23" } */
+
+typedef struct q { int x; } q_t;
+typedef struct q { int x; } q_t;
+typedef struct q { int x; } q_t;
+typedef struct q { int x; } q_t;
+typedef struct q { int x; } q_t;
+
+typedef struct r r_t;
+typedef struct r r_t;
+typedef struct r r_t;
+typedef struct r r_t;
+typedef struct r r_t;
+
+extern struct s { int x; } s;
+extern struct s { int x; } s;
+extern struct s { int x; } s;
+extern struct s { int x; } s;
+extern struct s { int x; } s;
+
+struct t { int x; };
+struct t { int x; };
+struct t { int x; };
+struct t { int x; };
+struct t { int x; };
+
+typedef enum e { E = 1 } e_t;
+typedef enum e { E = 1 } e_t;
+typedef enum e { E = 1 } e_t;
+typedef enum e { E = 1 } e_t;
+typedef enum e { E = 1 } e_t;
+
diff --git a/gcc/testsuite/gcc.dg/typedef-redecl3.c 
b/gcc/testsuite/gcc.dg/typedef-redecl3.c
new file mode 100644
index 00000000000..a2424d6b7ab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/typedef-redecl3.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+#define N 64
+
+struct f { int x; };
+typedef struct f T;
+typedef struct f T __attribute__((aligned (N)));
+typedef struct f T __attribute__((aligned (N * 2)));
+typedef struct f T __attribute__((aligned (N)));
+typedef struct f T;
+
+_Static_assert (_Alignof (T) == N * 2, "N * 2");
+
+enum g { A = 1 };
+typedef enum g S;
+typedef enum g S __attribute__((aligned (N)));
+typedef enum g S __attribute__((aligned (N * 2)));
+typedef enum g S __attribute__((aligned (N)));
+typedef enum g S;
+
+_Static_assert (_Alignof (S) == N * 2, "N * 2");
+

Reply via email to