diff --git a/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp b/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp index a63b85b93e2..bac1b5685bb 100644 --- a/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp +++ b/libs/core/execution/include/hpx/execution/algorithms/when_all_vector.hpp @@ -252,31 +252,31 @@ namespace hpx::when_all_vector_detail { } // clang-format off + // TODO: Make this a method friend auto tag_invoke(hpx::execution::experimental::get_env_t, when_all_vector_receiver const& r) #if defined(HPX_HAVE_STDEXEC) -// TODO: This part should be using the newer env/prop utilities based on P3325 -// but doing so results in an invalid memory access in the when_all_vector test. -// It is worth noting that make_env and env behave different in the following -// way: -// make_env(empty_env, with) -> with -// env(empty_env, prop) -> env, prop> -// But it is not clear at the moment why that cause an invalid memory access. noexcept - -> hpx::execution::experimental::make_env_t< + -> hpx::execution::experimental::env< hpx::execution::experimental::env_of_t, - hpx::execution::experimental::with_t< + hpx::execution::experimental::prop< hpx::execution::experimental::get_stop_token_t, hpx::experimental::in_place_stop_token>> { /* The new calling convention is: - * make_env(old_env, with(tag, val))*/ - return hpx::execution::experimental::make_env( - hpx::execution::experimental::get_env( - r.op_state.receiver), - hpx::execution::experimental::with( - hpx::execution::experimental::get_stop_token, - r.op_state.stop_source_.get_token())); + * env(old_env, prop(tag, val))*/ + + // Due to the bug described in the get_env.cpp tests, + // returning an env constructed directly with the + // temporaries returned by the functions causes wrong + // behaviour. + auto e = hpx::execution::experimental::get_env( + r.op_state.receiver); + auto p = hpx::execution::experimental::prop( + hpx::execution::experimental::get_stop_token, + r.op_state.stop_source_.get_token()); + return hpx::execution::experimental::env( + std::move(e), std::move(p)); } #else -> hpx::execution::experimental::make_env_t< diff --git a/libs/core/execution_base/tests/unit/get_env.cpp b/libs/core/execution_base/tests/unit/get_env.cpp index 2e4bb65e1d7..d856c01cc4d 100644 --- a/libs/core/execution_base/tests/unit/get_env.cpp +++ b/libs/core/execution_base/tests/unit/get_env.cpp @@ -31,7 +31,11 @@ namespace mylib { { using is_receiver = void; +#ifdef HPX_HAVE_STDEXEC + decltype(auto) get_env() const noexcept +#else friend some_env tag_invoke(ex::get_env_t, receiver_2 const&) noexcept +#endif { return some_env{}; } @@ -42,11 +46,9 @@ namespace mylib { { // clang-format off template - requires ex::stdexec_non_standard_tag_invoke::tag_invocable< - receiver_env_t, Env> - auto operator()(Env const& e) const + decltype(auto) operator()(Env const& e) const noexcept { - return ex::stdexec_non_standard_tag_invoke::tag_invoke(*this, e); + return e.query(*this); } // clang-format on } receiver_env{}; @@ -68,15 +70,19 @@ namespace mylib { { using is_receiver = void; +#if defined(HPX_HAVE_STDEXEC) + decltype(auto) get_env() const noexcept + { + auto f = ex::prop(receiver_env, 42); + return f; + } +#else friend constexpr auto tag_invoke( ex::get_env_t, receiver_3 const&) noexcept { -#if defined(HPX_HAVE_STDEXEC) - return ex::prop(receiver_env, 42); -#else return ex::make_env(42); -#endif } +#endif }; #if defined(HPX_HAVE_STDEXEC) @@ -93,32 +99,44 @@ namespace mylib { { using is_receiver = void; - friend auto tag_invoke(ex::get_env_t, receiver_4 const&) noexcept +#if defined(HPX_HAVE_STDEXEC) + decltype(auto) get_env() const noexcept { receiver_3 rcv; -#if defined(HPX_HAVE_STDEXEC) - return ex::env( - ex::get_env(rcv), ex::prop(receiver_env, std::string("42"))); + /* Due to https://github.com/llvm/llvm-project/issues/88077 + * The following line never compiles, and if it does, it misbehaves. + * return ex::env( + * ex::prop(receiver_env, std::string("42")), + * ex::get_env(rcv) + * ); + * + * The following is a workaround */ + + auto e = ex::get_env(rcv); + auto p = ex::prop(receiver_env, std::string("42")); + + return ex::env(std::move(e), std::move(p)); + } #else + friend auto tag_invoke(ex::get_env_t, receiver_4 const&) noexcept + { + receiver_3 rcv; + return ex::make_env( std::string("42"), ex::get_env(std::move(rcv))); -#endif } +#endif }; #if defined(HPX_HAVE_STDEXEC) inline constexpr struct receiver_env1_t final : ex::forwarding_query_t { - // clang-format off template - requires ex::stdexec_non_standard_tag_invoke::tag_invocable< - receiver_env1_t, Env> - auto operator()(Env const& e) const + decltype(auto) operator()(Env const& e) const noexcept { - return ex::stdexec_non_standard_tag_invoke::tag_invoke(*this, e); + return e.query(*this); } - // clang-format on } receiver_env1{}; #else inline constexpr struct receiver_env1_t final @@ -141,17 +159,27 @@ namespace mylib { { using is_receiver = void; - friend auto tag_invoke(ex::get_env_t, receiver_5 const&) noexcept +#if defined(HPX_HAVE_STDEXEC) + decltype(auto) get_env() const noexcept { receiver_3 rcv; -#if defined(HPX_HAVE_STDEXEC) - return ex::env( - ex::get_env(rcv), ex::prop(receiver_env1, std::string("42"))); + /* Same as receiver_4 + * This would cause the compiler to crash: + * return ex::env( + * ex::get_env(rcv), ex::prop(receiver_env1, std::string("42"))); + * */ + auto e = ex::get_env(rcv); + auto p = ex::prop(receiver_env1, std::string("42")); + return ex::env(std::move(e), std::move(p)); + } #else + friend auto tag_invoke(ex::get_env_t, receiver_5 const&) noexcept + { + receiver_3 rcv; return ex::make_env( std::string("42"), ex::get_env(std::move(rcv))); -#endif } +#endif }; } // namespace mylib