https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118874
--- Comment #11 from Jakub Jelinek <jakub at gcc dot gnu.org> --- In the #include <coroutine> struct B { bool await_ready () const noexcept; void await_suspend (std::coroutine_handle<> h) const noexcept; void await_resume () const noexcept; }; struct C { struct promise_type { const char *value; std::suspend_never initial_suspend (); std::suspend_always final_suspend () noexcept; void return_value (const char *v); void unhandled_exception (); C get_return_object () { return C{this}; } }; promise_type *p; explicit C (promise_type *p) : p(p) {} const char *get (); }; C bar (bool x) { if (x) co_await B{}; co_return "foobar"; } testcase (-O2 -m64 -mptr64 -fcoroutines -std=c++23) I see can_do_nrvo_p return twice false when functype is RECORD_TYPE C, once in get_return_object and once in bar function; the reason it returns false is that retval is not a VAR_DECL, but TARGET_EXPR in both cases. The coroutines.cc code refers to DECL_RESULT unconditionally then. I think the problematic INIT_EXPR is created by #5 0x0000000002090641 in build2 (code=INIT_EXPR, tt=<record_type 0x7fffe9a610a8 C>, arg0=<result_decl 0x7fffe9a60500>, arg1=<target_expr 0x7fffe9a7b038>) at ../../gcc/tree.cc:5199 #6 0x0000000000df98f8 in build2_loc (loc=84139394, code=INIT_EXPR, type=<record_type 0x7fffe9a610a8 C>, arg0=<result_decl 0x7fffe9a60500>, arg1=<target_expr 0x7fffe9a7b038>) at ../../gcc/tree.h:4825 #7 0x000000000120f81e in cp_build_init_expr (loc=84139394, target=<result_decl 0x7fffe9a60500>, init=<target_expr 0x7fffe9a7b038>) at ../../gcc/cp/typeck2.cc:2820 #8 0x0000000000d8a860 in cp_build_init_expr (t=<result_decl 0x7fffe9a60500>, i=<target_expr 0x7fffe9a7b038>) at ../../gcc/cp/cp-tree.h:8600 #9 0x00000000012027cb in check_return_expr (retval=<target_expr 0x7fffe9a7b038>, no_warning=0x7fffffffd14f, dangling=0x7fffffffd14e) at ../../gcc/cp/typeck.cc:11513 #10 0x0000000000e23d13 in cp_coroutine_transform::build_ramp_function (this=0x3c0bb60) at ../../gcc/cp/coroutines.cc:5186 Obviously, for the aggregate_value_p (TREE_TYPE (TREE_TYPE (current_function_decl)), current_function_decl) case what the code does is what we want. But I guess as these 2 PRs show, for !aggregate_value_p we want to just initialize a temporary VAR_DECL and then have GIMPLE_RETURN which returns that VAR_DECL.