From 487e6dabd8c30545e494be07cae6f2ab891b64e7 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Tue, 11 Aug 2026 01:51:16 +0200 Subject: [PATCH 1/3] Fix nvexec upon_stopped completions --- include/nvexec/stream/upon_stopped.cuh | 19 +++++---- test/nvexec/upon_stopped.cpp | 53 ++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/include/nvexec/stream/upon_stopped.cuh b/include/nvexec/stream/upon_stopped.cuh index cb7668c59..d4bc55478 100644 --- a/include/nvexec/stream/upon_stopped.cuh +++ b/include/nvexec/stream/upon_stopped.cuh @@ -106,7 +106,7 @@ namespace nv::execution::_strm status == cudaSuccess) { opstate_.defer_temp_storage_destruction(d_result); - opstate_.propagate_completion_signal(STDEXEC::set_value, *d_result); + opstate_.propagate_completion_signal(STDEXEC::set_value, std::move(*d_result)); } else { @@ -131,19 +131,24 @@ namespace nv::execution::_strm struct upon_stopped_sender : stream_sender_base { using sender_concept = STDEXEC::sender_tag; - using _set_error_t = completion_signatures; template using receiver_t = _upon_stopped::receiver; + template + using __error_completions_t = + __minvoke_q<__concat_completion_signatures_t, + __with_error_invoke_t<__mbind_front_q<__callable_error_t, upon_stopped_t>, + set_stopped_t, + Fun, + __copy_cvref_t, + Env...>, + completion_signatures>; + template using completion_signatures = __transform_completion_signatures_t< __completion_signatures_of_t<__copy_cvref_t, Env...>, - __with_error_invoke_t<__mbind_front_q<__callable_error_t, upon_stopped_t>, - set_stopped_t, - Fun, - __copy_cvref_t, - Env...>, + __error_completions_t, __cmplsigs::__default_set_value, __cmplsigs::__default_set_error, __set_value_from_t>; diff --git a/test/nvexec/upon_stopped.cpp b/test/nvexec/upon_stopped.cpp index 09fca2890..dad905ba9 100644 --- a/test/nvexec/upon_stopped.cpp +++ b/test/nvexec/upon_stopped.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include "common.cuh" #include "nvexec/stream_context.cuh" @@ -10,6 +12,45 @@ using nvexec::is_on_gpu; namespace { + struct move_only_result + { + STDEXEC_ATTRIBUTE(host, device) + explicit move_only_result(int value) noexcept + : value_(value) + {} + + STDEXEC_ATTRIBUTE(host, device) + move_only_result(move_only_result&& other) noexcept + : value_(other.value_) + { + other.value_ = 0; + } + + move_only_result(move_only_result const &) = delete; + + STDEXEC_ATTRIBUTE(host, device) + ~move_only_result() = default; + + STDEXEC_ATTRIBUTE(host, device) + auto value() const noexcept -> int + { + return value_; + } + + private: + int value_; + }; + + TEST_CASE("nvexec upon_stopped advertises CUDA launch errors", + "[cuda][stream][adaptors][upon_stopped]") + { + auto fun = []() noexcept {}; + using sender_t = nvexec::_strm::upon_stopped_sender, + decltype(fun)>; + sender_t snd{a_sender_of{}, std::move(fun)}; + + check_err_types>(snd); + } TEST_CASE("nvexec upon_stopped returns a sender", "[cuda][stream][adaptors][upon_stopped]") { @@ -41,4 +82,16 @@ namespace REQUIRE(flags_storage.all_set_once()); } + + TEST_CASE("nvexec upon_stopped moves its result", "[cuda][stream][adaptors][upon_stopped]") + { + nvexec::stream_context stream_ctx{}; + + auto snd = ex::just_stopped() | ex::continues_on(stream_ctx.get_scheduler()) + | ex::upon_stopped([] { return move_only_result{42}; }); + + auto [result] = STDEXEC::sync_wait(std::move(snd)).value(); + + REQUIRE(result.value() == 42); + } } // namespace From 7bf023a929d32abc185c0428526e6c8c86708b6f Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Thu, 13 Aug 2026 09:59:21 -0700 Subject: [PATCH 2/3] clang-format --- test/nvexec/upon_stopped.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nvexec/upon_stopped.cpp b/test/nvexec/upon_stopped.cpp index dad905ba9..1b7438f8b 100644 --- a/test/nvexec/upon_stopped.cpp +++ b/test/nvexec/upon_stopped.cpp @@ -45,8 +45,8 @@ namespace "[cuda][stream][adaptors][upon_stopped]") { auto fun = []() noexcept {}; - using sender_t = nvexec::_strm::upon_stopped_sender, - decltype(fun)>; + using sender_t = + nvexec::_strm::upon_stopped_sender, decltype(fun)>; sender_t snd{a_sender_of{}, std::move(fun)}; check_err_types>(snd); From a8ba8f9027a77248f1e19809e7055e80de7743dc Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Fri, 14 Aug 2026 16:35:39 +0000 Subject: [PATCH 3/3] working around nvhpc ICE and warnings --- examples/nvexec/maxwell/common.cuh | 5 +++ examples/nvexec/maxwell/stdpar.cuh | 5 +++ include/exec/static_thread_pool.hpp | 5 +++ include/nvexec/stream/common.cuh | 7 ++++ include/nvexec/stream/upon_stopped.cuh | 55 ++++++++++++-------------- 5 files changed, 48 insertions(+), 29 deletions(-) diff --git a/examples/nvexec/maxwell/common.cuh b/examples/nvexec/maxwell/common.cuh index 67efa4b5b..07b77c026 100644 --- a/examples/nvexec/maxwell/common.cuh +++ b/examples/nvexec/maxwell/common.cuh @@ -39,6 +39,9 @@ # include "nvexec/detail/throw_on_cuda_error.cuh" #endif +STDEXEC_PRAGMA_PUSH() +STDEXEC_PRAGMA_IGNORE_EDG(is_constant_evaluated_in_nonconstexpr_context) + struct deleter_t { bool on_gpu{}; @@ -538,3 +541,5 @@ auto value(std::map const ¶ms, } return default_value; } + +STDEXEC_PRAGMA_POP() diff --git a/examples/nvexec/maxwell/stdpar.cuh b/examples/nvexec/maxwell/stdpar.cuh index 6ccbc6b3b..fe096e3bd 100644 --- a/examples/nvexec/maxwell/stdpar.cuh +++ b/examples/nvexec/maxwell/stdpar.cuh @@ -31,6 +31,9 @@ # include +STDEXEC_PRAGMA_PUSH() +STDEXEC_PRAGMA_IGNORE_EDG(is_constant_evaluated_in_nonconstexpr_context) + template auto is_gpu_policy([[maybe_unused]] Policy&& policy) -> bool { @@ -81,4 +84,6 @@ void run_stdpar(float dt, }); } +STDEXEC_PRAGMA_POP() + #endif // !STDEXEC_NO_STDCPP_PARALLEL_ALGORITHMS() diff --git a/include/exec/static_thread_pool.hpp b/include/exec/static_thread_pool.hpp index f9d2e027d..91959e612 100644 --- a/include/exec/static_thread_pool.hpp +++ b/include/exec/static_thread_pool.hpp @@ -62,6 +62,9 @@ import stdexec; #include "sequence/iterate.hpp" #include "sequence_senders.hpp" +STDEXEC_PRAGMA_PUSH() +STDEXEC_PRAGMA_IGNORE_EDG(is_constant_evaluated_in_nonconstexpr_context) + namespace experimental::execution { struct bwos_params @@ -1843,3 +1846,5 @@ namespace experimental::execution STDEXEC_MODULE_EXPORT namespace exec = experimental::execution; + +STDEXEC_PRAGMA_POP() diff --git a/include/nvexec/stream/common.cuh b/include/nvexec/stream/common.cuh index 1e2a03ac5..c7ef910b3 100644 --- a/include/nvexec/stream/common.cuh +++ b/include/nvexec/stream/common.cuh @@ -1013,6 +1013,13 @@ namespace nv::execution template using __f = STDEXEC::__msize_t<_sizeof_v>>; }; + + using _cuda_error_completion_t = + STDEXEC::completion_signatures; + + template + using _cuda_error_completion_unless_t = + STDEXEC::__if<_NoExcept, STDEXEC::completion_signatures<>, _cuda_error_completion_t>; } // namespace nv::execution namespace nvexec = nv::execution; diff --git a/include/nvexec/stream/upon_stopped.cuh b/include/nvexec/stream/upon_stopped.cuh index d4bc55478..83b88fd63 100644 --- a/include/nvexec/stream/upon_stopped.cuh +++ b/include/nvexec/stream/upon_stopped.cuh @@ -19,14 +19,16 @@ #pragma once #include "../../stdexec/execution.hpp" -#include -#include -#include -#include +#include "../../exec/completion_signatures.hpp" #include "common.cuh" +#include + +#include +#include + STDEXEC_PRAGMA_PUSH() STDEXEC_PRAGMA_IGNORE_EDG(cuda_compile) @@ -125,6 +127,15 @@ namespace nv::execution::_strm Fun fun_; _strm::opstate_base& opstate_; }; + + template + consteval auto _get_completions_fun() noexcept + { + return []() noexcept + { + return __set_value_from_t(); + }; + } } // namespace _upon_stopped template @@ -133,25 +144,7 @@ namespace nv::execution::_strm using sender_concept = STDEXEC::sender_tag; template - using receiver_t = _upon_stopped::receiver; - - template - using __error_completions_t = - __minvoke_q<__concat_completion_signatures_t, - __with_error_invoke_t<__mbind_front_q<__callable_error_t, upon_stopped_t>, - set_stopped_t, - Fun, - __copy_cvref_t, - Env...>, - completion_signatures>; - - template - using completion_signatures = __transform_completion_signatures_t< - __completion_signatures_of_t<__copy_cvref_t, Env...>, - __error_completions_t, - __cmplsigs::__default_set_value, - __cmplsigs::__default_set_error, - __set_value_from_t>; + using _receiver_t = _upon_stopped::receiver; explicit upon_stopped_sender(Sender sndr, Fun fun) noexcept(__nothrow_move_constructible) @@ -160,22 +153,26 @@ namespace nv::execution::_strm {} template <__decays_to Self, STDEXEC::receiver Receiver> - requires receiver_of>> STDEXEC_EXPLICIT_THIS_BEGIN(auto connect)(this Self&& self, Receiver rcvr) - -> stream_opstate_t<__copy_cvref_t, receiver_t, Receiver> + -> stream_opstate_t<__copy_cvref_t, _receiver_t, Receiver> { return stream_opstate<__copy_cvref_t>( static_cast(self).sndr_, static_cast(rcvr), - [&](_strm::opstate_base& stream_provider) -> receiver_t - { return receiver_t(self.fun_, stream_provider); }); + [&](_strm::opstate_base& stream_provider) -> _receiver_t + { return _receiver_t(self.fun_, stream_provider); }); } STDEXEC_EXPLICIT_THIS_END(connect) template <__decays_to Self, class... Env> - static consteval auto get_completion_signatures() -> completion_signatures + static consteval auto get_completion_signatures() { - return {}; + return exec::transform_completion_signatures( + STDEXEC::get_completion_signatures<__copy_cvref_t, Env...>(), + {}, + {}, + _upon_stopped::_get_completions_fun(), + _cuda_error_completion_t()); } auto get_env() const noexcept -> stream_sender_attrs