https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365
--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- The reason why that would work in this case is that we have info = {}; as the first stmt that mentions it, but doesn't take address of info. Then there is if (something) fortify_panic (); The condition isn't possibly indirect stmt, fortify_panic is (it is a call), but none of the info vars are addressable at that point. Then there is: i2c_new_device(&info); which first takes info's address and is also (afterwards) a possibly indirect call (so, we first need to walk explicit references and then handle the possibly indirect, not the other way around). But, in this spot only one of the info vars is live/addressable, not all of them (on fortify_panic () all 4 info vars are live, but none is addressable). info ={v} {CLOBBER}; Finally, the var is no longer live nor addressable. Now, if you change the code so that i2c_new_device(&info); comes first and then f(a); this would no longer be optimized, because in the common fortify_panic call all 4 info vars would be addressable (even escaped to another function). That said, if it is the same type of variable and it can't be shared, I wonder why the kernel just doesn't use the same variable. Like: switch (model) { struct i2c_board_info info; case 1: info = (struct i2c_board_info) {}; f(a); i2c_new_device(&info); break; case 2: info = (struct i2c_board_info) {}; f(b); i2c_new_device(&info); break; ... } (or memset or whatever).