diff --git a/include/exec/materialize.hpp b/include/exec/materialize.hpp index 6d9dc215b..6ff354c36 100644 --- a/include/exec/materialize.hpp +++ b/include/exec/materialize.hpp @@ -43,7 +43,7 @@ namespace experimental::execution } template - constexpr void set_error(_Error __err) noexcept + constexpr void set_error(_Error&& __err) noexcept { STDEXEC::set_value(static_cast<_Receiver&&>(__upstream_), set_error_t(), diff --git a/test/exec/test_materialize.cpp b/test/exec/test_materialize.cpp index f076b70e4..97a30510a 100644 --- a/test/exec/test_materialize.cpp +++ b/test/exec/test_materialize.cpp @@ -11,6 +11,57 @@ using namespace exec; namespace { + struct noncopyable_error + { + noncopyable_error() = default; + noncopyable_error(noncopyable_error const &) = delete; + noncopyable_error& operator=(noncopyable_error const &) = delete; + }; + + struct error_sender + { + using sender_concept = ex::sender_tag; + using completion_signatures = ex::completion_signatures; + + template + struct operation + { + noncopyable_error* error_; + Receiver receiver_; + + void start() & noexcept + { + ex::set_error(static_cast(receiver_), *error_); + } + }; + + template + auto connect(Receiver receiver) const noexcept -> operation + { + return {error_, static_cast(receiver)}; + } + + noncopyable_error* error_; + }; + + struct error_receiver + { + using receiver_concept = ex::receiver_tag; + + void set_value(ex::set_error_t, noncopyable_error& error) && noexcept + { + *called_ = &error == expected_; + } + + void set_stopped() && noexcept + { + *called_ = false; + } + + noncopyable_error* expected_; + bool* called_; + }; + template requires __completion_tag> using __dematerialize_value = completion_signatures(_Args...)>; @@ -62,6 +113,21 @@ namespace static_assert(std::same_as); } + TEST_CASE("materialize preserves error references", "[adaptors][materialize]") + { + noncopyable_error error; + bool called = false; + auto sndr = materialize(error_sender{&error}); + + static_assert(set_equivalent, + completion_signatures>); + + auto op = connect(std::move(sndr), error_receiver{&error, &called}); + start(op); + CHECK(called); + } + TEST_CASE("dematerialize value", "[adaptors][materialize]") { auto just_42 = dematerialize(materialize(just(42)));