Quote from C99 standard:
6.5.2.3
5 One special guarantee is made in order to simplify the use of unions: if a union contains several structures th
The most important point is that your change (moving the union up) is not changing the definition of the function foo at all. It is still a function that receives unrelated pointers. In your example the passed pointers are related while elsewhere this might be different. The goal of compiler is to serve the most general case. The body of the function is different after the change and it is not clear why.
The question that you are asking is about how careful optimization is implemented in your particular compiler for certain command line keys. It has nothing to do with the memory layout. In a correct compiler the result should be the same. Compiler should handle the case when 2 different pointers in fact point to the same place in memory.