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; +} +
