This fixes an issue related to TBAA.  I will send another
patch for the middle-end, which should solve the issue independently
from this patch and also cover the same issue for types with tag
(which should be much rarer though), but this patch should go in
any case.


Bootstrapped and regression tested on x64_86 and aarch64.


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 could suspect that this just pessimizes
aliasing decisions, but due to how the middle-end handles TBAA for
components of aggregrates, 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.c: New test.
---
 gcc/c/c-typeck.cc               |  2 +-
 gcc/testsuite/gcc.dg/pr122572.c | 46 ++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr123356.c | 58 +++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr122572.c
 create mode 100644 gcc/testsuite/gcc.dg/pr123356.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 26805e5cfd6..7bf78529eae 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1887,7 +1887,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
index 00000000000..822042c3a8b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr122572.c
@@ -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.c b/gcc/testsuite/gcc.dg/pr123356.c
new file mode 100644
index 00000000000..dab0c606320
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr123356.c
@@ -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;
+}
+
-- 
2.43.7

Reply via email to