On Mon, 25 May 2026, Martin Uecker wrote:
>
>
> Any comments about this?
>
> The fix would need to be backported to 15 and 16.
>
> Martin
>
> Am Montag, dem 11.05.2026 um 18:20 +0200 schrieb Martin Uecker:
> > So, annoyingly, I got this wrong.
> >
> > Bootstrapped and regression tested on x86_64.
> >
> > Best,
> > Martin
> >
> >
> > c23: fix TBAA error for function returning structure [PR125252]
> >
> > To fix PR122572 we globbed pointers to structure or union types nested
> > within other structure or union types to a void pointer when computing
> > the TYPE_CANONICAL. But when doing this for function return types this
> > then leads to wrong aliasing decisions, because for some reason function
> > derivation behaves differently than pointer and array derivation.
> > Instead
> > of globbing to void, replace the nested structure or union type with an
> > incomplete type instead.
> >
> > PR c/124252
> >
> > gcc/c/ChangeLog:
> >
> > * c-typeck.cc (ptr_to_tagged_member): Return type of member.
> > (c_type_canonical): Use incomplete type.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * gcc.dg/pr125252.c
> >
> > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> > index 6195d179543..3ffeed73d8c 100644
> > --- a/gcc/c/c-typeck.cc
> > +++ b/gcc/c/c-typeck.cc
> > @@ -579,8 +579,9 @@ c_reconstruct_complex_type (tree type, tree bottom)
> >
> > /* Helper function for c_canonical_type. Check whether FIELD
> > contains a pointer to a structure or union with tag,
> > - possibly nested in other type derivations. */
> > -static bool
> > + possibly nested in other type derivations, and return the
> > + type of this nested structure or union. */
> > +static tree
> > ptr_to_tagged_member (tree field)
> > {
> > gcc_assert (FIELD_DECL == TREE_CODE (field));
> > @@ -598,17 +599,17 @@ ptr_to_tagged_member (tree field)
> > if (ptr_seen
> > && RECORD_OR_UNION_TYPE_P (type)
> > && NULL_TREE != c_type_tag (type))
> > - return true;
> > + return type;
> >
> > - return false;
> > + return NULL_TREE;
> > }
> >
> > /* For a record or union type, make necessary adaptations so that the
> > type can be used as TYPE_CANONICAL.
> >
> > If the TYPE contains a pointer (possibly nested in other type
> > - derivations) to a structure or union as a member, create a copy
> > - and change such pointers to void pointers. Otherwise, the middle-end
> > + derivations) to a structure or union as a member, create a copy and
> > + change the nested type to an incomplete type. Otherwise, the middle-end
> > gets confused when recording component aliases in the case where we
> > have formed equivalency classes that include types for which these
> > member pointers end up pointing to other structure or unions types
> > @@ -635,9 +636,15 @@ c_type_canonical (tree type)
> > for (tree x = TYPE_FIELDS (type); x; x = DECL_CHAIN (x))
> > {
> > tree f = copy_node (x);
> > - if (ptr_to_tagged_member (x))
> > - TREE_TYPE (f) = c_reconstruct_complex_type (TREE_TYPE (x),
> > - ptr_type_node);
> > + if (tree m = ptr_to_tagged_member (x))
I'm not sure how this constrains 'm', so does
> > + {
> > + tree new_node = make_node (TREE_CODE (m));
this possibly lose some important bits of 'm' that you do not set below?
Other than that it looks consistent on what you do (and you understand
it better than me). I usually do not want to get into approving
C language frontend changes though ...
Richard.
> > + TYPE_NAME (new_node) = TYPE_NAME (m);
> > + SET_TYPE_STRUCTURAL_EQUALITY (new_node);
> > + new_node = qualify_type (new_node, m);
> > + TREE_TYPE (f) = c_reconstruct_complex_type (TREE_TYPE (x),
> > + new_node);
> > + }
> > *fields = f;
> > fields = &DECL_CHAIN (f);
> > }
> > diff --git a/gcc/testsuite/gcc.dg/pr125252.c
> > b/gcc/testsuite/gcc.dg/pr125252.c
> > new file mode 100644
> > index 00000000000..4e27fa15978
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/pr125252.c
> > @@ -0,0 +1,36 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-std=gnu23 -O2" } */
> > +
> > +
> > +int k;
> > +struct S {};
> > +
> > +#define T struct S
> > +
> > +T *get_sender () {
> > + k = 1;
> > + return (void *)0;
> > +}
> > +
> > +T *get_cc () { }
> > +
> > +void test () {
> > + struct {
> > + T *(*get_header) (void);
> > + } reply_to_map[] = {
> > + { get_sender },
> > + { get_cc },
> > + };
> > +
> > + for (int i = 0; i < 2; i++) {
> > + asm ("" ::"r"(reply_to_map[i].get_header ()));
> > + }
> > +}
> > +
> > +int main() {
> > + test ();
> > +
> > + if (k != 1)
> > + __builtin_abort();
> > +}
> > +
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)