This is similar to the enum issue, where setting the alias set to zero
is insufficient because also derived types need to be able to alias.

After this change, it is also possible to add checking assertions that
verify TYPE_CANONICAL for all tagged types at end of each call to the
comptypes family.  At least for the test suite this then shows no
additional issues for tagged types.   

(We still make incorrect aliasing decisions at least for types derived 
from  functions types (PR114959) but this is an ancient issue.  We
probably should set TYPE_CANONICAL in the FE similar to what is done
for tagged types in C23.)


Bootstrapped and regression tested on x86_64.



    C23: allow aliasing for types derived from structs with variable size
    
    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.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 6e6606c9570..9f7d55c0b10 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -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);
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index 551ec6f4b65..29127d037e1 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -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);
 }
 
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2d092357e0f..c07e2f2b5cf 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -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 ist 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;
@@ -1187,6 +1209,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;
 }
 
@@ -1200,6 +1224,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;
 
@@ -1217,6 +1243,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;
 }
 
@@ -1231,6 +1259,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;
 }
 
@@ -1245,6 +1275,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;
 }
 
@@ -1593,9 +1627,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
index 00000000000..11f2787521e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu23-tag-alias-8.c
@@ -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();
+}
+
+

Reply via email to