aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-04-20 00:05:21 +0200
committerJakub Jelinek <jakub@redhat.com>2024-04-20 00:05:21 +0200
commita39983bf58d3097c472252f6989d19b60909dd9a (patch)
treedad65b4b2d5eab51977f75e08b3831bdbc6cd6ff
parentd86472a6f041ccf3d1be0cf6bb15d1e0ad8f6dbe (diff)
downloadgcc-a39983bf58d3097c472252f6989d19b60909dd9a.zip
gcc-a39983bf58d3097c472252f6989d19b60909dd9a.tar.gz
gcc-a39983bf58d3097c472252f6989d19b60909dd9a.tar.bz2
c: Fix ICE with -g and -std=c23 related to incomplete types [PR114361]
We did not update TYPE_CANONICAL for incomplete variants when completing a structure. We now set for flag_isoc23 TYPE_STRUCTURAL_EQUALITY_P for incomplete structure and union types and then update TYPE_CANONICAL later, though update it only for the variants and derived pointer types which can be easily discovered. Other derived types created while the type was still incomplete will remain TYPE_STRUCTURAL_EQUALITY_P. See PR114574 for discussion. 2024-04-20 Martin Uecker <uecker@tugraz.at> Jakub Jelinek <jakub@redhat.com> PR lto/114574 PR c/114361 gcc/c/ * c-decl.cc (shadow_tag_warned): For flag_isoc23 and code not ENUMERAL_TYPE use SET_TYPE_STRUCTURAL_EQUALITY. (parser_xref_tag): Likewise. (start_struct): For flag_isoc23 use SET_TYPE_STRUCTURAL_EQUALITY. (c_update_type_canonical): New function. (finish_struct): Put NULL as second == operand rather than first. Assert TYPE_STRUCTURAL_EQUALITY_P. Call c_update_type_canonical. * c-typeck.cc (composite_type_internal): Use SET_TYPE_STRUCTURAL_EQUALITY. Formatting fix. gcc/testsuite/ * gcc.dg/pr114574-1.c: New test. * gcc.dg/pr114574-2.c: New test. * gcc.dg/pr114361.c: New test. * gcc.dg/c23-tag-incomplete-1.c: New test. * gcc.dg/c23-tag-incomplete-2.c: New test.
-rw-r--r--gcc/c/c-decl.cc49
-rw-r--r--gcc/c/c-typeck.cc4
-rw-r--r--gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c11
-rw-r--r--gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c11
-rw-r--r--gcc/testsuite/gcc.dg/pr114361.c10
-rw-r--r--gcc/testsuite/gcc.dg/pr114574-1.c7
-rw-r--r--gcc/testsuite/gcc.dg/pr114574-2.c7
7 files changed, 97 insertions, 2 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 345090d..52af8f3 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5051,6 +5051,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
if (t == NULL_TREE)
{
t = make_node (code);
+ if (flag_isoc23 && code != ENUMERAL_TYPE)
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
pushtag (input_location, name, t);
}
}
@@ -8809,6 +8811,8 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name,
the forward-reference will be altered into a real type. */
ref = make_node (code);
+ if (flag_isoc23 && code != ENUMERAL_TYPE)
+ SET_TYPE_STRUCTURAL_EQUALITY (ref);
if (code == ENUMERAL_TYPE)
{
/* Give the type a default layout like unsigned int
@@ -8910,6 +8914,8 @@ start_struct (location_t loc, enum tree_code code, tree name,
if (ref == NULL_TREE || TREE_CODE (ref) != code)
{
ref = make_node (code);
+ if (flag_isoc23)
+ SET_TYPE_STRUCTURAL_EQUALITY (ref);
pushtag (loc, name, ref);
}
@@ -9347,6 +9353,45 @@ is_flexible_array_member_p (bool is_last_field,
return false;
}
+/* Recompute TYPE_CANONICAL for variants of the type including qualified
+ versions of the type and related pointer types after an aggregate type
+ has been finalized.
+ Will not update array types, pointers to array types, function
+ types and other derived types created while the type was still
+ incomplete, those will remain TYPE_STRUCTURAL_EQUALITY_P. */
+
+static void
+c_update_type_canonical (tree t)
+{
+ for (tree x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
+ {
+ if (x != t && TYPE_STRUCTURAL_EQUALITY_P (x))
+ {
+ if (TYPE_QUALS (x) == TYPE_QUALS (t))
+ TYPE_CANONICAL (x) = TYPE_CANONICAL (t);
+ else if (TYPE_CANONICAL (t) != t
+ || check_qualified_type (x, t, TYPE_QUALS (x)))
+ TYPE_CANONICAL (x)
+ = build_qualified_type (TYPE_CANONICAL (t), TYPE_QUALS (x));
+ else
+ TYPE_CANONICAL (x) = x;
+ }
+ else if (x != t)
+ continue;
+ for (tree p = TYPE_POINTER_TO (x); p; p = TYPE_NEXT_PTR_TO (p))
+ {
+ if (!TYPE_STRUCTURAL_EQUALITY_P (p))
+ continue;
+ if (TYPE_CANONICAL (x) != x || TYPE_REF_CAN_ALIAS_ALL (p))
+ TYPE_CANONICAL (p)
+ = build_pointer_type_for_mode (TYPE_CANONICAL (x), TYPE_MODE (p),
+ false);
+ else
+ TYPE_CANONICAL (p) = p;
+ c_update_type_canonical (p);
+ }
+ }
+}
/* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
LOC is the location of the RECORD_TYPE or UNION_TYPE's definition.
@@ -9695,11 +9740,12 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
/* Set type canonical based on equivalence class. */
if (flag_isoc23)
{
- if (NULL == c_struct_htab)
+ if (c_struct_htab == NULL)
c_struct_htab = hash_table<c_struct_hasher>::create_ggc (61);
hashval_t hash = c_struct_hasher::hash (t);
+ gcc_checking_assert (TYPE_STRUCTURAL_EQUALITY_P (t));
tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT);
if (*e)
TYPE_CANONICAL (t) = *e;
@@ -9708,6 +9754,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
TYPE_CANONICAL (t) = t;
*e = t;
}
+ c_update_type_canonical (t);
}
tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ddeab1e..4567b11 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -532,6 +532,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
/* Otherwise, create a new type node and link it into the cache. */
tree n = make_node (code1);
+ SET_TYPE_STRUCTURAL_EQUALITY (n);
TYPE_NAME (n) = TYPE_NAME (t1);
struct composite_cache cache2 = { t1, t2, n, cache };
@@ -590,7 +591,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
TYPE_STUB_DECL (n) = pushdecl (build_decl (input_location, TYPE_DECL,
NULL_TREE, n));
- n = finish_struct(input_location, n, fields, attributes, NULL, &expr);
+ n = finish_struct (input_location, n, fields, attributes, NULL,
+ &expr);
n = qualify_type (n, t1);
diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c b/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c
new file mode 100644
index 0000000..837de05
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23 -g" } */
+
+struct a;
+typedef struct a b;
+
+void g() {
+ struct a { b* x; };
+}
+
+struct a { b* x; };
diff --git a/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c b/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c
new file mode 100644
index 0000000..ba36789
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile }
+ * { dg-options "-std=c23 -g" } */
+
+struct a;
+typedef struct a b;
+
+void f() {
+ extern struct a { b* x; } t;
+}
+
+extern struct a { b* x; } t;
diff --git a/gcc/testsuite/gcc.dg/pr114361.c b/gcc/testsuite/gcc.dg/pr114361.c
new file mode 100644
index 0000000..1d5baba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114361.c
@@ -0,0 +1,10 @@
+/* PR c/114361 */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23 -g" } */
+
+void f()
+{
+ typedef struct foo bar;
+ typedef __typeof( ({ (struct foo { bar *x; }){ }; }) ) wuz;
+ struct foo { wuz *x; };
+}
diff --git a/gcc/testsuite/gcc.dg/pr114574-1.c b/gcc/testsuite/gcc.dg/pr114574-1.c
new file mode 100644
index 0000000..e125b68
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114574-1.c
@@ -0,0 +1,7 @@
+/* PR lto/114574
+ * { dg-do compile }
+ * { dg-options "-flto" } */
+
+const struct S * x;
+struct S {};
+void f(const struct S **);
diff --git a/gcc/testsuite/gcc.dg/pr114574-2.c b/gcc/testsuite/gcc.dg/pr114574-2.c
new file mode 100644
index 0000000..0e70997
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr114574-2.c
@@ -0,0 +1,7 @@
+/* PR lto/114574
+ * { dg-do compile }
+ * { dg-options "-flto -std=c23" } */
+
+const struct S * x;
+struct S {};
+void f(const struct S **);