aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c/c-decl.cc5
-rw-r--r--gcc/c/c-tree.h1
-rw-r--r--gcc/c/c-typeck.cc38
-rw-r--r--gcc/testsuite/gcc.dg/gnu23-tag-6.c27
-rw-r--r--gcc/testsuite/gcc.dg/pr119612.c9
5 files changed, 64 insertions, 16 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index c778c7f..8c420f2 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 743ec5c..2098120 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 19e79b5..3870e8a 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 0000000..b28c7b3
--- /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 0000000..82bc5d9
--- /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" } */
+