Skip to content

Commit f4d9cdf

Browse files
Preserve error references in materialize (NVIDIA#2161)
--------- Co-authored-by: Eric Niebler <eniebler@nvidia.com>
1 parent 91bd6cc commit f4d9cdf

2 files changed

Lines changed: 67 additions & 1 deletion

File tree

include/exec/materialize.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace experimental::execution
4343
}
4444

4545
template <class _Error>
46-
constexpr void set_error(_Error __err) noexcept
46+
constexpr void set_error(_Error&& __err) noexcept
4747
{
4848
STDEXEC::set_value(static_cast<_Receiver&&>(__upstream_),
4949
set_error_t(),

test/exec/test_materialize.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,57 @@ using namespace exec;
1111
namespace
1212
{
1313

14+
struct noncopyable_error
15+
{
16+
noncopyable_error() = default;
17+
noncopyable_error(noncopyable_error const &) = delete;
18+
noncopyable_error& operator=(noncopyable_error const &) = delete;
19+
};
20+
21+
struct error_sender
22+
{
23+
using sender_concept = ex::sender_tag;
24+
using completion_signatures = ex::completion_signatures<ex::set_error_t(noncopyable_error&)>;
25+
26+
template <class Receiver>
27+
struct operation
28+
{
29+
noncopyable_error* error_;
30+
Receiver receiver_;
31+
32+
void start() & noexcept
33+
{
34+
ex::set_error(static_cast<Receiver&&>(receiver_), *error_);
35+
}
36+
};
37+
38+
template <class Receiver>
39+
auto connect(Receiver receiver) const noexcept -> operation<Receiver>
40+
{
41+
return {error_, static_cast<Receiver&&>(receiver)};
42+
}
43+
44+
noncopyable_error* error_;
45+
};
46+
47+
struct error_receiver
48+
{
49+
using receiver_concept = ex::receiver_tag;
50+
51+
void set_value(ex::set_error_t, noncopyable_error& error) && noexcept
52+
{
53+
*called_ = &error == expected_;
54+
}
55+
56+
void set_stopped() && noexcept
57+
{
58+
*called_ = false;
59+
}
60+
61+
noncopyable_error* expected_;
62+
bool* called_;
63+
};
64+
1465
template <class _Tag, class... _Args>
1566
requires __completion_tag<std::decay_t<_Tag>>
1667
using __dematerialize_value = completion_signatures<std::decay_t<_Tag>(_Args...)>;
@@ -62,6 +113,21 @@ namespace
62113
static_assert(std::same_as<decltype(tag), set_stopped_t>);
63114
}
64115

116+
TEST_CASE("materialize preserves error references", "[adaptors][materialize]")
117+
{
118+
noncopyable_error error;
119+
bool called = false;
120+
auto sndr = materialize(error_sender{&error});
121+
122+
static_assert(
123+
set_equivalent<completion_signatures_of_t<decltype(sndr)>,
124+
completion_signatures<set_value_t(set_error_t, noncopyable_error&)>>);
125+
126+
auto op = connect(std::move(sndr), error_receiver{&error, &called});
127+
start(op);
128+
CHECK(called);
129+
}
130+
65131
TEST_CASE("dematerialize value", "[adaptors][materialize]")
66132
{
67133
auto just_42 = dematerialize(materialize(just(42)));

0 commit comments

Comments
 (0)