]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c: Fix wrong code related to TBAA for components of structure types 1/2 [PR122572]
authorMartin Uecker <uecker@tugraz.at>
Tue, 6 Jan 2026 18:26:42 +0000 (19:26 +0100)
committerMartin Uecker <uecker@gcc.gnu.org>
Tue, 3 Mar 2026 15:14:53 +0000 (16:14 +0100)
When computing TYPE_CANONICAL we form equivalence classes of types
ignoring some aspects.  In particular, we treat two structure / union
types as equivalent if a member is a pointer to another tagged type
which has the same tag, even if this pointed-to type is otherwise not
compatible.  The fundamental reason why we do this is that even in a
single TU the equivalence class needs to be consistent with compatibility
of incomplete types across TUs.  (LTO globs such pointers to void*).

The bug is that the test incorrectly treated also two pointed-to types
without tag as equivalent.  One would expect that this just pessimizes
aliasing decisions, but due to how the middle-end handles TBAA for
components of structures, this leads to wrong code.

PR c/122572

gcc/c/ChangeLog:
* c-typeck.cc (tagged_types_tu_compatible_p): Fix check.

gcc/testsuite/ChangeLog:
* gcc.dg/pr122572.c: New test.
* gcc.dg/pr123356-1.c: New test.

gcc/c/c-typeck.cc
gcc/testsuite/gcc.dg/pr122572.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr123356-1.c [new file with mode: 0644]

index dc803dc6388a013a324ac9572d10206ca5a1ae14..5b6b2b1d6e088ef3cf521bd02eee62a7b02b9ced 100644 (file)
@@ -1857,7 +1857,7 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
   /* When forming equivalence classes for TYPE_CANONICAL in C23, we treat
      structs with the same tag as equivalent, but only when they are targets
      of pointers inside other structs.  */
-  if (data->equiv && data->pointedto)
+  if (data->equiv && data->pointedto && NULL_TREE != c_type_tag (t1))
     return true;
 
   /* Different types without tag are incompatible except as an anonymous
diff --git a/gcc/testsuite/gcc.dg/pr122572.c b/gcc/testsuite/gcc.dg/pr122572.c
new file mode 100644 (file)
index 0000000..822042c
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-options "-std=c23 -O2" } */
+
+typedef struct {
+       int *arg;
+       int flags;
+} optStruct;
+
+typedef struct {
+       int *specified;
+       int flags;
+} optEntry;
+
+typedef struct {
+       int short_allowed;
+       optStruct *opt_table;
+} optStruct2;
+
+typedef struct {
+       int short_allowed;
+       optEntry *opt_table;
+} optStruct3;
+
+[[gnu::noipa]]
+void f(int, int, optStruct3 a)
+{
+        a.opt_table[0].flags = 1;
+}
+
+[[gnu::noipa]]
+int alias_bug (void)
+{
+       static optEntry option_def[50];
+       static optStruct3 opt;
+       option_def[0].flags = 0;
+       opt.opt_table = option_def;
+       f (0, 0, opt);
+       return opt.opt_table[0].flags;
+}
+
+int main()
+{
+       if (1 != alias_bug())
+               __builtin_abort();
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr123356-1.c b/gcc/testsuite/gcc.dg/pr123356-1.c
new file mode 100644 (file)
index 0000000..dab0c60
--- /dev/null
@@ -0,0 +1,58 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+typedef struct
+{
+    long  coeffs;
+}
+fmpz_poly_struct;
+typedef struct
+{
+} n_poly_struct;
+typedef struct
+{
+    n_poly_struct * coeffs;
+    long alloc;
+    long length;
+} n_bpoly_struct;
+typedef struct
+{
+    fmpz_poly_struct * coeffs;
+    long alloc;
+    long length;
+} fmpz_bpoly_struct;
+typedef fmpz_bpoly_struct fmpz_bpoly_t[];
+
+__attribute__((noinline))
+fmpz_poly_struct * fmpz_bpoly_swap_(fmpz_bpoly_t B, fmpz_bpoly_t Q)
+{
+    fmpz_bpoly_struct t = *B;
+    *B = *Q;
+    *Q = t;
+    return B->coeffs;
+}
+
+__attribute__((noinline,optimize("no-strict-aliasing")))
+fmpz_poly_struct * fmpz_bpoly_swap_2(fmpz_bpoly_t B, fmpz_bpoly_t Q)
+{
+    fmpz_bpoly_struct t = *B;
+    *B = *Q;
+    *Q = t;
+    return B->coeffs;
+}
+
+int main(){
+    fmpz_poly_struct B_coeffs = {0}, Q_coeffs = {0};
+    fmpz_bpoly_t B = {0};
+    fmpz_bpoly_t Q = {0};
+    B->coeffs = &B_coeffs;
+    Q->coeffs = &Q_coeffs;
+    if (fmpz_bpoly_swap_(B, Q) != &Q_coeffs)
+           __builtin_abort();
+    B->coeffs = &B_coeffs;
+    Q->coeffs = &Q_coeffs;
+    if (fmpz_bpoly_swap_2(B, Q) != &Q_coeffs)
+           __builtin_abort();
+    return 0;
+}
+