https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128312

--- Comment #2 from liu zhenyu <lzy20000419 at outlook dot com> ---
gcc/tree-nrv.cc, pass_return_slot::execute (14.2 :362-389) sets [return slot
optimization] on `d = f (t)` when dest_safe_for_nrv_p (14.2 :304-320) holds.
That function only checks whether the call may clobber or use dest through
escaped pointers (call_may_clobber_ref_p, ref_maybe_used_by_stmt_p). It does
not check whether the call can throw internally while dest is live on the EH
edge. With RSO, f's NRV object r is d itself, so the stores made before the
throw are visible in the handler (optimized dump: `d = f (t_7(D)); [return slot
optimization]` then `<L5>: _10 = d.a[0];`). The C++ front end already avoids
this for MODIFY_EXPRs (gimplify.cc 14.2 :6131-6168, use_target only for INIT or
non-addressable targets); the middle-end pass upgrades it without the EH check.

Suggested fix: in dest_safe_for_nrv_p, return false when
stmt_can_throw_internal (cfun, call) and dest is not an SSA name. A more
precise fix would check whether dest is live in the landing pad. I tested the
conservative version on 14.2 (fix-14.2.patch): the testcase passes at
-O1/-O2/-O3/-Os.

The same thing happens in C with setjmp/longjmp at -Os (lj1.c), but that case
is less clear-cut, so I'm only mentioning it here.

Reply via email to