On October 29, 2017 2:46:42 AM GMT+01:00, Yubin Ruan <ablacktsh...@gmail.com> wrote: >On 10/27/2017 04:54 PM, Richard Biener wrote: >> On Fri, Oct 27, 2017 at 3:00 PM, Yubin Ruan <ablacktsh...@gmail.com> >wrote: >>> +Cc gcc-list. >>> >>> Does any gcc developer have any comments? >> >> See PR82224. The code is valid. >> >>> On Mon, Sep 25, 2017 at 01:41:55PM -0700, Myriachan wrote: >>>> This question that "supercat" posted on Stack Overflow ran into an >>>> interesting problem: >>>> >>>> >https://stackoverflow.com/questions/46205744/is-this-use-of-unions-strictly-conforming/ >>>> >>>> A copy of the code involved is as follows: >>>> >>>> struct s1 {unsigned short x;}; >>>> struct s2 {unsigned short x;}; >>>> union s1s2 { struct s1 v1; struct s2 v2; }; >>>> >>>> static int read_s1x(struct s1 *p) { return p->x; } >>>> static void write_s2x(struct s2 *p, int v) { p->x=v;} >>>> >>>> int test(union s1s2 *p1, union s1s2 *p2, union s1s2 *p3) >>>> { >>>> if (read_s1x(&p1->v1)) >>>> { >>>> unsigned short temp; >>>> temp = p3->v1.x; >>>> p3->v2.x = temp; >>>> write_s2x(&p2->v2,1234); >>>> temp = p3->v2.x; >>>> p3->v1.x = temp; >>>> } >>>> return read_s1x(&p1->v1); >>>> } >>>> int test2(int x) >>>> { >>>> union s1s2 q[2]; >>>> q->v1.x = 4321; >>>> return test(q,q+x,q+x); >>>> } >>>> #include <stdio.h> >>>> int main(void) >>>> { >>>> printf("%d\n",test2(0)); >>>> } >>>> >>>> >>>> Both GCC and Clang in -fstrict-aliasing mode with optimizations are >acting >>>> as if they ran into undefined behavior, and return 4321 instead of >the >>>> expected 1234. This happens in both C and C++ mode. Intel C++ and >Visual >>>> C++ return the expected 1234. All four compilers hardwire the >result as a >>>> constant parameter to printf rather than call test2 or modify >memory at >>>> runtime. >>>> >>>> From my reading of the C++ Standard, particularly [class.union]/5, >>>> assignment expressions through a union member access changes the >active >>>> member of the union (if the union member has a trivial default >constructor, >>>> which it does here, being C code). Taking the address of p2->v2 >and p1->v1 >>>> ought to be legal because those are the active members of the union >at the >>>> time their pointers are taken. >>>> >>>> Is this a well-defined program, or is there subtle undefined >behavior >>>> happening here? > >Thanks. > >As put in my stackoverflow answer[1], I believe this behavior is >specified in >the GCC-online-doc, in section `-fstrict-alisgin'[2]: > > Pay special attention to code like this: > > union a_union { > int i; > double d; > }; > > int f() { > union a_union t; > t.d = 3.0; > return t.i; > } > >The practice of reading from a different union member than the one most > recently written to (called *type-punning*) is common. Even with > *-fstrict-aliasing*, type-punning is allowed, provided the memory is > accessed through the union type. So, the code above works as expected. > See Structures unions enumerations and bit-fields implementation. > However, this code might not: > > int f() { > union a_union t; > int* ip; > t.d = 3.0; > ip = &t.i; > return *ip; > }
The difference is that in the original example the dynamic type of the memory is changed by a store to the union member via the union type. So this doesn't apply. Richard. > Similarly, access by taking the address, casting the resulting pointer > and dereferencing the result has undefined behavior, even if the cast > uses a union type, e.g.: > > int f() { > double d = 3.0; > return ((union a_union *) &d)->i; > } > > The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os. > >I think the second example above is similar to the OP's question >(although the >C standard might not say so... so from my perspective if the second >example >above is true, the OP's code is invalid. > >Do anyone have any comment? > >Yubin > >[1]: >https://stackoverflow.com/questions/46205744/is-this-use-of-unions-strictly-conforming/46968235?noredirect=1#comment80930683_46968235 >[2]: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html