https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112727
--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> --- struct S { bool s[8]; }; void foo (const S *x) { unsigned n = 0; for (unsigned j = 0; j < 8; j++) n |= ((!x->s[j]) ? 1 : 0) << (16 + j); } -O2 -fsanitize=shift-exponent,bounds-strict -Wuninitialized is all that is needed. Seems the SAVE_EXPR <j> used in the .UBSAN_BOUNDS call is evaluated separately both in the __builtin___ubsan_handle_shift_out_of_bounds argument and then later on again, but because the call is conditional and is gimplified first, j is initialized only in case 16 + j > 31 and uninitialized otherwise. Now, if I try: int bar (void); int baz (int x) { return bar () << x; } we properly evaluate SAVE_EXPR <bar ()> first, then conditionally in __builtin___ubsan_handle_shift_out_of_bounds argument and again afterwards. So I guess the bug is that (x->s[j] ? 0 : 1) isn't considered as having side-effects by the shift sanitization. And we then add the bounds-strict sanitization into it which definitely turns it into something with side-effects.