diff --git a/include/beman/execution/detail/just.hpp b/include/beman/execution/detail/just.hpp index e670ff5e..3a734e5a 100644 --- a/include/beman/execution/detail/just.hpp +++ b/include/beman/execution/detail/just.hpp @@ -51,7 +51,8 @@ struct just_t { template requires ::beman::execution::detail::just_size && (::beman::execution::detail::movable_value && ...) - auto operator()(T&&... arg) const { + auto operator()(T&&... arg) const + noexcept((::std::is_nothrow_constructible_v<::std::remove_cvref_t, T> && ...)) { return ::beman::execution::detail::make_sender( *this, ::beman::execution::detail::product_type{::std::forward(arg)...}); } diff --git a/include/beman/execution/detail/let.hpp b/include/beman/execution/detail/let.hpp index e90ce816..2f3f85e2 100644 --- a/include/beman/execution/detail/let.hpp +++ b/include/beman/execution/detail/let.hpp @@ -297,8 +297,9 @@ struct let_t { try { let_bind(state, receiver, ::std::forward(args)...); } catch (...) { - if constexpr (not noexcept(let_bind(state, receiver, ::std::forward(args)...))) + if constexpr (not noexcept(let_bind(state, receiver, ::std::forward(args)...))) { ::beman::execution::set_error(::std::move(receiver), ::std::current_exception()); + } } } else { Tag()(::std::move(receiver), ::std::forward(args)...); diff --git a/include/beman/execution/detail/product_type.hpp b/include/beman/execution/detail/product_type.hpp index db14937a..83dd0592 100644 --- a/include/beman/execution/detail/product_type.hpp +++ b/include/beman/execution/detail/product_type.hpp @@ -47,15 +47,15 @@ struct product_type_base<::std::index_sequence, T...> } template <::std::size_t J> - auto get() & -> decltype(auto) { + auto get() & noexcept -> decltype(auto) { return this->element_get(*this); } template <::std::size_t J> - auto get() && -> decltype(auto) { + auto get() && noexcept -> decltype(auto) { return this->element_get(::std::move(*this)); } template <::std::size_t J> - auto get() const& -> decltype(auto) { + auto get() const& noexcept -> decltype(auto) { return this->element_get(*this); } diff --git a/include/beman/execution/detail/run_loop.hpp b/include/beman/execution/detail/run_loop.hpp index 2e71b38f..b05369f4 100644 --- a/include/beman/execution/detail/run_loop.hpp +++ b/include/beman/execution/detail/run_loop.hpp @@ -161,7 +161,7 @@ class run_loop { auto operator=(const run_loop&) -> run_loop& = delete; auto operator=(run_loop&&) -> run_loop& = delete; - auto get_scheduler() -> scheduler { return {this}; } + auto get_scheduler() noexcept -> scheduler { return {this}; } auto run() -> void { if (::std::lock_guard guard(this->mutex); diff --git a/include/beman/execution/detail/starts_on.hpp b/include/beman/execution/detail/starts_on.hpp index bc0bc56a..c7d7c9fc 100644 --- a/include/beman/execution/detail/starts_on.hpp +++ b/include/beman/execution/detail/starts_on.hpp @@ -59,7 +59,9 @@ struct starts_on_t { return ::beman::execution::let_value( ::beman::execution::schedule(scheduler), [new_sender = ::beman::execution::detail::forward_like(new_sender)]() mutable noexcept( - ::std::is_nothrow_constructible_v<::std::decay_t>) { return ::std::move(new_sender); }); + ::std::is_nothrow_move_constructible_v<::std::remove_cvref_t>) { + return ::std::move(new_sender); + }); } template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender> diff --git a/include/beman/execution/detail/then.hpp b/include/beman/execution/detail/then.hpp index 2f4b239d..e6fd17b4 100644 --- a/include/beman/execution/detail/then.hpp +++ b/include/beman/execution/detail/then.hpp @@ -112,11 +112,13 @@ struct then_exception struct then_t : ::beman::execution::sender_adaptor_closure> { template <::beman::execution::detail::movable_value Fun> - auto operator()(Fun&& fun) const { + auto operator()(Fun&& fun) const noexcept(::std::is_nothrow_constructible_v<::std::remove_cvref_t, Fun>) { return ::beman::execution::detail::make_sender_adaptor(*this, std::forward(fun)); } template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun> - auto operator()(Sender&& sender, Fun&& fun) const { + auto operator()(Sender&& sender, Fun&& fun) const + noexcept(::std::is_nothrow_constructible_v<::std::remove_cvref_t, Sender> && + ::std::is_nothrow_constructible_v<::std::remove_cvref_t, Fun>) { auto domain{::beman::execution::detail::get_domain_early(sender)}; return ::beman::execution::transform_sender( domain, diff --git a/tests/beman/execution/exec-let.test.cpp b/tests/beman/execution/exec-let.test.cpp index 21bdd6df..2cd8a8ee 100644 --- a/tests/beman/execution/exec-let.test.cpp +++ b/tests/beman/execution/exec-let.test.cpp @@ -123,6 +123,13 @@ auto test_let_value_env() -> void { ex::then([](auto s) { static_assert(ex::scheduler); })); } +struct all_receiver { + using receiver_concept = test_std::receiver_t; + auto set_value(auto&&...) && noexcept {} + auto set_error(auto&&) && noexcept {} + auto set_stopped() && noexcept {} +}; + auto test_completion_signatures() -> void { test_std::sync_wait( test::completion_test(test_std::just() | test_std::let_value([]() { return test_std::just(); }))); @@ -130,6 +137,22 @@ auto test_completion_signatures() -> void { test::completion_test(test_std::just() | test_std::let_value([]() noexcept { return test_std::just(); }))); test_std::sync_wait(test::completion_test( test_std::just() | test_std::let_value([]() noexcept { return test_std::just_error(std::exception_ptr{}); }))); + + test_std::sync_wait( + test::completion_test(test_std::let_value(test_std::just(), []() noexcept { return test_std::just(); }))); + static_assert(std::is_nothrow_move_constructible_v); + static_assert( + requires { test_std::connect(test_std::just() | test_std::then([]() noexcept {}), all_receiver{}); }); + static_assert(noexcept(all_receiver{})); + static_assert(noexcept(test_std::just())); + static_assert(noexcept(test_std::just().connect(all_receiver{}))); + static_assert(noexcept(test_std::connect(test_std::just(), all_receiver{}))); + static_assert(noexcept(ex::then(test_std::just(), []() noexcept {}))); + static_assert(noexcept(test_std::just() | ex::then([]() noexcept {}))); + static_assert(noexcept((test_std::just() | test_std::then([]() noexcept {})).connect(all_receiver{}))); + static_assert(noexcept(test_std::connect(test_std::just() | test_std::then([]() noexcept {}), all_receiver{}))); + test_std::sync_wait(test::completion_test(test_std::let_value( + test_std::just(), []() noexcept { return test_std::just() | test_std::then([]() noexcept {}); }))); } } // namespace diff --git a/tests/beman/execution/exec-starts-on.test.cpp b/tests/beman/execution/exec-starts-on.test.cpp index f50cb441..4a65d1da 100644 --- a/tests/beman/execution/exec-starts-on.test.cpp +++ b/tests/beman/execution/exec-starts-on.test.cpp @@ -3,6 +3,7 @@ #include #include +#include #ifdef BEMAN_HAS_MODULES import beman.execution; #else @@ -79,6 +80,21 @@ auto test_use(Scheduler&& scheduler, Sender&& sender) -> void { //-dk:TODO test::check_type(test_std::get_completion_signatures(s, test_std::test_std::env<>{})); test_std::sync_wait(std::move(s)); } + +auto test_starts_on_completions() { + test_std::sync_wait(test::completion_test(test_std::starts_on(test_std::inline_scheduler(), test_std::just()))); + test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([]() noexcept {}))); + test_std::sync_wait( + test::completion_test(test_std::let_value(test_std::just(), []() noexcept { return test_std::just(); }))); + test_std::sync_wait(test::completion_test(test_std::let_value( + test_std::just(), []() noexcept { return test_std::just() | test_std::then([]() noexcept {}); }))); + test_std::sync_wait( + test::completion_test(test_std::let_value(test_std::schedule(test_std::inline_scheduler()), []() noexcept { + return test_std::just() | test_std::then([]() noexcept {}); + }))); + test_std::sync_wait(test::completion_test( + test_std::starts_on(test_std::inline_scheduler(), test_std::just() | test_std::then([]() noexcept {})))); +} } // namespace TEST(exec_starts_on) { @@ -94,4 +110,5 @@ TEST(exec_starts_on) { test_constraints(scheduler{}, sender{}); test_use(scheduler{}, sender{}); + test_starts_on_completions(); } diff --git a/tests/beman/execution/exec-then.test.cpp b/tests/beman/execution/exec-then.test.cpp index 0c8900ab..a9cbc749 100644 --- a/tests/beman/execution/exec-then.test.cpp +++ b/tests/beman/execution/exec-then.test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef BEMAN_HAS_MODULES import beman.execution; #else @@ -257,6 +258,12 @@ auto test_then_env() -> void { } } +auto test_then_completions() { + test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([]() {}))); + test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([]() noexcept {}))); + test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([](auto&&...) noexcept {}))); +} + } // namespace TEST(exec_then) { @@ -275,4 +282,5 @@ TEST(exec_then) { test_then_allocator(); test_then_env(); + test_then_completions(); }