Skip to content

Commit de92b54

Browse files
authored
Merge pull request #1578 from RobertLeahy/just
Allow just to Throw on Connect
2 parents 3a155e1 + daf9a01 commit de92b54

3 files changed

Lines changed: 57 additions & 2 deletions

File tree

include/stdexec/__detail/__basic_sender.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ namespace stdexec {
228228

229229
__op_base(_Sexpr&& __sndr, _Receiver&& __rcvr) noexcept(
230230
__nothrow_decay_copyable<_Receiver>
231-
&& __noexcept_of<__sexpr_impl<__tag_t>::get_state, _Sexpr, _Receiver&>)
231+
&& noexcept(__state_t(__sexpr_impl<__tag_t>::get_state(static_cast<_Sexpr&&>(__sndr), __rcvr_))))
232232
: __rcvr_(static_cast<_Receiver&&>(__rcvr))
233233
, __state_(__sexpr_impl<__tag_t>::get_state(static_cast<_Sexpr&&>(__sndr), __rcvr_)) {
234234
}

test/stdexec/algos/factories/test_just.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include <test_common/receivers.hpp>
2020
#include <test_common/type_helpers.hpp>
2121

22+
#include <cstddef>
23+
#include <stdexcept>
24+
#include <utility>
25+
2226
namespace ex = stdexec;
2327

2428
namespace {
@@ -124,4 +128,55 @@ namespace {
124128
CHECK(res == original);
125129
CHECK(cat == typecat::rvalref);
126130
}
131+
132+
TEST_CASE("just works with types with throwing move", "[factories][just]") {
133+
struct throwing_move {
134+
explicit throwing_move(std::size_t& throws_after) noexcept : throws_after_(throws_after) {}
135+
throwing_move(throwing_move&& other)
136+
: throws_after_(other.throws_after_)
137+
{
138+
if (throws_after_) {
139+
--throws_after_;
140+
} else {
141+
throw std::runtime_error("Throwing as requested");
142+
}
143+
}
144+
private:
145+
std::size_t& throws_after_;
146+
};
147+
std::size_t throws_after = 0;
148+
const auto repeat_until_succeeds = [&](auto f) noexcept -> decltype(auto) {
149+
struct guard {
150+
~guard() noexcept {
151+
CHECK(threw);
152+
}
153+
bool threw{false};
154+
};
155+
guard g;
156+
for (;;) {
157+
auto orig = throws_after;
158+
try {
159+
return f();
160+
} catch (...) {
161+
g.threw = true;
162+
++orig;
163+
throws_after = orig;
164+
}
165+
}
166+
};
167+
auto sender = repeat_until_succeeds([&]() {
168+
return ::stdexec::just(throwing_move(throws_after));
169+
});
170+
CHECK(throws_after == 0);
171+
std::size_t invoked = 0;
172+
auto op = repeat_until_succeeds([&]() {
173+
return ::stdexec::connect(
174+
std::move(sender),
175+
make_fun_receiver([&](throwing_move&&) noexcept { ++invoked; }));
176+
});
177+
CHECK(throws_after == 0);
178+
CHECK(invoked == 0);
179+
::stdexec::start(op);
180+
CHECK(invoked == 1);
181+
}
127182
} // namespace

test/test_common/receivers.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ namespace {
487487
F f_;
488488

489489
template <class... Ts>
490-
void set_value(Ts... vals) noexcept {
490+
void set_value(Ts&&... vals) noexcept {
491491
STDEXEC_TRY {
492492
std::move(f_)(static_cast<Ts&&>(vals)...);
493493
}

0 commit comments

Comments
 (0)