From d8af6c203f18b4fd736df9567926589d96f8e0b3 Mon Sep 17 00:00:00 2001 From: Martin Uecker Date: Thu, 14 Nov 2024 20:54:33 +0100 Subject: [PATCH] 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/c/ChangeLog: * c-decl.cc (finish_struct): Add checking assertion. * 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. --- gcc/c/c-decl.cc | 3 +++ gcc/c/c-typeck.cc | 38 ++++++++++++++++++++------------- gcc/testsuite/gcc.dg/pr117548.c | 12 +++++++++++ 3 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr117548.c 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 (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*); +} +