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"); +