diff --git a/include/stdexec/__detail/__affine.hpp b/include/stdexec/__detail/__affine.hpp index f0f81f21a..839b06a84 100644 --- a/include/stdexec/__detail/__affine.hpp +++ b/include/stdexec/__detail/__affine.hpp @@ -163,13 +163,14 @@ namespace STDEXEC } } - template <__forwarding_query _Tag, class... _Args> - requires(!__completion_query<_Tag>) - && __queryable_with, _Tag, _Args const &...> - constexpr auto query(_Tag, _Args const &...) const noexcept - -> __query_result_t, _Tag, _Args const &...> + template <__forwarding_query _Query, class... _Args> + requires(!__completion_query<_Query>) + && __queryable_with, _Query, _Args...> + STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) + constexpr auto query(_Query, _Args &&...__args) const + noexcept(__nothrow_queryable_with, _Query, _Args...>) -> decltype(auto) { - return __query_result_t, _Tag, _Args const &...>{}; + return STDEXEC::get_env(__sndr_).query(_Query(), static_cast<_Args &&>(__args)...); } _Sender const &__sndr_; diff --git a/include/stdexec/__detail/__continues_on.hpp b/include/stdexec/__detail/__continues_on.hpp index 54887a115..cf96b8c60 100644 --- a/include/stdexec/__detail/__continues_on.hpp +++ b/include/stdexec/__detail/__continues_on.hpp @@ -268,8 +268,7 @@ namespace STDEXEC && __queryable_with, _Query, _Args...> [[nodiscard]] constexpr auto query(_Query, _Args&&... __args) const - noexcept(__nothrow_queryable_with, _Query, _Args...>) - -> __query_result_t, _Query, _Args...> + noexcept(__nothrow_queryable_with, _Query, _Args...>) -> decltype(auto) { return __attrs_.query(_Query(), static_cast<_Args&&>(__args)...); } @@ -360,8 +359,7 @@ namespace STDEXEC } STDEXEC_CATCH_ALL { - STDEXEC::set_error(static_cast<_State&&>(__state).__rcvr_, std::current_exception()); - return; + __state.__data_.__emplace_from(__mktuple, set_error, std::current_exception()); } } diff --git a/include/stdexec/__detail/__on.hpp b/include/stdexec/__detail/__on.hpp index 258fc24e3..83fbd1d1e 100644 --- a/include/stdexec/__detail/__on.hpp +++ b/include/stdexec/__detail/__on.hpp @@ -110,11 +110,10 @@ namespace STDEXEC requires(!__completion_query<_Query>) && __queryable_with, _Query, _Args...> STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) - constexpr auto query(_Query __query, _Args&&... __args) const - noexcept(__nothrow_queryable_with, _Query, _Args...>) - -> __query_result_t, _Query, _Args...> + constexpr auto query(_Query, _Args&&... __args) const + noexcept(__nothrow_queryable_with, _Query, _Args...>) -> decltype(auto) { - return __query(STDEXEC::get_env(__child_), static_cast<_Args&&>(__args)...); + return STDEXEC::get_env(__child_).query(_Query(), static_cast<_Args&&>(__args)...); } _Child const & __child_; diff --git a/include/stdexec/__detail/__sequence.hpp b/include/stdexec/__detail/__sequence.hpp index ce7626748..73e16379a 100644 --- a/include/stdexec/__detail/__sequence.hpp +++ b/include/stdexec/__detail/__sequence.hpp @@ -79,8 +79,7 @@ namespace STDEXEC requires __queryable_with<_env_t, _Query, _Args...> STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) constexpr auto query(_Query, _Args &&...__args) const - noexcept(__nothrow_queryable_with<_env_t, _Query, _Args...>) - -> __query_result_t<_env_t, _Query, _Args...> + noexcept(__nothrow_queryable_with<_env_t, _Query, _Args...>) -> decltype(auto) { return STDEXEC::get_env(__sndr_).query(_Query(), static_cast<_Args &&>(__args)...); } @@ -174,8 +173,7 @@ namespace STDEXEC requires(!__completion_query<_Query>) && __queryable_with<__joined_t, _Query, _Args...> [[nodiscard]] constexpr auto operator()(_Query, _Args &&...__args) const - noexcept(__nothrow_queryable_with<__joined_t, _Query, _Args...>) - -> __query_result_t<__joined_t, _Query, _Args...> + noexcept(__nothrow_queryable_with<__joined_t, _Query, _Args...>) -> decltype(auto) { return __joined_t{STDEXEC::get_env(__sndr2_), STDEXEC::get_env(__sndr1_)} .query(_Query(), static_cast<_Args &&>(__args)...); diff --git a/include/stdexec/__detail/__starts_on.hpp b/include/stdexec/__detail/__starts_on.hpp index 59b6d8aac..4f0166149 100644 --- a/include/stdexec/__detail/__starts_on.hpp +++ b/include/stdexec/__detail/__starts_on.hpp @@ -87,6 +87,16 @@ namespace STDEXEC { return {}; } + + template <__forwarding_query _Query, class... _Args> + requires(!__completion_query<_Query>) + && __queryable_with, _Query, _Args...> + STDEXEC_ATTRIBUTE(nodiscard, always_inline, host, device) + constexpr auto query(_Query, _Args&&... __args) const + noexcept(__nothrow_queryable_with, _Query, _Args...>) -> decltype(auto) + { + return __attr_.query(_Query(), static_cast<_Args&&>(__args)...); + } }; } // namespace __starts_on diff --git a/test/stdexec/algos/adaptors/test_continues_on.cpp b/test/stdexec/algos/adaptors/test_continues_on.cpp index bc0f0d79e..e1481b7ef 100644 --- a/test/stdexec/algos/adaptors/test_continues_on.cpp +++ b/test/stdexec/algos/adaptors/test_continues_on.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,12 @@ namespace (void) snd; } + TEST_CASE("continues_on forwards non-completion queries", "[adaptors][continues_on]") + { + auto snd = ex::continues_on(test_common::non_completion_query_sender{}, inline_scheduler{}); + CHECK(test_common::non_completion_query(ex::get_env(snd), 41) == 42); + } + TEST_CASE("continues_on with environment returns a sender", "[adaptors][continues_on]") { auto snd = ex::continues_on(ex::just(13), inline_scheduler{}); diff --git a/test/stdexec/algos/adaptors/test_on.cpp b/test/stdexec/algos/adaptors/test_on.cpp index eb896ebc8..d6359c795 100644 --- a/test/stdexec/algos/adaptors/test_on.cpp +++ b/test/stdexec/algos/adaptors/test_on.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -47,6 +48,12 @@ namespace (void) snd; } + TEST_CASE("STDEXEC::on forwards non-completion queries", "[adaptors][on]") + { + auto snd = ex::on(inline_scheduler{}, test_common::non_completion_query_sender{}); + CHECK(test_common::non_completion_query(ex::get_env(snd), 41) == 42); + } + TEST_CASE("STDEXEC::on with environment returns a sender", "[adaptors][on]") { auto snd = ex::on(inline_scheduler{}, ex::just(13)); diff --git a/test/stdexec/algos/adaptors/test_starts_on.cpp b/test/stdexec/algos/adaptors/test_starts_on.cpp index 2b5891dd7..b6229da6f 100644 --- a/test/stdexec/algos/adaptors/test_starts_on.cpp +++ b/test/stdexec/algos/adaptors/test_starts_on.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,12 @@ namespace (void) snd; } + TEST_CASE("starts_on forwards non-completion queries", "[adaptors][starts_on]") + { + auto snd = ex::starts_on(inline_scheduler{}, test_common::non_completion_query_sender{}); + CHECK(test_common::non_completion_query(ex::get_env(snd), 41) == 42); + } + TEST_CASE("starts_on with environment returns a sender", "[adaptors][starts_on]") { auto snd = ex::starts_on(inline_scheduler{}, ex::just(13)); diff --git a/test/test_common/non_completion_query.hpp b/test/test_common/non_completion_query.hpp new file mode 100644 index 000000000..a68ff94cf --- /dev/null +++ b/test/test_common/non_completion_query.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2026 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 with LLVM Exceptions + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace test_common +{ + namespace ex = STDEXEC; + + struct non_completion_query_t + : ex::__query + , ex::forwarding_query_t + { + using ex::__query::operator(); + }; + + inline constexpr non_completion_query_t non_completion_query{}; + + struct non_completion_query_env + { + constexpr auto query(non_completion_query_t, int value) const noexcept -> int + { + return value + 1; + } + }; + + struct non_completion_query_sender + { + using sender_concept = ex::sender_tag; + using completion_signatures = ex::completion_signatures; + + template + struct operation + { + using operation_state_concept = ex::operation_state_tag; + + void start() & noexcept + { + ex::set_value(static_cast(receiver)); + } + + Receiver receiver; + }; + + template + auto connect(Receiver&& receiver) const -> operation> + { + return {static_cast(receiver)}; + } + + auto get_env() const noexcept -> non_completion_query_env + { + return {}; + } + }; +} // namespace test_common