Skip to content

Commit

Permalink
env compiler bug workaroud
Browse files Browse the repository at this point in the history
  • Loading branch information
isidorostsa committed Aug 19, 2024
1 parent 13e83ce commit ea9cda8
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<tag, val>) -> with<tag, val>
// env(empty_env, prop<tag, val>) -> env<env<>, prop<tag, val>>
// 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<receiver_type>,
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<
Expand Down
76 changes: 52 additions & 24 deletions libs/core/execution_base/tests/unit/get_env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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{};
}
Expand All @@ -42,11 +46,9 @@ namespace mylib {
{
// clang-format off
template <typename Env>
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{};
Expand All @@ -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<receiver_env_t>(42);
#endif
}
#endif
};

#if defined(HPX_HAVE_STDEXEC)
Expand All @@ -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<receiver_env_t>(
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 <typename Env>
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
Expand All @@ -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<receiver_env1_t>(
std::string("42"), ex::get_env(std::move(rcv)));
#endif
}
#endif
};
} // namespace mylib

Expand Down

0 comments on commit ea9cda8

Please sign in to comment.