Bootstrapped and regression tested on x86_64.
c: Fix ICE when forming composite type for two structures / unions
[PR117548]
When forming the composite type from two tagged type, we need to find the
original type for a typedecl to get the correct tag.
PR c/117548
gcc/ChangeLog:
* c/c-decl.cc (finish_struct): Add checking assertion.
* c/c-typeck.cc (c_type_original): New function.
(composite_types_internal): Get tag from original type.
gcc/testsuite/ChangeLog:
* gcc.dg/pr117548.c: New test.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 07c18a34072..7e65bd04b11 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9872,6 +9872,9 @@ finish_struct (location_t loc, tree t, tree fieldlist,
tree attributes,
hashval_t hash = c_struct_hasher::hash (t);
gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t));
+ gcc_checking_assert (!TYPE_NAME (t)
+ || TREE_CODE (TYPE_NAME (t)) == IDENTIFIER_NODE);
+
tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT);
if (*e)
TYPE_CANONICAL (t) = *e;
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 10b02da8752..9212a8ebc0a 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -576,6 +576,21 @@ c_build_functype_attribute_variant (tree ntype, tree
otype, tree attrs)
}
+/* Given a type which could be a typedef name, make sure to return the
+ original type. */
+static const_tree
+c_type_original (const_tree t)
+{
+ /* It may even be a typedef of a typedef...
+ In the case of compiler-created builtin structs the TYPE_DECL
+ may be a dummy, with no DECL_ORIGINAL_TYPE. Don't fault. */
+ while (TYPE_NAME (t)
+ && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (t)))
+ t = DECL_ORIGINAL_TYPE (TYPE_NAME (t));
+ return t;
+}
+
/* Return the composite type of two compatible types.
@@ -728,8 +743,11 @@ composite_type_internal (tree t1, tree t2, struct
composite_cache* cache)
case UNION_TYPE:
if (flag_isoc23 && !comptypes_same_p (t1, t2))
{
+ /* Go to the original type to get the right tag. */
+ tree tag = TYPE_NAME (c_type_original (const_cast<tree> (t1)));
+
gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
- gcc_checking_assert (!TYPE_NAME (t1) || comptypes (t1, t2));
+ gcc_checking_assert (!tag || comptypes (t1, t2));
/* If a composite type for these two types is already under
construction, return it. */
@@ -742,7 +760,7 @@ composite_type_internal (tree t1, tree t2, struct
composite_cache* cache)
tree n = make_node (code1);
SET_TYPE_STRUCTURAL_EQUALITY (n);
- TYPE_NAME (n) = TYPE_NAME (t1);
+ TYPE_NAME (n) = tag;
struct composite_cache cache2 = { t1, t2, n, cache };
cache = &cache2;
@@ -1781,19 +1799,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree
t2,
/* We have to verify that the tags of the types are the same. This
is harder than it looks because this may be a typedef, so we have
- to go look at the original type. It may even be a typedef of a
- typedef...
- In the case of compiler-created builtin structs the TYPE_DECL
- may be a dummy, with no DECL_ORIGINAL_TYPE. Don't fault. */
- while (TYPE_NAME (t1)
- && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL
- && DECL_ORIGINAL_TYPE (TYPE_NAME (t1)))
- t1 = DECL_ORIGINAL_TYPE (TYPE_NAME (t1));
-
- while (TYPE_NAME (t2)
- && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL
- && DECL_ORIGINAL_TYPE (TYPE_NAME (t2)))
- t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2));
+ to go look at the original type. */
+ t1 = c_type_original (t1);
+ t2 = c_type_original (t2);
if (TYPE_NAME (t1) != TYPE_NAME (t2))
return false;
diff --git a/gcc/testsuite/gcc.dg/pr117548.c b/gcc/testsuite/gcc.dg/pr117548.c
new file mode 100644
index 00000000000..d388d2587c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr117548.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+typedef struct A { int q; } A;
+void f(A*);
+
+int main(void)
+{
+ struct A { int q; };
+ void f(struct A*);
+}
+