https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102268
Bug ID: 102268 Summary: Wrong code with aliasing union pointers Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: davmac at davmac dot org Target Milestone: --- The following code is adapted from an LLVM PR: https://bugs.llvm.org/show_bug.cgi?id=34632 The "test" function is called with all three pointers pointing to the same union object. Note there are only reads from the active union object so this is not a type-punning issue. I've also changed the original test case to show that the issue is present even if changing the active union object requires assignment directly to the corresponding union member, though it's not clear if this should be necessary. Runs ok with GCC 9.4; fails with every version since and on trunk. --- begin --- 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; // Active member is v1, so this is fine: temp = p3->v1.x; struct s2 t2 = { temp }; // now change active member to v2, and write to it: p3->v2 = t2; write_s2x(&p2->v2,1234); temp = p3->v2.x; // now change active member back to v1: struct s1 t1 = { temp }; p3->v1 = t1; } return read_s1x(&p1->v1); } int test2(int x) { union s1s2 q[2]; struct s1 t1 = { 4321 }; q->v1 = t1; // ensure active member is v1 return test(q,q+x,q+x); } int main(void) { if(test2(0) == 4321) __builtin_abort(); } --- end ---