Here is a patch to fix a TBAA issue for tagged types.  In principle,
this affects earlier language modes too, but I limited the change to
C23 for now because it was always wrong but is less of an issue before
C23. If there is no fallout, I would propose to later fix this also
for earlier version of C, which would mean using all the TYPE_CANONICAL
code even there (I would consider having the same logic for all
languages versions a good idea anyway).

The change it self is simple, we assign TYPE_CANONICAL also for tagless
types based on the same rules we already use in C23 for types with tag.

I had to change two tests I had added specifically to avoid pessimizing
TBAA for such types with the C23 changes, but I am not sure what the
impact on optimization is.  FWIW, Clang implements it correctly.

There is also still an issue related to FAMs, i.e. PR113688, that appears
with checking.  With this change, this issue now also affects tagless types.
I still hope this can be resolved in time for GCC 15.


Bootstrapped and regression tested on x86_64.


    c: fix incorrect TBAA for tagged types across translation units [PR117490]
    
    Two different declarations of tagged types in the same translation unit
    are incompatible in C before C23 and without tag also in C23.  Still,
    two such types can be compatible to the same tagged type in a different
    translation unit, but this means that pointers can alias.
    
    typedef struct { int i; } s1;
    typedef struct { int i; } s2;
    
    int f(s1 *p1, s2 *p2)
    {
      p1->i = 2;
      p2->i = 3; // p2->i can alias p1->i
      return p1->i;
    }
    
    We need to assign the same TYPE_CANONICAL to both types.  This patch fixes
    this for C23 and types without tag by also forming equivalence classes for
    such types based on their structure as already done for types with tag.
    Because this change exposes checking errors related to flexible array
    members (cf. PR113688), one test is restricted to C17 for now.
    
            PR c/PR117490
    
    gcc/c/ChangeLog:
            * c-typeck.cc (tagged_types_tu_compatible): Form equivalence
            classed for tagless types in C23.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/gnu23-tag-alias-4.c: Adapt test.
            * gcc.dg/gnu23-tag-alias-7.c: Adapt test.
            * gcc.dg/quality/zero-length-array.c: Restrict to c17.
            * gcc.dg/pr117490.c: New test.

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 9212a8ebc0a..6cc340dda65 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1812,7 +1812,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
   if (data->equiv && data->pointedto)
     return true;
 
-  if (!data->anon_field && NULL_TREE == TYPE_NAME (t1))
+  /* 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))
     return false;
 
   if (!data->anon_field && TYPE_STUB_DECL (t1) != TYPE_STUB_DECL (t2))
diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c 
b/gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
index 1ea3a883d0c..b1f4e7c2363 100644
--- a/gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
+++ b/gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
@@ -2,12 +2,12 @@
  * { dg-options "-std=gnu23 -O2" }
  */
 
-/* This test checks that an incompatible definition of
+/* This used to check that an incompatible definition of
  * a tagged type without tag can be assumed not to alias.  
- * and that this is exploited during optimization.  */
+ * and that this is exploited during optimization.  
+ * Because PR117490 we now check the opposite. */
 
 
-// not sure this is wise, but this was already like this before
 
 typedef struct { int x; } foo_t;
 
@@ -27,7 +27,7 @@ int main()
 {
        foo_t y;
 
-       if (1 != test_foo(&y, &y))
+       if (2 != test_foo(&y, &y))
                __builtin_abort();
 
        return 0;
diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c 
b/gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c
index d3fc4bd57e1..d35514a069d 100644
--- a/gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c
+++ b/gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c
@@ -83,10 +83,12 @@ int main()
                __builtin_abort();
 
        struct bar4 z4;
-
+#if 0
+       // we used to test this, but this would be incorrect
+       // if there is a declaration in another TU cf. PR117490
        if (1 != test_bar4(&z4, &z4))
                __builtin_abort();
-
+#endif
        return 0;
 }
 
diff --git a/gcc/testsuite/gcc.dg/guality/zero-length-array.c 
b/gcc/testsuite/gcc.dg/guality/zero-length-array.c
index 33f34d98ac2..83d5a76779d 100644
--- a/gcc/testsuite/gcc.dg/guality/zero-length-array.c
+++ b/gcc/testsuite/gcc.dg/guality/zero-length-array.c
@@ -1,6 +1,8 @@
 /* PR debug/86985 */
 /* { dg-do run } */
-/* { dg-options "-g" } */
+/* { dg-options "-std=c17 -g" } */
+
+/* FIXME: Use -std=c17 until PR113688 if fixed.  */
 
 struct {
   int foo;
diff --git a/gcc/testsuite/gcc.dg/pr117490.c b/gcc/testsuite/gcc.dg/pr117490.c
new file mode 100644
index 00000000000..80a0cd6d99d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr117490.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -std=c23" } */
+
+typedef struct {
+  int i1;
+} s1;
+
+typedef struct {
+  int i1;
+} s2_alt;
+
+[[gnu::noinline,gnu::noipa]]
+int f2(s1 *s1p, s2_alt *s2p) {
+  s1p->i1 = 2;
+  s2p->i1 = 3;
+  return s1p->i1 * 3;
+}
+
+int main()
+{
+  s1 a;
+  if (9 != f2(&a, (void*)&a))
+         __builtin_abort();
+}
+

Reply via email to