]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
C23: allow aliasing for types derived from structs with variable size
authorMartin Uecker <uecker@tugraz.at>
Fri, 24 May 2024 10:35:27 +0000 (12:35 +0200)
committerMartin Uecker <uecker@tugraz.at>
Fri, 31 May 2024 05:12:34 +0000 (07:12 +0200)
Previously, we set the aliasing set of structures with variable size

struct foo { int x[n]; char b; };

to zero. The reason is that such types can be compatible to diffrent
structure types which are incompatible.

struct foo { int x[2]; char b; };
struct foo { int x[3]; char b; };

But it is not enough to set the aliasing set to zero, because derived
types would then still end up in different equivalence classes even
though they might be compatible.  Instead those types should be set
to structural equivalency.  We also add checking assertions that
ensure that TYPE_CANONICAL is set correctly for all tagged types.

gcc/c/
* c-decl.cc (finish_struct): Do not set TYPE_CANONICAL for
structure or unions with variable size.
* c-objc-common.cc (c_get_alias_set): Do not set alias set to zero.
* c-typeck.cc (comptypes_verify): New function.
(comptypes,comptypes_same_p,comptypes_check_enum_int): Add assertion.
(comptypes_equiv_p): Add assertion that ensures that compatible
types have the same equivalence class.
(tagged_types_tu_compatible_p): Remove now unneeded special case.

gcc/testsuite/
* gcc.dg/gnu23-tag-alias-8.c: New test.

gcc/c/c-decl.cc
gcc/c/c-objc-common.cc
gcc/c/c-typeck.cc
gcc/testsuite/gcc.dg/gnu23-tag-alias-8.c [new file with mode: 0644]

index 6e6606c9570854f8907162f78f3f071e5836c1e4..9f7d55c0b109d1d9322659b547eed159ab215879 100644 (file)
@@ -9749,7 +9749,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
   C_TYPE_BEING_DEFINED (t) = 0;
 
   /* Set type canonical based on equivalence class.  */
-  if (flag_isoc23)
+  if (flag_isoc23 && !C_TYPE_VARIABLE_SIZE (t))
     {
       if (c_struct_htab == NULL)
        c_struct_htab = hash_table<c_struct_hasher>::create_ggc (61);
index 283f6a8ae2652877b8ec3476e26da6792020c006..738e899a2a93af91c8773aa3f0dc84f7a51f4739 100644 (file)
@@ -420,11 +420,6 @@ c_var_mod_p (tree x, tree fn ATTRIBUTE_UNUSED)
 alias_set_type
 c_get_alias_set (tree t)
 {
-  /* Structs with variable size can alias different incompatible
-     structs.  Let them alias anything.   */
-  if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t))
-    return 0;
-
   return c_common_get_alias_set (t);
 }
 
index 09b2c265a46a912ea6f46b630f2a2bb01da57c95..48934802148f0c54d84c6fa52020cf08672ffd6b 100644 (file)
@@ -1167,6 +1167,28 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+
+
+/* Helper function for comptypes.  For two compatible types, return 1
+   if they pass consistency checks.  In particular we test that
+   TYPE_CANONICAL is set correctly, i.e. the two types can alias.  */
+
+static bool
+comptypes_verify (tree type1, tree type2)
+{
+  if (TYPE_CANONICAL (type1) != TYPE_CANONICAL (type2)
+      && !TYPE_STRUCTURAL_EQUALITY_P (type1)
+      && !TYPE_STRUCTURAL_EQUALITY_P (type2))
+    {
+      /* FIXME: check other types. */
+      if (RECORD_OR_UNION_TYPE_P (type1)
+         || TREE_CODE (type1) == ENUMERAL_TYPE
+         || TREE_CODE (type2) == ENUMERAL_TYPE)
+       return false;
+    }
+  return true;
+}
+
 struct comptypes_data {
   bool enum_and_int_p;
   bool different_types_p;
@@ -1188,6 +1210,8 @@ comptypes (tree type1, tree type2)
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, &data);
 
+  gcc_checking_assert (!ret || comptypes_verify (type1, type2));
+
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1201,6 +1225,8 @@ comptypes_same_p (tree type1, tree type2)
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, &data);
 
+  gcc_checking_assert (!ret || comptypes_verify (type1, type2));
+
   if (data.different_types_p)
     return false;
 
@@ -1218,6 +1244,8 @@ comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
   bool ret = comptypes_internal (type1, type2, &data);
   *enum_and_int_p = data.enum_and_int_p;
 
+  gcc_checking_assert (!ret || comptypes_verify (type1, type2));
+
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1232,6 +1260,8 @@ comptypes_check_different_types (tree type1, tree type2,
   bool ret = comptypes_internal (type1, type2, &data);
   *different_types_p = data.different_types_p;
 
+  gcc_checking_assert (!ret || comptypes_verify (type1, type2));
+
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1274,6 +1304,10 @@ comptypes_equiv_p (tree type1, tree type2)
   data.equiv = true;
   bool ret = comptypes_internal (type1, type2, &data);
 
+  /* check that different equivance classes are assigned only
+     to types that are not compatible.  */
+  gcc_checking_assert (ret || !comptypes (type1, type2));
+
   return ret;
 }
 
@@ -1629,9 +1663,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
        if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
          return false;
 
-       if (data->equiv && (C_TYPE_VARIABLE_SIZE (t1) || C_TYPE_VARIABLE_SIZE (t2)))
-         return false;
-
        for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
             s1 && s2;
             s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-alias-8.c b/gcc/testsuite/gcc.dg/gnu23-tag-alias-8.c
new file mode 100644 (file)
index 0000000..11f2787
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu23 -O2" } */
+
+typedef struct E { int a[2]; int b; } *A;
+
+void* foo(void* a, void *b, void *c, void *d)
+{
+       *(A**)a = c;
+
+       int N = 2;
+       typedef struct E { int a[N]; int b; } *B;
+       *(B**)b = d;
+
+       return *(A**)a;
+}
+
+int main()
+{
+       A *a, b, c;
+       if (&c != (A*)foo(&a, &a, &b, &c))
+               __builtin_abort();
+}
+
+