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.
This commit is contained in:
parent
0f77d88fdf
commit
a3382d9d67
5 changed files with 64 additions and 16 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
27
gcc/testsuite/gcc.dg/gnu23-tag-6.c
Normal file
27
gcc/testsuite/gcc.dg/gnu23-tag-6.c
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
9
gcc/testsuite/gcc.dg/pr119612.c
Normal file
9
gcc/testsuite/gcc.dg/pr119612.c
Normal file
|
@ -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" } */
|
||||
|
Loading…
Add table
Reference in a new issue