https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64601
--- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Marc Glisse from comment #3) > Actually there is no need for inlining. > > struct A { int i; }; > void f(struct A *a){ *&a->i=0; } > void g(struct A *a){ int*p=&a->i;*p=0; } > > The main difference seems to be that the first one gets through fold-const.c > while the second is handled by tree-ssa-forwprop.c. &a->i is merely an address calculation, not an access to type A at a. Thus it's valid to write struct B { int i; int j; }; struct B b; int *p = &((struct A *)&b)->i; *p = 0; and it's only required that the actual access (here a int * dereference) honors TBAA rules. So generally you can't "reconstruct" access paths when forwarding address calculations into dereferences. We've had very elaborate code "guessing" access paths in oder releases which broke down very easily for moderately complex testcases. We still have some of that code in forwprop (I still believe it's not 100% correct...) which handles struct A { int i[4]; }; void g(struct A *a, int j) { int *p = &a->i[j]; *p = 0;} generating MEM[(int *)a_1(D)].i[j_2(D)] = 0; return; but the case comes after forwarding invariant addresses. If we'd swap them (really believing in its correctness) then we also handle your case. But as I said - that "If ... and the value type is the same as that of the pointed-to type of the address" is really bogus - the type of the address doesn't have any meaning in GIMPLE (all pointer type conversions are useless).