]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c: fix incorrect TBAA for tagged types across translation units [PR117490]
authorMartin Uecker <uecker@tugraz.at>
Fri, 8 Nov 2024 17:46:10 +0000 (18:46 +0100)
committerMartin Uecker <uecker@gcc.gnu.org>
Tue, 19 Nov 2024 18:34:31 +0000 (19:34 +0100)
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/117490

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/guality/zero-length-array.c: Restrict to c17.
* gcc.dg/pr117490.c: New test.

gcc/c/c-typeck.cc
gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c
gcc/testsuite/gcc.dg/guality/zero-length-array.c
gcc/testsuite/gcc.dg/pr117490.c [new file with mode: 0644]

index a701dd090fb84d9a74cbc89deb577144b9fb8b87..61145d7e4f0ffe02759c18598ecd166326d95f37 100644 (file)
@@ -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))
index 1ea3a883d0c107792dd110ca2cd351f62ef72608..b1f4e7c2363dbb57aa5de80c9bb3da7d9a2ea0e6 100644 (file)
@@ -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;
index d3fc4bd57e19cef588ed481683d640d24c64da7a..d35514a069d809316a80565cdb87de870648cdc0 100644 (file)
@@ -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;
 }
 
index 33f34d98ac29d81781760151199a5fff8a2c0057..83d5a76779d963732cee10a2fcd165f57ddd3159 100644 (file)
@@ -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 (file)
index 0000000..80a0cd6
--- /dev/null
@@ -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();
+}
+