Skip to content

Commit fb944c3

Browse files
Make exec::without conditionally noexcept (#2213)
* Fix exec::without reference return noexcept * Apply suggestions from code review Co-authored-by: Eric Niebler <eniebler@boost.org> --------- Co-authored-by: Eric Niebler <eniebler@boost.org>
1 parent c3f9efb commit fb944c3

2 files changed

Lines changed: 108 additions & 9 deletions

File tree

include/exec/env.hpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,19 @@ namespace experimental::execution
6161
struct __without_t
6262
{
6363
template <class _Env, class _Query>
64-
constexpr auto operator()(_Env&& __env, _Query) const noexcept
64+
requires STDEXEC::__queryable_with<_Env, _Query>
65+
constexpr auto operator()(_Env&& __env, _Query) const
66+
noexcept(STDEXEC::__nothrow_constructible_from<__without<_Env, _Query>, _Env>)
67+
-> __without<_Env, _Query>
6568
{
66-
if constexpr (STDEXEC::__queryable_with<_Env, _Query>)
67-
{
68-
return __without<_Env, _Query>{static_cast<_Env&&>(__env)};
69-
}
70-
else
71-
{
72-
return static_cast<_Env&&>(__env);
73-
}
69+
return __without<_Env, _Query>{static_cast<_Env&&>(__env)};
70+
}
71+
72+
template <class _Env, class _Query>
73+
constexpr auto operator()(_Env&& __env, _Query) const
74+
noexcept(STDEXEC::__nothrow_move_constructible<_Env>) -> _Env
75+
{
76+
return static_cast<_Env&&>(__env);
7477
}
7578
};
7679

test/exec/test_env.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include <stdexec/execution.hpp>
1919
#include <test_common/catch2.hpp>
2020

21+
#include <type_traits>
22+
#include <utility>
23+
2124
namespace
2225
{
2326
// Two dummy properties:
@@ -53,4 +56,97 @@ namespace
5356
STATIC_REQUIRE(!std::invocable<Foo, decltype(e4)>);
5457
CHECK(bar(e4) == 43);
5558
}
59+
60+
TEST_CASE("without propagates environment move exceptions", "[env]")
61+
{
62+
struct missing_query : STDEXEC::__query<missing_query>
63+
{
64+
using STDEXEC::__query<missing_query>::operator();
65+
};
66+
67+
struct without_move_error
68+
{};
69+
70+
struct throwing_env
71+
{
72+
explicit throwing_env(bool* throw_on_move) noexcept
73+
: throw_on_move_{throw_on_move}
74+
{}
75+
76+
throwing_env(throwing_env const & other) noexcept
77+
: throw_on_move_{other.throw_on_move_}
78+
{}
79+
80+
throwing_env(throwing_env&& other)
81+
: throw_on_move_{other.throw_on_move_}
82+
{
83+
#if !STDEXEC_NO_STDCPP_EXCEPTIONS()
84+
if (*throw_on_move_)
85+
{
86+
throw without_move_error{};
87+
}
88+
#endif
89+
}
90+
91+
int query(Foo) const noexcept
92+
{
93+
return 42;
94+
}
95+
96+
bool* throw_on_move_;
97+
};
98+
99+
bool throw_on_move = false;
100+
throwing_env missing_env{&throw_on_move};
101+
throwing_env queried_env{&throw_on_move};
102+
103+
STATIC_REQUIRE_FALSE(noexcept(exec::without(std::move(missing_env), missing_query{})));
104+
STATIC_REQUIRE_FALSE(noexcept(exec::without(std::move(queried_env), foo)));
105+
STATIC_REQUIRE(noexcept(exec::without(missing_env, missing_query{})));
106+
STATIC_REQUIRE(noexcept(exec::without(queried_env, foo)));
107+
108+
#if !STDEXEC_NO_STDCPP_EXCEPTIONS()
109+
throw_on_move = true;
110+
CHECK_THROWS_AS(exec::without(std::move(missing_env), missing_query{}), without_move_error);
111+
CHECK_THROWS_AS(exec::without(std::move(queried_env), foo), without_move_error);
112+
#endif
113+
114+
struct throwing_copy_error
115+
{};
116+
117+
struct throwing_copy_env
118+
{
119+
explicit throwing_copy_env(bool* throw_on_copy) noexcept
120+
: throw_on_copy_{throw_on_copy}
121+
{}
122+
123+
throwing_copy_env(throwing_copy_env const & other)
124+
: throw_on_copy_{other.throw_on_copy_}
125+
{
126+
#if !STDEXEC_NO_STDCPP_EXCEPTIONS()
127+
if (*throw_on_copy_)
128+
{
129+
throw throwing_copy_error{};
130+
}
131+
#endif
132+
}
133+
134+
throwing_copy_env(throwing_copy_env&&) noexcept = default;
135+
136+
bool* throw_on_copy_;
137+
};
138+
139+
bool throw_on_copy = false;
140+
throwing_copy_env copy_env{&throw_on_copy};
141+
142+
STATIC_REQUIRE(
143+
std::is_same_v<decltype(exec::without(copy_env, missing_query{})), throwing_copy_env&>);
144+
STATIC_REQUIRE(noexcept(exec::without(copy_env, missing_query{})));
145+
146+
#if !STDEXEC_NO_STDCPP_EXCEPTIONS()
147+
throw_on_copy = true;
148+
auto&& result = exec::without(copy_env, missing_query{});
149+
CHECK(&result == &copy_env);
150+
#endif
151+
}
56152
} // namespace

0 commit comments

Comments
 (0)