1919#include " ../stdexec/__detail/__variant.hpp"
2020#include " ../stdexec/execution.hpp"
2121
22+ #include < type_traits>
23+
2224STDEXEC_PRAGMA_PUSH ()
2325STDEXEC_PRAGMA_IGNORE_GNU(" -Wmissing-braces" )
2426
@@ -54,18 +56,11 @@ namespace experimental::execution
5456 STDEXEC_ATTRIBUTE (host, device)
5557 constexpr void _start_next () noexcept
5658 {
57- STDEXEC_TRY
58- {
59- (*_start_next_)(this );
60- }
61- STDEXEC_CATCH_ALL
62- {
63- STDEXEC::set_error (static_cast <Rcvr&&>(_rcvr), std::current_exception ());
64- }
59+ (*_start_next_)(this );
6560 }
6661
6762 Rcvr _rcvr;
68- void (*_start_next_)(_opstate_base*) = nullptr ;
63+ void (*_start_next_)(_opstate_base*) noexcept = nullptr ;
6964 };
7065
7166 template <class Rcvr >
@@ -120,8 +115,11 @@ namespace experimental::execution
120115 {
121116 template <class ... _Ts>
122117 STDEXEC_ATTRIBUTE (host, device, always_inline)
123- constexpr auto
124- operator ()(_Ts&&... __ts) const STDEXEC_AUTO_RETURN (_Tuple{static_cast <_Ts&&>(__ts)...});
118+ constexpr _Tuple
119+ operator ()(_Ts&&... __ts) const noexcept (std::is_nothrow_constructible_v<_Tuple, _Ts...>)
120+ {
121+ return _Tuple{(_Ts&&) __ts...};
122+ }
125123 };
126124
127125 template <class Rcvr , class ... Senders>
@@ -156,6 +154,12 @@ namespace experimental::execution
156154 template <class CvSndrs >
157155 STDEXEC_ATTRIBUTE (host, device)
158156 constexpr explicit _opstate (Rcvr&& rcvr, CvSndrs&& sndrs)
157+ noexcept (::STDEXEC::__nothrow_connectable<
158+ decltype (::STDEXEC::__get<0 >(::STDEXEC::__declval<CvSndrs>())),
159+ _rcvr_t<sizeof...(Senders) == 0>>
160+ && ::STDEXEC::__nothrow_invocable<decltype(::STDEXEC::__apply),
161+ __convert_tuple_fn<_senders_tuple_t>,
162+ CvSndrs>)
159163 : _opstate_base<Rcvr>{static_cast <Rcvr&&>(rcvr)}
160164 , _sndrs{STDEXEC::__apply (__convert_tuple_fn<_senders_tuple_t >{},
161165 static_cast <CvSndrs&&>(sndrs))}
@@ -170,19 +174,39 @@ namespace experimental::execution
170174 }
171175
172176 template <std::size_t Remaining>
173- static constexpr void _start_next (_opstate_base<Rcvr>* _self)
177+ static constexpr void _start_next (_opstate_base<Rcvr>* _self) noexcept
174178 {
175- constexpr auto __nth = sizeof ...(Senders) - Remaining;
176- auto * self = static_cast <_opstate*>(_self);
177- auto & sndr = STDEXEC::__get<__nth + 1 >(self->_sndrs );
178- auto & op = self->_ops .template __emplace_from <__nth + 1 >(STDEXEC::connect,
179- std::move (sndr),
180- _rcvr_t <Remaining == 1 >{self});
181- if constexpr (Remaining > 1 )
179+ constexpr auto __nth = sizeof ...(Senders) - Remaining;
180+ auto * self = static_cast <_opstate*>(_self);
181+ auto & sndr = STDEXEC::__get<__nth + 1 >(self->_sndrs );
182+ constexpr auto nothrow = noexcept (
183+ self->_ops .template __emplace_from <__nth + 1 >(STDEXEC::connect,
184+ std::move (sndr),
185+ _rcvr_t < Remaining == 1 > {self}));
186+ STDEXEC_TRY
187+ {
188+ auto & op = self->_ops .template __emplace_from <__nth + 1 >(STDEXEC::connect,
189+ std::move (sndr),
190+ _rcvr_t < Remaining
191+ == 1 > {self});
192+ if constexpr (Remaining > 1 )
193+ {
194+ self->_start_next_ = &_start_next<Remaining - 1 >;
195+ }
196+ STDEXEC::start (op);
197+ }
198+ STDEXEC_CATCH_ALL
182199 {
183- self->_start_next_ = &_start_next<Remaining - 1 >;
200+ if constexpr (nothrow)
201+ {
202+ STDEXEC_UNREACHABLE ();
203+ }
204+ else
205+ {
206+ STDEXEC::set_error (static_cast <Rcvr&&>(static_cast <_opstate*>(_self)->_rcvr ),
207+ std::current_exception ());
208+ }
184209 }
185- STDEXEC::start (op);
186210 }
187211
188212 STDEXEC_ATTRIBUTE (host, device)
@@ -202,36 +226,48 @@ namespace experimental::execution
202226 // The completions of the sequence sender are the error and stopped completions of all the
203227 // child senders plus the value completions of the last child sender.
204228 template <class ... Env>
205- struct _completions_fn
229+ struct _completions_fn ;
230+
231+ template <class Env >
232+ struct _completions_fn <Env>
206233 {
207- // When folding left, the first sender folded will be the last sender in the list. That is
208- // also when the "state" of the fold is void. For this case we want to include the value
209- // completions; otherwise, we want to exclude them.
210- template <class State , class ... Args>
234+ template <bool First, bool AddExceptionPtr, class Sender >
235+ static constexpr bool _add_exception_ptr =
236+ AddExceptionPtr
237+ || !(First || STDEXEC::__nothrow_connectable<Sender, STDEXEC::__receiver_archetype<Env>>);
238+
239+ // When folding left, the first sender folded will be the last sender in the list.
240+ // For this case we want to include the value completions; otherwise, we want to
241+ // exclude them.
242+ template <bool First, bool AddExceptionPtr, class ... Args>
211243 struct _fold_left ;
212244
213- template <class State , class Head , class ... Tail>
214- struct _fold_left <State , Head, Tail...>
245+ template <bool First, bool AddExceptionPtr , class Head , class ... Tail>
246+ struct _fold_left <First, AddExceptionPtr , Head, Tail...>
215247 {
216248 using __t = STDEXEC::__gather_completion_signatures_t <
217- STDEXEC::__completion_signatures_of_t <Head, Env... >,
249+ STDEXEC::__completion_signatures_of_t <Head, Env>,
218250 STDEXEC::set_value_t ,
219251 STDEXEC::__mconst<STDEXEC::completion_signatures<>>::__f,
220252 STDEXEC::__cmplsigs::__default_completion,
221253 STDEXEC::__mtry_q<STDEXEC::__concat_completion_signatures_t >::__f,
222- STDEXEC::__t <_fold_left<State, Tail...>>>;
254+ STDEXEC::__t <
255+ _fold_left<false , _add_exception_ptr<First, AddExceptionPtr, Head>, Tail...>>>;
223256 };
224257
225- template <class Head >
226- struct _fold_left <void , Head>
258+ template <bool First, bool AddExceptionPtr, class Head >
259+ struct _fold_left <First, AddExceptionPtr , Head>
227260 {
228261 using __t = STDEXEC::__mtry_q<STDEXEC::__concat_completion_signatures_t >::__f<
229- STDEXEC::completion_signatures<STDEXEC::set_error_t (std::exception_ptr)>,
230- STDEXEC::__completion_signatures_of_t <Head, Env...>>;
262+ std::conditional_t <
263+ _add_exception_ptr<First, AddExceptionPtr, Head>,
264+ STDEXEC::completion_signatures<STDEXEC::set_error_t (std::exception_ptr)>,
265+ STDEXEC::completion_signatures<>>,
266+ STDEXEC::__completion_signatures_of_t <Head, Env>>;
231267 };
232268
233269 template <class ... Sender>
234- using __f = STDEXEC::__t <_fold_left<void , Sender...>>;
270+ using __f = STDEXEC::__t <_fold_left<true , false , Sender...>>;
235271 };
236272
237273 template <class Sender0 , class ... Senders>
@@ -248,7 +284,11 @@ namespace experimental::execution
248284 STDEXEC_ATTRIBUTE (host, device)
249285 static consteval auto get_completion_signatures ()
250286 {
251- if constexpr (STDEXEC::__decay_copyable<Self>)
287+ if constexpr (sizeof ...(Env) == 0 )
288+ {
289+ return STDEXEC::__dependent_sender<Self>();
290+ }
291+ else if constexpr (STDEXEC::__decay_copyable<Self>)
252292 {
253293 return _completions_t <Self, Env...>{};
254294 }
@@ -263,6 +303,10 @@ namespace experimental::execution
263303 template <STDEXEC::__decay_copyable Self, class Rcvr >
264304 STDEXEC_ATTRIBUTE (host, device)
265305 constexpr STDEXEC_EXPLICIT_THIS_BEGIN (auto connect)(this Self&& self, Rcvr rcvr)
306+ noexcept (std::is_nothrow_constructible_v<
307+ _opstate<Rcvr, STDEXEC::__copy_cvref_t <Self, Sender0>, Senders...>,
308+ Rcvr,
309+ decltype (((Self&&) self)._sndrs)>)
266310 {
267311 return _opstate<Rcvr, STDEXEC::__copy_cvref_t <Self, Sender0>, Senders...>{
268312 static_cast <Rcvr&&>(rcvr),
0 commit comments