Skip to content

Commit fbb47a2

Browse files
authored
Merge pull request #1711 from RobertLeahy/let_value_use_after_move_20251213
let_value, _error, & _stopped: Use After Move On Exception From Connect
2 parents 8e1d10d + 43feda9 commit fbb47a2

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

include/stdexec/__detail/__let.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ namespace stdexec {
111111
return __env::__join(__env_, stdexec::get_env(__rcvr_));
112112
}
113113

114-
_Receiver __rcvr_;
114+
_Receiver& __rcvr_;
115115
const _Env2& __env_;
116116
};
117117
};
@@ -296,7 +296,7 @@ namespace stdexec {
296296

297297
template <class _ResultSender, class _OpState>
298298
auto __get_result_receiver(const _ResultSender&, _OpState& __op_state) -> decltype(auto) {
299-
return __rcvr_t{static_cast<_Receiver&&>(__op_state.__rcvr_), __env2_};
299+
return __rcvr_t{__op_state.__rcvr_, __env2_};
300300
}
301301

302302
STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS

test/stdexec/algos/adaptors/test_let_value.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <exec/env.hpp>
2525

2626
#include <chrono> // IWYU pragma: keep for chrono_literals
27+
#include <exception>
28+
#include <memory>
2729

2830
namespace ex = stdexec;
2931

@@ -347,4 +349,41 @@ namespace {
347349
ex::start(op);
348350
CHECK(completed);
349351
}
352+
353+
struct throws_on_connect {
354+
using sender_concept = ::stdexec::sender_t;
355+
template <typename... Args>
356+
static consteval ::stdexec::completion_signatures<::stdexec::set_value_t()>
357+
get_completion_signatures(const Args&...) noexcept {
358+
return {};
359+
}
360+
template <typename Receiver>
361+
auto connect(Receiver) const
362+
-> ::stdexec::connect_result_t<decltype(::stdexec::just()), Receiver> {
363+
throw std::logic_error("TEST");
364+
}
365+
};
366+
367+
TEST_CASE(
368+
"When connecting the successor throws an exception let_value delivers an error completion "
369+
"signal to a valid receiver",
370+
"[adaptors][let_value]") {
371+
struct receiver {
372+
using receiver_concept = ::stdexec::receiver_t;
373+
std::shared_ptr<int> ptr;
374+
void set_value() noexcept {
375+
FAIL_CHECK("Operation should end in error");
376+
}
377+
void set_error(std::exception_ptr ex) noexcept {
378+
CHECK(ex);
379+
REQUIRE(ptr);
380+
*ptr = 5;
381+
}
382+
};
383+
const auto ptr = std::make_shared<int>(0);
384+
auto sender = ex::let_value(::stdexec::just(), []() noexcept { return throws_on_connect{}; });
385+
auto op = ex::connect(std::move(sender), receiver{ptr});
386+
ex::start(op);
387+
CHECK(*ptr == 5);
388+
}
350389
} // namespace

0 commit comments

Comments
 (0)