Skip to content

Commit afde940

Browse files
authored
Fix noexcept (#267)
* fix a problem with starts_on noexcept specification * more missing/wrong noexcept specifications * fix some minor issues detected by CI/AI * clang format
1 parent b881bca commit afde940

9 files changed

Lines changed: 63 additions & 9 deletions

File tree

include/beman/execution/detail/just.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ struct just_t {
5151
template <typename... T>
5252
requires ::beman::execution::detail::just_size<Completion, T...> &&
5353
(::beman::execution::detail::movable_value<T> && ...)
54-
auto operator()(T&&... arg) const {
54+
auto operator()(T&&... arg) const
55+
noexcept((::std::is_nothrow_constructible_v<::std::remove_cvref_t<T>, T> && ...)) {
5556
return ::beman::execution::detail::make_sender(
5657
*this, ::beman::execution::detail::product_type{::std::forward<T>(arg)...});
5758
}

include/beman/execution/detail/let.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,9 @@ struct let_t {
297297
try {
298298
let_bind(state, receiver, ::std::forward<Args>(args)...);
299299
} catch (...) {
300-
if constexpr (not noexcept(let_bind(state, receiver, ::std::forward<Args>(args)...)))
300+
if constexpr (not noexcept(let_bind(state, receiver, ::std::forward<Args>(args)...))) {
301301
::beman::execution::set_error(::std::move(receiver), ::std::current_exception());
302+
}
302303
}
303304
} else {
304305
Tag()(::std::move(receiver), ::std::forward<Args>(args)...);

include/beman/execution/detail/product_type.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ struct product_type_base<::std::index_sequence<I...>, T...>
4747
}
4848

4949
template <::std::size_t J>
50-
auto get() & -> decltype(auto) {
50+
auto get() & noexcept -> decltype(auto) {
5151
return this->element_get<J>(*this);
5252
}
5353
template <::std::size_t J>
54-
auto get() && -> decltype(auto) {
54+
auto get() && noexcept -> decltype(auto) {
5555
return this->element_get<J>(::std::move(*this));
5656
}
5757
template <::std::size_t J>
58-
auto get() const& -> decltype(auto) {
58+
auto get() const& noexcept -> decltype(auto) {
5959
return this->element_get<J>(*this);
6060
}
6161

include/beman/execution/detail/run_loop.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ class run_loop {
161161
auto operator=(const run_loop&) -> run_loop& = delete;
162162
auto operator=(run_loop&&) -> run_loop& = delete;
163163

164-
auto get_scheduler() -> scheduler { return {this}; }
164+
auto get_scheduler() noexcept -> scheduler { return {this}; }
165165

166166
auto run() -> void {
167167
if (::std::lock_guard guard(this->mutex);

include/beman/execution/detail/starts_on.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ struct starts_on_t {
5959
return ::beman::execution::let_value(
6060
::beman::execution::schedule(scheduler),
6161
[new_sender = ::beman::execution::detail::forward_like<Sender>(new_sender)]() mutable noexcept(
62-
::std::is_nothrow_constructible_v<::std::decay_t<Sender>>) { return ::std::move(new_sender); });
62+
::std::is_nothrow_move_constructible_v<::std::remove_cvref_t<Sender>>) {
63+
return ::std::move(new_sender);
64+
});
6365
}
6466

6567
template <::beman::execution::scheduler Scheduler, ::beman::execution::sender Sender>

include/beman/execution/detail/then.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,13 @@ struct then_exception<Comp, Fun, ::beman::execution::completion_signatures<Compl
112112
template <typename Completion>
113113
struct then_t : ::beman::execution::sender_adaptor_closure<then_t<Completion>> {
114114
template <::beman::execution::detail::movable_value Fun>
115-
auto operator()(Fun&& fun) const {
115+
auto operator()(Fun&& fun) const noexcept(::std::is_nothrow_constructible_v<::std::remove_cvref_t<Fun>, Fun>) {
116116
return ::beman::execution::detail::make_sender_adaptor(*this, std::forward<decltype(fun)>(fun));
117117
}
118118
template <::beman::execution::sender Sender, ::beman::execution::detail::movable_value Fun>
119-
auto operator()(Sender&& sender, Fun&& fun) const {
119+
auto operator()(Sender&& sender, Fun&& fun) const
120+
noexcept(::std::is_nothrow_constructible_v<::std::remove_cvref_t<Sender>, Sender> &&
121+
::std::is_nothrow_constructible_v<::std::remove_cvref_t<Fun>, Fun>) {
120122
auto domain{::beman::execution::detail::get_domain_early(sender)};
121123
return ::beman::execution::transform_sender(
122124
domain,

tests/beman/execution/exec-let.test.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,36 @@ auto test_let_value_env() -> void {
123123
ex::then([](auto s) { static_assert(ex::scheduler<decltype(s)>); }));
124124
}
125125

126+
struct all_receiver {
127+
using receiver_concept = test_std::receiver_t;
128+
auto set_value(auto&&...) && noexcept {}
129+
auto set_error(auto&&) && noexcept {}
130+
auto set_stopped() && noexcept {}
131+
};
132+
126133
auto test_completion_signatures() -> void {
127134
test_std::sync_wait(
128135
test::completion_test(test_std::just() | test_std::let_value([]() { return test_std::just(); })));
129136
test_std::sync_wait(
130137
test::completion_test(test_std::just() | test_std::let_value([]() noexcept { return test_std::just(); })));
131138
test_std::sync_wait(test::completion_test(
132139
test_std::just() | test_std::let_value([]() noexcept { return test_std::just_error(std::exception_ptr{}); })));
140+
141+
test_std::sync_wait(
142+
test::completion_test(test_std::let_value(test_std::just(), []() noexcept { return test_std::just(); })));
143+
static_assert(std::is_nothrow_move_constructible_v<decltype(test_std::just() | test_std::then([]() noexcept {}))>);
144+
static_assert(
145+
requires { test_std::connect(test_std::just() | test_std::then([]() noexcept {}), all_receiver{}); });
146+
static_assert(noexcept(all_receiver{}));
147+
static_assert(noexcept(test_std::just()));
148+
static_assert(noexcept(test_std::just().connect(all_receiver{})));
149+
static_assert(noexcept(test_std::connect(test_std::just(), all_receiver{})));
150+
static_assert(noexcept(ex::then(test_std::just(), []() noexcept {})));
151+
static_assert(noexcept(test_std::just() | ex::then([]() noexcept {})));
152+
static_assert(noexcept((test_std::just() | test_std::then([]() noexcept {})).connect(all_receiver{})));
153+
static_assert(noexcept(test_std::connect(test_std::just() | test_std::then([]() noexcept {}), all_receiver{})));
154+
test_std::sync_wait(test::completion_test(test_std::let_value(
155+
test_std::just(), []() noexcept { return test_std::just() | test_std::then([]() noexcept {}); })));
133156
}
134157
} // namespace
135158

tests/beman/execution/exec-starts-on.test.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <concepts>
55
#include <test/execution.hpp>
6+
#include <test/completion_test.hpp>
67
#ifdef BEMAN_HAS_MODULES
78
import beman.execution;
89
#else
@@ -79,6 +80,21 @@ auto test_use(Scheduler&& scheduler, Sender&& sender) -> void {
7980
//-dk:TODO test::check_type<void>(test_std::get_completion_signatures(s, test_std::test_std::env<>{}));
8081
test_std::sync_wait(std::move(s));
8182
}
83+
84+
auto test_starts_on_completions() {
85+
test_std::sync_wait(test::completion_test(test_std::starts_on(test_std::inline_scheduler(), test_std::just())));
86+
test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([]() noexcept {})));
87+
test_std::sync_wait(
88+
test::completion_test(test_std::let_value(test_std::just(), []() noexcept { return test_std::just(); })));
89+
test_std::sync_wait(test::completion_test(test_std::let_value(
90+
test_std::just(), []() noexcept { return test_std::just() | test_std::then([]() noexcept {}); })));
91+
test_std::sync_wait(
92+
test::completion_test(test_std::let_value(test_std::schedule(test_std::inline_scheduler()), []() noexcept {
93+
return test_std::just() | test_std::then([]() noexcept {});
94+
})));
95+
test_std::sync_wait(test::completion_test(
96+
test_std::starts_on(test_std::inline_scheduler(), test_std::just() | test_std::then([]() noexcept {}))));
97+
}
8298
} // namespace
8399

84100
TEST(exec_starts_on) {
@@ -94,4 +110,5 @@ TEST(exec_starts_on) {
94110
test_constraints<true>(scheduler{}, sender{});
95111

96112
test_use(scheduler{}, sender{});
113+
test_starts_on_completions();
97114
}

tests/beman/execution/exec-then.test.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <tuple>
88
#include <utility>
99
#include <test/execution.hpp>
10+
#include <test/completion_test.hpp>
1011
#ifdef BEMAN_HAS_MODULES
1112
import beman.execution;
1213
#else
@@ -257,6 +258,12 @@ auto test_then_env() -> void {
257258
}
258259
}
259260

261+
auto test_then_completions() {
262+
test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([]() {})));
263+
test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([]() noexcept {})));
264+
test_std::sync_wait(test::completion_test(test_std::just() | test_std::then([](auto&&...) noexcept {})));
265+
}
266+
260267
} // namespace
261268

262269
TEST(exec_then) {
@@ -275,4 +282,5 @@ TEST(exec_then) {
275282
test_then_allocator();
276283

277284
test_then_env();
285+
test_then_completions();
278286
}

0 commit comments

Comments
 (0)