https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120400
Bug ID: 120400 Summary: C++ FE optimisations reorder && operands. Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: iains at gcc dot gnu.org CC: jason at gcc dot gnu.org Target Milestone: --- In the coroutines code we need to guard some accesses to frame data - since that might become invalidated by completion of a coroutine body. So we have code-gen like this: tree fr_cleanup_if = begin_if_stmt (); tree cond = build1_loc (loc, TRUTH_NOT_EXPR, boolean_type_node, iarc_x); cond = build2_loc (loc, TRUTH_ANDIF_EXPR, boolean_type_node, coro_before_return, cond); finish_if_stmt_cond (cond, fr_cleanup_if); finish_expr_stmt (delete_frame_call); finish_then_clause (fr_cleanup_if); finish_if_stmt (fr_cleanup_if); The intention is that "coro_before_return" guards the (potentially) unsafe access of iarc_x. When we build this with O0 then: 0) coroutine codegen: s if (E |EC|test::_Coro_before_return && !test::_Coro_initial_await_resume_called) CxE operator delete (E (void*)E cvt[coro::promise_type*,VD test::_Coro_frameptr], E 40);<<s-cleanup point>> 1) tree-original: if (_Coro_before_returnD.9342 && !_Coro_initial_await_resume_calledD.9343) { 2) gimple: if (_Coro_before_returnD.9342 != 0) goto <D.9486>; else goto <D.9487>; <D.9486>: _3 = _Coro_frameptrD.9340->_Coro_initial_await_resume_calledD.9326; _4 = ~_3; if (_4 != 0) goto <D.9488>; else goto <D.9489>; <D.9488>: === All OK and doing what's expected. When we build at O1+: 0) coroutine codegen s if (E |EC|test::_Coro_before_return && !test::_Coro_initial_await_resume_called) (same) 1) tree-original: if (!_Coro_initial_await_resume_calledD.9346 && _Coro_before_returnD.9345) ouch! .. the operands are reversed - UB can happen 2) tree-gimple: _3 = _Coro_frameptrD.9343->_Coro_initial_await_resume_calledD.9329; _4 = ~_3; _5 = _Coro_before_returnD.9345 & _4; if (_5 != 0) goto <D.9490>; else goto <D.9491>; and this is even worse, it's all unconditional. ======== I guess this is happening in folding or genericization. Perhaps the argument is that "it's OK to reorder" because if any of the operations would be UB then we can do what we like... however, that does rather make defensive programming hard. I'd categorise it as wrong-code .. but perhaps I'm missing something.