https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82224
Bug ID: 82224 Summary: Strict-aliasing not noticing valid aliasing of two unions with active members Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: myriachan at gmail dot com Target Milestone: --- Consider the following C/C++ code with -O3 -fstrict-aliasing: 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)); } GCC (and Clang) generate code that outputs 4321 instead of the expected 1234. I don't really understand things in terms of the C standard, but in terms of the C++ standard, it seems as if GCC and Clang are incorrect, and this code is well-defined. (The output is 4321 in both C and C++ mode.) According to [class.union]/5 in the C++17 draft N4659, the assignment expression "p3->v2.x = temp;" changes the active member of the union. It's done through a union member access expression. Thus the pointer &p2->v2 is valid here. Even if I switch this to "p3->v2 = { x };", avoiding the nested case, the problem still happens. Even if I explicitly change the active member of the union with placement new as "new(&p3.v2) s2;", the problem still happens. Is it possible that Clang doesn't see the possibility that p2 and p3 point to the same object? Clang cross-reference: https://bugs.llvm.org/show_bug.cgi?id=34632