]> gcc.gnu.org Git - gcc.git/commitdiff
c: Fix ICE with -g and -std=c23 related to incomplete types [PR114361]
authorJakub Jelinek <jakub@redhat.com>
Fri, 19 Apr 2024 22:05:21 +0000 (00:05 +0200)
committerJakub Jelinek <jakub@redhat.com>
Fri, 19 Apr 2024 22:05:21 +0000 (00:05 +0200)
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.

gcc/c/c-decl.cc
gcc/c/c-typeck.cc
gcc/testsuite/gcc.dg/c23-tag-incomplete-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c23-tag-incomplete-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr114361.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr114574-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr114574-2.c [new file with mode: 0644]

index 345090dae38b1c7e77d2d1ad0067b4b12bf1505a..52af8f32998dbcd04f3a1f4ec0c9945aace3aebe 100644 (file)
@@ -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));
index ddeab1e2a8a1c960f357ff41e008d170a4381f26..4567b114734b711df054b4502b522007e6563fd1 100644 (file)
@@ -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 (file)
index 0000000..837de05
--- /dev/null
@@ -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 (file)
index 0000000..ba36789
--- /dev/null
@@ -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 (file)
index 0000000..1d5baba
--- /dev/null
@@ -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 (file)
index 0000000..e125b68
--- /dev/null
@@ -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 (file)
index 0000000..0e70997
--- /dev/null
@@ -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 **);
This page took 0.079068 seconds and 5 git commands to generate.