https://gcc.gnu.org/g:a3382d9d675f42db96a51d902afc49a0a4cfadee
commit r15-9315-ga3382d9d675f42db96a51d902afc49a0a4cfadee Author: Martin Uecker <uec...@tugraz.at> Date: Fri Apr 4 21:01:48 2025 +0200 c: fix checking for a tag for variably modified tagged types [PR119612] The checking assertion added for PR118765 did not take into account that add_decl_expr can change TYPE_NAME to a TYPE_DECL with no name for certain cases of variably modified types. This also implies that we might sometimes not reliably detect the absence of a tag when only considering TYPE_NAME. This patch introduces a new helper function c_type_tag to reliable compute the tag for a tagged types and uses it for code where the switch to C23 may cause regressions. PR c/119612 gcc/c/ChangeLog: * c-tree.h (c_type_tag): Add prototype. * c-typeck.cc (c_type_tag): New function. (tagged_types_tu_compatible_p, composite_type_internal): Use c_type_tag. * c-decl.cc (c_struct_hasher::hash, previous_tag): Use c_type_tag. gcc/testsuite/ChangeLog: * gcc.dg/gnu23-tag-6.c: New test. * gcc.dg/pr119612.c: New test. Diff: --- gcc/c/c-decl.cc | 5 +++-- gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 38 ++++++++++++++++++++++++-------------- gcc/testsuite/gcc.dg/gnu23-tag-6.c | 27 +++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr119612.c | 9 +++++++++ 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index c778c7febfa0..8c420f229762 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -659,7 +659,8 @@ c_struct_hasher::hash (tree type) inchash::hash hstate; hstate.add_int (TREE_CODE (type)); - hstate.add_object (TYPE_NAME (type)); + tree tag = c_type_tag (type); + hstate.add_object (tag); return hstate.end (); } @@ -2073,7 +2074,7 @@ static tree previous_tag (tree type) { struct c_binding *b = NULL; - tree name = TYPE_NAME (type); + tree name = c_type_tag (type); if (name) b = I_TAG_BINDING (name); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 743ec5cbae61..2098120de297 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -795,6 +795,7 @@ c_type_unspecified_p (tree t) } extern bool char_type_p (tree); +extern tree c_type_tag (const_tree t); extern tree c_objc_common_truthvalue_conversion (location_t, tree, tree = integer_type_node); extern tree require_complete_type (location_t, tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 19e79b554dca..3870e8a15587 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -577,7 +577,7 @@ 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. */ + original type. See set_underlying_type. */ static const_tree c_type_original (const_tree t) { @@ -591,6 +591,26 @@ c_type_original (const_tree t) return t; } +/* Return the tag for a tagged type. */ +tree +c_type_tag (const_tree t) +{ + gcc_assert (RECORD_OR_UNION_TYPE_P (t) || TREE_CODE (t) == ENUMERAL_TYPE); + const_tree orig = c_type_original (t); + tree name = TYPE_NAME (orig); + if (!name) + return NULL_TREE; + if (TREE_CODE (name) == TYPE_DECL) + { + /* A TYPE_DECL added by add_decl_expr. */ + gcc_checking_assert (!DECL_NAME (name)); + return NULL_TREE; + } + gcc_checking_assert (TREE_CODE (name) == IDENTIFIER_NODE); + return name; +} + + /* Return the composite type of two compatible types. @@ -744,7 +764,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) 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))); + tree tag = c_type_tag (t1); gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2)); gcc_checking_assert (!tag || comptypes (t1, t2)); @@ -1807,17 +1827,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, { tree s1, s2; - /* 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. */ - 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)) + if (c_type_tag (t1) != c_type_tag (t2)) return false; /* When forming equivalence classes for TYPE_CANONICAL in C23, we treat @@ -1828,7 +1838,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, /* Different types without tag are incompatible except as an anonymous field or when forming equivalence classes for TYPE_CANONICAL. */ - if (!data->anon_field && !data->equiv && NULL_TREE == TYPE_NAME (t1)) + if (!data->anon_field && !data->equiv && NULL_TREE == c_type_tag (t1)) return false; if (!data->anon_field && TYPE_STUB_DECL (t1) != TYPE_STUB_DECL (t2)) diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-6.c b/gcc/testsuite/gcc.dg/gnu23-tag-6.c new file mode 100644 index 000000000000..b28c7b3bad99 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu23-tag-6.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu23" } */ + +int f(int n) +{ + struct foo { struct { char (*x)[n]; }; } a; + { + struct foo { struct { char (*x)[n]; }; } b = a; + } +} + +int g(int n) +{ + struct foo { struct { char (*x)[n]; }; } a; + { + struct foo { struct { char (*x)[n]; }; } *b = &a; + } +} + +int h(int n) +{ + struct foo { struct { struct bar { char (*x)[n]; }* p; }; } a; + { + struct foo { struct { struct bar { char (*x)[n]; }* p; }; } *b = &a; + } +} + diff --git a/gcc/testsuite/gcc.dg/pr119612.c b/gcc/testsuite/gcc.dg/pr119612.c new file mode 100644 index 000000000000..82bc5d99ce70 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr119612.c @@ -0,0 +1,9 @@ +/* PR c/119612 + * { dg-do compile } + * { dg-options "-std=gnu23" } + * */ + +int n = 3; +void a(struct { char (*p)[n]; } *); /* { dg-warning "anonymous struct" } */ +void b(struct { char (*p)[n]; } *); /* { dg-warning "anonymous struct" } */ +