https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118874
--- Comment #14 from Jakub Jelinek <jakub at gcc dot gnu.org> --- So, I've tried --- gcc/coroutines.cc.jj 2025-02-04 09:16:42.820267205 +0100 +++ gcc/coroutines.cc 2025-03-04 11:42:28.004682770 +0100 @@ -5183,6 +5183,15 @@ cp_coroutine_transform::build_ramp_funct of the relevant function. Here we carry out the first part of finish_return_expr(). */ input_location = fn_start; + if (!aggregate_value_p (gro_type, orig_fn_decl)) + { + /* If get_ro doesn't need to be returned in memory, force it into + a TARGET_EXPR and try to return TARGET_EXPR_SLOT of it. See + PR118874. */ + get_ro = force_target_expr (gro_type, get_ro, tf_warning_or_error); + finish_expr_stmt (get_ro); + get_ro = TARGET_EXPR_SLOT (get_ro); + } r = check_return_expr (get_ro, &no_warning, &dangling); input_location = UNKNOWN_LOCATION; gcc_checking_assert (!dangling); but that actually makes things even worse, not better. Before that change gimple dump was _3 = &_Coro_frameptr->_Coro_promise; <retval> = C::promise_type::get_return_object (_3); bar (_Coro_frameptr); return <retval>; (which is undesirable, we IMO really want for the !aggregate_value_p initialize a temporary VAR_DECL with what get_return_object returns, then call bar (_Coro_frameptr); and then return that_temporary; But with the above patch it emits try { _3 = &_Coro_frameptr->_Coro_promise; D.8886 = C::promise_type::get_return_object (_3); } finally { D.8886 = {CLOBBER(eos)}; } <retval> = D.8886; bar (_Coro_frameptr); return <retval>; which still ICEs the same way but also clobbers the temporary before it is copied.