https://gcc.gnu.org/g:065bbf5c5f8ce438f4cab94eec695e01e089c443

commit r16-7871-g065bbf5c5f8ce438f4cab94eec695e01e089c443
Author: Martin Uecker <[email protected]>
Date:   Tue Jan 6 19:26:42 2026 +0100

    c: Fix wrong code related to TBAA for components of structure types 1/2 
[PR122572]
    
    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.

Diff:
---
 gcc/c/c-typeck.cc                 |  2 +-
 gcc/testsuite/gcc.dg/pr122572.c   | 46 +++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr123356-1.c | 58 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index dc803dc6388a..5b6b2b1d6e08 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -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
index 000000000000..822042c3a8b7
--- /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-1.c 
b/gcc/testsuite/gcc.dg/pr123356-1.c
new file mode 100644
index 000000000000..dab0c606320c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr123356-1.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;
+}
+

Reply via email to