Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
tighten up specification of connect-awaitable, change the prototype t…
…o match
  • Loading branch information
ericniebler committed Aug 25, 2021
commit 744ee27791369909741ba4eaa683875a57b03f5b
9 changes: 8 additions & 1 deletion include/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ namespace std::execution {
using __nothrow_ = bool_constant<nothrow_receiver_of<R, Args...>>;

template <class A, class R>
static __impl::__op<__id_t<remove_cvref_t<R>>> __impl(A&& a, R&& r) noexcept {
static __impl::__op<__id_t<remove_cvref_t<R>>> __impl(A&& a, R&& r) {
exception_ptr ex;
try {
// This is a bit mind bending control-flow wise.
Expand Down Expand Up @@ -334,6 +334,13 @@ namespace std::execution {
}
public:
template <__awaitable A, receiver R>
requires receiver_of<R, __await_result_t<A>>
__impl::__op<__id_t<remove_cvref_t<R>>> operator()(A&& a, R&& r) const {
return __impl((A&&) a, (R&&) r);
}
template <__awaitable A, receiver R>
requires same_as<void, __await_result_t<A>> &&
receiver_of<R, __await_result_t<A>>
__impl::__op<__id_t<remove_cvref_t<R>>> operator()(A&& a, R&& r) const {
return __impl((A&&) a, (R&&) r);
}
Expand Down
12 changes: 8 additions & 4 deletions std_execution.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2148,10 +2148,10 @@ enum class forward_progress_guarantee {
1. `tag_invoke(execution::connect, s, r)`, if that expression is valid and its type satisfies `execution::operation_state`. If the function selected by `tag_invoke` does not return an operation state for which `execution::start` starts work described by `s`, the program
is ill-formed with no diagnostic required.

2. Otherwise, <code><i>connect-awaitable</i>(s, r)</code> if <code><i>is-awaitable</i>&lt;S></code> is `true`, where <code><i>connect-awaitable</i></code> is a coroutine equivalent to the following:
2. Otherwise, <code><i>connect-awaitable</i>(s, r)</code> if <code><i>is-awaitable</i>&lt;S></code> is `true` and that expression is valid, where <code><i>connect-awaitable</i></code> is a coroutine equivalent to the following:

<pre highlight="c++">
<i>operation-state-task</i> <i>connect-awaitable</i>(S&& s, R&& r) noexcept {
<i>operation-state-task</i> <i>connect-awaitable</i>(S&& s, R&& r) requires <i>see-below</i> {
exception_ptr e;
try {
<i>set-value-expr</i>
Expand All @@ -2162,10 +2162,12 @@ enum class forward_progress_guarantee {
}
</pre>

where <code><i>connect-awaitable</i></code> starts suspended and:
where <code><i>connect-awaitable</i></code> starts suspended, and:

- <i>set-value-expr</i> first evaluates `co_await (S&&) s`, then suspends the coroutine and evaluates `execution::set_value((R&&) r)` if <code><i>await-result-type</i>&lt;S></code> is <code><i>cv</i> void</code>; otherwise, it evaluates `auto&& res = co_await (S&&) s`, then suspends the coroutine and evaluates `execution::set_value((R&&) r, (decltype(res)) res)`.

If the call to `execution::set_value` exits with an exception, the coroutine is resumed and the exception is immediately propagated in the context of the coroutine.

[<i>Note</i>: If the call to `execution::set_value` exits normally, then the <code><i>connect-awaitable</i></code> coroutine is never resumed. --<i>end note</i>]

- <i>set-error-expr</i> first suspends the coroutine and then executes `execution::set_error((R&&) r, std::move(e))`.
Expand All @@ -2174,7 +2176,9 @@ enum class forward_progress_guarantee {

- <code><i>operation-state-task</i></code> is a type that models `operation_state`. Its `execution::start` resumes the <code><i>connect-awaitable</i></code> coroutine, advancing it past the initial suspend point.

- Let `p` be an lvalue reference to the promise of the <code><i>connect-awaitable</i></code> coroutine and let `c` be any `tag_invoke`-based customization point object. Then `c(p, as...)` is expression-equivalent to `c(r, as...)` for any set of arguments `as...`.
- Let `p` be an lvalue reference to the promise of the <code><i>connect-awaitable</i></code> coroutine and let `c` be any customization point object. Then `std::tag_invoke(c, p, as...)` is expression-equivalent to `std::tag_invoke(c, r, as...)` for any set of arguments `as...`.

The operand of the <i>requires-clause</i> of <code><i>connect-awaitable</i></code> is equivalent to `receiver_of<R>` if <code><i>await-result-type</i>&lt;S></code> is <code><i>cv</i> void</code>; otherwise, it is <code>receiver_of&lt;R, <i>await-result-type</i>&lt;S>></code>.

3. Otherwise, `execution::connect(s, r)` is ill-formed.

Expand Down