Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#pragma once

#include <hpx/assert.hpp>
#include <hpx/execution/algorithms/detail/inject_scheduler.hpp>
#include <hpx/execution/algorithms/detail/partial_algorithm.hpp>
#include <hpx/execution/algorithms/detail/single_result.hpp>
Expand Down Expand Up @@ -218,11 +219,10 @@ namespace hpx::execution::experimental {
};

// Detects whether a sender's set_value completion scheduler is
// run_loop_scheduler. Used by detail::make_future to reject -- at
// compile time -- the 1-argument form make_future(sender) when the
// sender's completion path runs on a run_loop scheduler. That call
// would silently hang at runtime because the 1-argument overload
// constructs a future_data that never drives loop.run().
// run_loop_scheduler. Used by detail::make_future as a runtime
// guard (see HPX_ASSERT_MSG below). The trait itself is SFINAE-
// friendly so it can be safely instantiated during overload
// resolution.
Comment thread
guptapratykshh marked this conversation as resolved.
template <typename Sender, typename = void>
struct sender_completion_is_run_loop_scheduler : std::false_type
{
Expand All @@ -247,13 +247,25 @@ namespace hpx::execution::experimental {
HPX_CXX_CORE_EXPORT template <typename Sender, typename Allocator>
auto make_future(Sender&& sender, Allocator const& allocator)
{
// The 1-argument make_future(sender) overload constructs a
// future_data that never calls loop.run(), so passing a sender
// whose set_value completion scheduler is a run_loop_scheduler
// produces a future that silently hangs. Reject at compile time
// and direct the user to make_future(sched, sender).
static_assert(!sender_completion_is_run_loop_scheduler<
std::decay_t<Sender>>::value,
// Debug-only runtime guard against the silent-hang case:
// this 1-argument fallback constructs a future_data that
// never drives loop.run(), so a sender whose set_value
// completion scheduler is a run_loop_scheduler produces a
// future that hangs in get(). The public make_future CPO
// routes such senders to the scheduler-form overload via
// tag_override_invoke, so reaching this body with a run-loop
// completion scheduler indicates a direct call to
// detail::make_future rather than the public API. HPX_ASSERT_MSG
// is a no-op in release builds (HPX_DEBUG off), so this only
// catches the misuse in debug; an unconditional throw would
// also alter the release-mode failure shape and is left out
// intentionally -- the assert exists to flag bypassing the
// public CPO during development, not to harden release-mode
// misuse. static_assert is avoided here because tag_priority's
// SFINAE probing during overload resolution may instantiate
// this body before the scheduler-form overload is selected.
HPX_ASSERT_MSG(!sender_completion_is_run_loop_scheduler<
std::decay_t<Sender>>::value,
"make_future(sender) cannot drive the parent run_loop when "
"the sender's completion scheduler is a run_loop_scheduler. "
"Use make_future(loop.get_scheduler(), sender) so the "
Expand Down
Loading