Skip to content
Open
Show file tree
Hide file tree
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
5 changes: 4 additions & 1 deletion include/stdexec/__detail/__connect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#pragma once

#include "__execution_fwd.hpp"
#include "__diagnostics.hpp"

// include these after __execution_fwd.hpp
#include "__completion_signatures_of.hpp"
Expand Down Expand Up @@ -206,7 +207,9 @@ namespace STDEXEC {
class _Receiver,
class _DeclFn = __connect_declfn_t<_Sender, _Receiver>
>
requires __connectable_to<_Sender, _Receiver>
requires assert_with<
__connectable_to<_Sender, _Receiver>,
__connect_error_t<transform_sender_result_t<_Sender, env_of_t<_Receiver>>, _Receiver>>
STDEXEC_ATTRIBUTE(always_inline)
constexpr auto operator()(_Sender&& __sndr, _Receiver&& __rcvr) const
noexcept(__nothrow_callable<_DeclFn>) -> __call_result_t<_DeclFn> {
Expand Down
28 changes: 28 additions & 0 deletions include/stdexec/__detail/__diagnostics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ namespace STDEXEC {
_WITH_ENVIRONMENT_(_Env)...
>;

struct _CONNECT_ERROR_ {};
struct _UNABLE_TO_CONNECT_THE_SENDER_TO_THE_RECEIVER_ { };

template <class _Sender, class _Receiver>
using __connect_error_t = __mexception<
_WHAT_(_CONNECT_ERROR_),
_WHY_(_UNABLE_TO_CONNECT_THE_SENDER_TO_THE_RECEIVER_),
_WITH_PRETTY_SENDER_<_Sender>,
_WITH_RECEIVER_(_Receiver),
_WITH_ENVIRONMENT_(env_of_t<_Receiver>)
>;

#if __cpp_lib_constexpr_exceptions >= 2025'02L // constexpr exception types, https://wg21.link/p3378

using __exception = ::std::exception;
Expand Down Expand Up @@ -258,6 +270,22 @@ namespace STDEXEC {

constexpr bool operator==(const __not_a_scheduler&) const noexcept = default;
};

template<bool _MustBeTrue, class _WithError>
struct __assert_with;

template<class _WithError>
struct __assert_with<false, _WithError> {
static constexpr bool value = __ok<_WithError>;
static_assert(__ok<_WithError>, "concept assertion failed with..");
};
template<class _Elide>
struct __assert_with<true, _Elide> {
static constexpr bool value = true;
};

template<bool _MustBeTrue, class _WithError>
concept assert_with = __assert_with<_MustBeTrue, _WithError>::value;
} // namespace STDEXEC

////////////////////////////////////////////////////////////////////////////////
Expand Down
9 changes: 6 additions & 3 deletions include/stdexec/__detail/__get_completion_signatures.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,11 @@ namespace STDEXEC {
}

template <class _Sender, class _Env>
requires __has_get_completion_signatures<_Sender, _Env>
requires assert_with<
__has_get_completion_signatures<_Sender, _Env>,
__unrecognized_sender_error_t<transform_sender_result_t<_Sender, _Env>, _Env>>
consteval auto get_completion_signatures() {
using __new_sndr_t = transform_sender_result_t<_Sender, _Env>;
static_assert(!__merror<__new_sndr_t>);
return __cmplsigs::__get_completion_signatures_helper<__new_sndr_t, _Env>();
}

Expand All @@ -255,7 +256,9 @@ namespace STDEXEC {
///////////////////////////////////////////////////////////////////////////////////////////////////
// An minimally constrained alias for the result of get_completion_signatures:
template <class _Sender, class... _Env>
requires enable_sender<__decay_t<_Sender>>
requires assert_with<
enable_sender<__decay_t<_Sender>>,
__unrecognized_sender_error_t<__decay_t<_Sender>, _Env...>>
using __completion_signatures_of_t =
decltype(STDEXEC::get_completion_signatures<_Sender, _Env...>());

Expand Down
4 changes: 1 addition & 3 deletions test/stdexec/concepts/test_concepts_sender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ namespace {
ex::set_stopped_t()
>;

auto connect(empty_recv::recv0&&) const -> oper {
auto connect(empty_recv::recv0&&) const -> oper {
return {};
}
};
Expand Down Expand Up @@ -171,11 +171,9 @@ namespace {
"not all combinations of senders & receivers satisfy the sender_to concept",
"[concepts][sender]") {
REQUIRE_FALSE(ex::sender_to<my_sender0, empty_recv::recv_int>);
REQUIRE_FALSE(ex::sender_to<my_sender0, empty_recv::recv0_ec>);
REQUIRE_FALSE(ex::sender_to<my_sender0, empty_recv::recv_int_ec>);
REQUIRE_FALSE(ex::sender_to<my_sender_int, empty_recv::recv0>);
REQUIRE_FALSE(ex::sender_to<my_sender_int, empty_recv::recv0_ec>);
REQUIRE_FALSE(ex::sender_to<my_sender_int, empty_recv::recv_int_ec>);
}

TEST_CASE(
Expand Down