https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84085
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |FIXED --- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> --- This was indeed fixed in GCC 8. Note that the fundamental issue is that *(&s1->a1[0][0] + n) performs an access via 'int *' while s1->a1[N-1][N-1] performs an access via struct S1 *. This allows the test1 case to disambiguate the load via s1 against that via s2 by using type-based aliasing. This is not possible for test2 or test3. We now optimize this solely by the fact that *((&s2->a2[0][0] + n)) = *(&s1->a1[0][0] + n); stores the same value it later loads into *((&s2->a2[0][0] + n)). If you change this by doing say *((&s2->a2[0][0] + n)) = *(&s1->a1[0][0] + n) + 1; it will no longer be optimized. This may be too conservative reading of the C standard by GCC but we also have to adhere other languages and tricks done by programmers like viewing a data array via different multidimensional array shapes by means of casting. So, this particular case is fixed in GCC 8.