From 86f58570dade43c30e3c5ac4c64d073328d222e2 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Sat, 8 Aug 2026 17:30:40 +0200 Subject: [PATCH 1/2] Preserve error references in materialize --- include/exec/materialize.hpp | 2 +- test/exec/test_materialize.cpp | 66 ++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) 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))); From dfe4351496ead75d00758104678d8c33693df98d Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Sun, 9 Aug 2026 20:16:41 -0700 Subject: [PATCH 2/2] clang-format --- test/exec/test_materialize.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/exec/test_materialize.cpp b/test/exec/test_materialize.cpp index 97a30510a..c0b1f0712 100644 --- a/test/exec/test_materialize.cpp +++ b/test/exec/test_materialize.cpp @@ -13,15 +13,15 @@ namespace struct noncopyable_error { - noncopyable_error() = default; - noncopyable_error(noncopyable_error const &) = delete; + 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; + using sender_concept = ex::sender_tag; + using completion_signatures = ex::completion_signatures; template struct operation @@ -59,7 +59,7 @@ namespace } noncopyable_error* expected_; - bool* called_; + bool* called_; }; template @@ -119,9 +119,9 @@ namespace bool called = false; auto sndr = materialize(error_sender{&error}); - static_assert(set_equivalent, - completion_signatures>); + static_assert( + set_equivalent, + completion_signatures>); auto op = connect(std::move(sndr), error_receiver{&error, &called}); start(op);