From 162b66a8f5cd30448d1362bb388f2d4845c46d3f Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Fri, 22 May 2026 14:21:46 +0500 Subject: [PATCH 1/7] move inhouse stdexec_assert after definition of stdexec-no-stdcpp-exceptions Replace throw with STDEXEC_THROW --- include/stdexec/__detail/__config.hpp | 64 +++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/include/stdexec/__detail/__config.hpp b/include/stdexec/__detail/__config.hpp index c7e5d3605..aa7b1125b 100644 --- a/include/stdexec/__detail/__config.hpp +++ b/include/stdexec/__detail/__config.hpp @@ -658,38 +658,6 @@ namespace STDEXEC # define STDEXEC_IF_NOT_CONSTEVAL STDEXEC_IF_CONSTEVAL {} else #endif -#if defined(STDEXEC_ASSERT) -// nothing to do, user has provided their own assertion macro -#elif defined(STDEXEC_ASSERT_FN) -// legacy way to customize assertions, still supported for backward compatibility -# define STDEXEC_ASSERT(_XP) STDEXEC_ASSERT_FN(_XP) -#else -# define STDEXEC_ASSERT(_XP) \ - do \ - { \ - STDEXEC_IF_CONSTEVAL \ - { \ - if (!(_XP)) \ - STDEXEC::__throw_assertion_failure(); \ - } \ - else \ - { \ - assert(_XP); \ - } \ - } while (false) -#endif - -namespace STDEXEC -{ - struct __assertion_failure - {}; - - inline void __throw_assertion_failure() - { - throw __assertion_failure{}; - } -} // namespace STDEXEC - #define STDEXEC_AUTO_RETURN(...) \ noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { \ return __VA_ARGS__; \ @@ -810,6 +778,38 @@ namespace STDEXEC } } // namespace STDEXEC +#if defined(STDEXEC_ASSERT) +// nothing to do, user has provided their own assertion macro +#elif defined(STDEXEC_ASSERT_FN) +// legacy way to customize assertions, still supported for backward compatibility +# define STDEXEC_ASSERT(_XP) STDEXEC_ASSERT_FN(_XP) +#else +# define STDEXEC_ASSERT(_XP) \ + do \ + { \ + STDEXEC_IF_CONSTEVAL \ + { \ + if (!(_XP)) \ + STDEXEC::__throw_assertion_failure(); \ + } \ + else \ + { \ + assert(_XP); \ + } \ + } while (false) +#endif + +namespace STDEXEC +{ + struct __assertion_failure + {}; + + inline void __throw_assertion_failure() + { + STDEXEC_THROW(__assertion_failure{}); + } +} // namespace STDEXEC + /////////////////////////////////////////////////////////////////////////////// /// To hook a customization point like STDEXEC::connect, define a member /// function like this: From 7b0f99274421ccf53943a2644600e862437ad709 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Fri, 22 May 2026 14:22:19 +0500 Subject: [PATCH 2/7] make tests respect !STDEXEC_NO_STDCPP_EXCEPTIONS --- test/exec/sequence/test_ignore_all_values.cpp | 2 +- test/exec/test_any_sender.cpp | 16 ++++++++------- test/exec/test_function.cpp | 20 ++++++++++--------- test/exec/test_repeat_until.cpp | 2 ++ test/exec/test_type_async_scope.cpp | 4 ++-- test/exec/test_when_any.cpp | 8 ++++---- .../stdexec/algos/adaptors/test_let_value.cpp | 4 +++- .../algos/adaptors/test_spawn_future.cpp | 2 ++ test/stdexec/algos/consumers/test_spawn.cpp | 3 ++- test/stdexec/algos/factories/test_just.cpp | 2 ++ .../concepts/test_concepts_receiver.cpp | 3 +++ .../cpos/test_cpo_connect_awaitable.cpp | 2 ++ test/stdexec/cpos/test_cpo_receiver.cpp | 2 ++ test/stdexec/detail/test_any.cpp | 5 ++++- test/stdexec/types/test_counting_scopes.cpp | 2 ++ test/stdexec/types/test_task.cpp | 2 ++ 16 files changed, 53 insertions(+), 26 deletions(-) diff --git a/test/exec/sequence/test_ignore_all_values.cpp b/test/exec/sequence/test_ignore_all_values.cpp index ee288e864..3cd700533 100644 --- a/test/exec/sequence/test_ignore_all_values.cpp +++ b/test/exec/sequence/test_ignore_all_values.cpp @@ -78,7 +78,6 @@ namespace STDEXEC::completion_signatures_of_t>>); CHECK_THROWS(STDEXEC::sync_wait(sndr)); } -#endif // !STDEXEC_NO_STDCPP_EXCEPTIONS() struct sequence_op { @@ -114,4 +113,5 @@ namespace STDEXEC::set_error_t(std::exception_ptr)>; STATIC_REQUIRE(STDEXEC::__mset_eq); } +#endif // !STDEXEC_NO_STDCPP_EXCEPTIONS() } // namespace diff --git a/test/exec/test_any_sender.cpp b/test/exec/test_any_sender.cpp index 4cd5b4fe9..fd2ea56a8 100644 --- a/test/exec/test_any_sender.cpp +++ b/test/exec/test_any_sender.cpp @@ -41,7 +41,7 @@ STDEXEC_PRAGMA_IGNORE_EDG(deprecated_entity_with_custom_message) namespace { struct get_address_t : ex::__query - {}; + { }; inline constexpr get_address_t get_address; @@ -149,12 +149,12 @@ namespace ex::set_value(static_cast(ref), 42); CHECK(value.value_.index() == 1); CHECK(std::get<1>(value.value_) == 42); +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() // Check set error CHECK(error.value_.index() == 0); ref = error; ex::set_error(static_cast(ref), std::make_exception_ptr(42)); CHECK(error.value_.index() == 2); -#if !STDEXEC_NO_STDCPP_EXCEPTIONS() // MSVC issues a warning about unreachable code in this block, hence the warning // suppression at the top of the file. CHECK_THROWS_AS(std::rethrow_exception(std::get<2>(error.value_)), int); @@ -199,7 +199,7 @@ namespace { int value = 0; any_sender_of sndr = ex::just(42) - | ex::then([&](int v) noexcept { value = v; }); + | ex::then([&](int v) noexcept { value = v; }); CHECK(std::same_as>, ex::completion_signatures>); ex::sync_wait(std::move(sndr)); @@ -319,7 +319,7 @@ namespace explicit constexpr stopped_token(bool stopped) noexcept : stopped_{stopped} - {} + { } template using callback_type = __callback_type; @@ -362,7 +362,7 @@ namespace stopped_receiver(Token token, bool expect_stop) : stopped_receiver_base{token} , expect_stop_{expect_stop} - {} + { } bool expect_stop_{false}; @@ -610,11 +610,13 @@ namespace auto op = ex::connect(ex::schedule(scheduler), expect_stopped_receiver{}); ex::start(op); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() scheduler = error_scheduler<>{std::make_exception_ptr(std::logic_error("test"))}; { auto op = ex::connect(ex::schedule(scheduler), expect_error_receiver<>{}); ex::start(op); } +#endif // !STDEXEC_NO_STDCPP_EXCEPTIONS() } TEST_CASE("any_scheduler sender lifetime", "[types][any_scheduler][any_sender]") @@ -799,14 +801,14 @@ namespace TEST_CASE("any_receiver", "[types][any_sender]") { using completions_t = ex::completion_signatures; using queries_t = exec::queries; using any_receiver_t = exec::any_receiver; any_receiver_t rcvr = sink{}; std::move(rcvr).set_value(42); - std::move(rcvr).set_error(std::make_exception_ptr(std::runtime_error("error"))); + std::move(rcvr).set_error(std::string_view{"error"}); std::move(rcvr).set_stopped(); [[maybe_unused]] diff --git a/test/exec/test_function.cpp b/test/exec/test_function.cpp index 6283df70e..6b996f39e 100644 --- a/test/exec/test_function.cpp +++ b/test/exec/test_function.cpp @@ -103,6 +103,16 @@ namespace REQUIRE(fortytwo == 42); } + SECTION("void() from just_stopped()") + { + exec::function sndr([]() noexcept { return ex::just_stopped(); }); + + auto ret = ex::sync_wait(std::move(sndr)); + + REQUIRE_FALSE(ret.has_value()); + } + +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() SECTION("void() from throwing factory") { exec::function sndr([]() -> decltype(ex::just()) { throw "oops"; }); @@ -118,15 +128,6 @@ namespace REQUIRE_THROWS(ex::sync_wait(std::move(sndr))); } - SECTION("void() from just_stopped()") - { - exec::function sndr([]() noexcept { return ex::just_stopped(); }); - - auto ret = ex::sync_wait(std::move(sndr)); - - REQUIRE_FALSE(ret.has_value()); - } - SECTION("custom completions from just_error(42)") { exec::function ::STDEXEC::task test_awaitable_in_stdexec_task(AsyncScope& scope) { @@ -144,6 +144,6 @@ namespace exec::async_scope scope; CHECK_NOTHROW(test_awaitable_in_stdexec_task(scope)); } -#endif // !STDEXEC_NO_STDCPP_COROUTINES() +#endif // !STDEXEC_NO_STDCPP_COROUTINES() && !STDEXEC_NO_STDCPP_EXCEPTIONS() } // namespace diff --git a/test/exec/test_when_any.cpp b/test/exec/test_when_any.cpp index 00a601738..0195eec3a 100644 --- a/test/exec/test_when_any.cpp +++ b/test/exec/test_when_any.cpp @@ -77,7 +77,7 @@ namespace stopped_scheduler stop; int result = 42; ex::sender auto snd = exec::when_any(completes_if{false}, ex::schedule(stop)) - | ex::then([&result] { result += 1; }); + | ex::then([&result] { result += 1; }); ex::sync_wait(std::move(snd)); REQUIRE(result == 42); } @@ -98,7 +98,7 @@ namespace { int result = 41; ex::sender auto snd = exec::when_any(ex::just_stopped(), completes_if{false}) - | ex::upon_stopped([&result] { result += 1; }); + | ex::upon_stopped([&result] { result += 1; }); ex::sync_wait(std::move(snd)); REQUIRE(result == 42); } @@ -131,7 +131,7 @@ namespace { move_throws() = default; - move_throws(move_throws&&) noexcept(false) {} + move_throws(move_throws&&) noexcept(false) { } auto operator=(move_throws&&) noexcept(false) -> move_throws& { @@ -188,6 +188,7 @@ namespace // wait_for_value(std::move(snd), movable(42)); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() template struct dup_op { @@ -214,7 +215,6 @@ namespace } }; -#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("when_any - with duplicate completions", "[adaptors][when_any]") { REQUIRE_THROWS(STDEXEC::sync_wait(exec::when_any(dup_sender{}))); diff --git a/test/stdexec/algos/adaptors/test_let_value.cpp b/test/stdexec/algos/adaptors/test_let_value.cpp index dec4733ef..7fd8ec319 100644 --- a/test/stdexec/algos/adaptors/test_let_value.cpp +++ b/test/stdexec/algos/adaptors/test_let_value.cpp @@ -105,6 +105,7 @@ namespace ex::start(op); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() auto is_prime(int x) -> bool { if (x > 2 && (x % 2 == 0)) @@ -119,7 +120,6 @@ namespace return true; } -#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("let_value can be used for composition", "[adaptors][let_value]") { bool called1{false}; @@ -414,6 +414,7 @@ namespace CHECK(completed); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() struct throws_on_connect { using sender_concept = ::STDEXEC::sender_tag; @@ -516,4 +517,5 @@ namespace auto op = ex::connect(sender, expect_void_receiver{}); ex::start(op); } +#endif } // namespace diff --git a/test/stdexec/algos/adaptors/test_spawn_future.cpp b/test/stdexec/algos/adaptors/test_spawn_future.cpp index 163cd4856..740ed055e 100644 --- a/test/stdexec/algos/adaptors/test_spawn_future.cpp +++ b/test/stdexec/algos/adaptors/test_spawn_future.cpp @@ -243,6 +243,7 @@ namespace CHECK(rsc2.allocated() == 0); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("spawn_future tolerates throwing scope tokens", "[consumers][spawn_future]") { counting_resource rsc; @@ -276,6 +277,7 @@ namespace CHECK(rsc.allocated() == 0); } +#endif TEST_CASE("spawn_future tolerates expired scope tokens", "[consumers][spawn_future]") { diff --git a/test/stdexec/algos/consumers/test_spawn.cpp b/test/stdexec/algos/consumers/test_spawn.cpp index 34652404c..95ad8ca00 100644 --- a/test/stdexec/algos/consumers/test_spawn.cpp +++ b/test/stdexec/algos/consumers/test_spawn.cpp @@ -120,7 +120,7 @@ namespace REQUIRE(rsc1.allocated() == 0); REQUIRE(rsc2.allocated() == 0); } - +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("spawn tolerates throwing scope tokens", "[consumers][spawn]") { counting_resource rsc; @@ -154,6 +154,7 @@ namespace REQUIRE(rsc.allocated() == 0); } +#endif TEST_CASE("spawn tolerates expired scope tokens", "[consumers][spawn]") { diff --git a/test/stdexec/algos/factories/test_just.cpp b/test/stdexec/algos/factories/test_just.cpp index 583e8448e..843015905 100644 --- a/test/stdexec/algos/factories/test_just.cpp +++ b/test/stdexec/algos/factories/test_just.cpp @@ -160,6 +160,7 @@ namespace CHECK(cat == typecat::rvalref); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("just works with types with throwing move", "[factories][just]") { struct throwing_move @@ -226,6 +227,7 @@ namespace ::STDEXEC::start(op); CHECK(invoked == 1); } +#endif TEST_CASE("just completes inline and has no completion domain", "[factories][just]") { diff --git a/test/stdexec/concepts/test_concepts_receiver.cpp b/test/stdexec/concepts/test_concepts_receiver.cpp index a35fbd9cf..7b0e8d59e 100644 --- a/test/stdexec/concepts/test_concepts_receiver.cpp +++ b/test/stdexec/concepts/test_concepts_receiver.cpp @@ -64,6 +64,7 @@ struct recv_set_value_noexcept } }; +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() struct recv_set_error_except { using receiver_concept = STDEXEC::receiver_tag; @@ -81,6 +82,7 @@ struct recv_set_error_except return {}; } }; + struct recv_set_stopped_except { using receiver_concept = STDEXEC::receiver_tag; @@ -98,6 +100,7 @@ struct recv_set_stopped_except return {}; } }; +#endif struct recv_non_movable { diff --git a/test/stdexec/cpos/test_cpo_connect_awaitable.cpp b/test/stdexec/cpos/test_cpo_connect_awaitable.cpp index 3702bdde8..7535b65f5 100644 --- a/test/stdexec/cpos/test_cpo_connect_awaitable.cpp +++ b/test/stdexec/cpos/test_cpo_connect_awaitable.cpp @@ -492,6 +492,7 @@ namespace } } +# if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("exceptions thrown from await_ready are reported to set_error", "[cpo][cpo_connect_awaitable]") { @@ -689,6 +690,7 @@ namespace op.start(); } } +# endif struct stop_on_suspend { diff --git a/test/stdexec/cpos/test_cpo_receiver.cpp b/test/stdexec/cpos/test_cpo_receiver.cpp index 16d208a33..9ab3711cb 100644 --- a/test/stdexec/cpos/test_cpo_receiver.cpp +++ b/test/stdexec/cpos/test_cpo_receiver.cpp @@ -129,11 +129,13 @@ namespace ex::set_stopped(expect_stopped_receiver{}); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("can call set_error on a receiver", "[cpo][cpo_receiver]") { std::exception_ptr ex = std::make_exception_ptr(std::bad_alloc{}); ex::set_error(expect_error_receiver{}, ex); } +#endif TEST_CASE("can call set_error with an error code on a receiver", "[cpo][cpo_receiver]") { diff --git a/test/stdexec/detail/test_any.cpp b/test/stdexec/detail/test_any.cpp index 17497a4f3..4e1f94f7c 100644 --- a/test/stdexec/detail/test_any.cpp +++ b/test/stdexec/detail/test_any.cpp @@ -209,6 +209,7 @@ namespace static_assert(any::__iabstract::__buffer_size < any::__iabstract::__buffer_size); +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() // test constant evaluation works template consteval void test_consteval() @@ -231,6 +232,7 @@ namespace [[maybe_unused]] auto y = any::__any_cast>(pifoo); } +#endif template struct iempty : any::__interface_base, 0> @@ -249,7 +251,8 @@ namespace { static constexpr bool is_small = std::same_as>; -#if STDEXEC_CLANG() || (STDEXEC_GCC() && STDEXEC_GCC_VERSION >= 1403) +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() \ + && (STDEXEC_CLANG() || (STDEXEC_GCC() && STDEXEC_GCC_VERSION >= 1403)) test_consteval(); // NOLINT(invalid_consteval_call) #endif diff --git a/test/stdexec/types/test_counting_scopes.cpp b/test/stdexec/types/test_counting_scopes.cpp index 7a946fb8e..4465a36b6 100644 --- a/test/stdexec/types/test_counting_scopes.cpp +++ b/test/stdexec/types/test_counting_scopes.cpp @@ -220,6 +220,7 @@ namespace REQUIRE(!failed); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() SCOPE_TEST_CASE("spawn lots of concurrent join-senders looking for UB") { exec::static_thread_pool pool; @@ -273,6 +274,7 @@ namespace REQUIRE(!failed); } +#endif TEST_CASE("counting_scope::request_stop signals associated senders", "[types][counting_scope]") { diff --git a/test/stdexec/types/test_task.cpp b/test/stdexec/types/test_task.cpp index daf8dd072..b3b69f29f 100644 --- a/test/stdexec/types/test_task.cpp +++ b/test/stdexec/types/test_task.cpp @@ -134,6 +134,7 @@ namespace CHECK(i == 42); } +# if !STDEXEC_NO_STDCPP_EXCEPTIONS() auto test_task_awaits_just_error_sender() -> ex::task { co_await ex::just_error(std::runtime_error("error")); @@ -145,6 +146,7 @@ namespace auto t = test_task_awaits_just_error_sender(); REQUIRE_THROWS_AS(ex::sync_wait(std::move(t)), std::runtime_error); } +# endif auto test_task_awaits_just_stopped_sender() -> ex::task { From e2056bcf04d7fac8c5c63c4ffdd65c1b8305101d Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Fri, 22 May 2026 14:31:29 +0500 Subject: [PATCH 3/7] add atleast one -fno-exceptions test --- .github/workflows/ci.cpu.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.cpu.yml b/.github/workflows/ci.cpu.yml index f46782ed5..d0cc8c122 100644 --- a/.github/workflows/ci.cpu.yml +++ b/.github/workflows/ci.cpu.yml @@ -26,6 +26,7 @@ jobs: - { name: "CPU (clang 16, Release, ASAN)", build: "Release", tag: llvm16-cuda12.9, cxxstd: "20", cxxflags: "-stdlib=libc++ -fsanitize=address -fsanitize-ignorelist=/home/coder/stdexec/sanitizer-ignorelist.txt" } - { name: "CPU (clang 22, Debug)", build: "Debug", tag: llvm22-cuda13.2, cxxstd: "23", cxxflags: "-stdlib=libc++" } - { name: "CPU (clang 22, Release)", build: "Release", tag: llvm22-cuda13.2, cxxstd: "23", cxxflags: "-stdlib=libc++" } + - { name: "CPU (clang 22, Release, noexcept)", build: "Release", tag: llvm22-cuda13.2, cxxstd: "23", cxxflags: "-stdlib=libc++ -fno-exceptions" } - { name: "CPU (gcc 12, Debug)", build: "Debug", tag: gcc12-cuda12.9, cxxstd: "20", cxxflags: "", } - { name: "CPU (gcc 12, Release)", build: "Release", tag: gcc12-cuda12.9, cxxstd: "20", cxxflags: "", } # With the following config, 2 tests mysteriously time out, but only in CI and not locally. @@ -39,6 +40,7 @@ jobs: - { name: "CPU (gcc 14, Release, LEAK)", build: "Release", tag: gcc14-cuda12.9, cxxstd: "20", cxxflags: "-fsanitize=leak", } - { name: "CPU (gcc 14, Release, c++23)", build: "Release", tag: gcc14-cuda12.9, cxxstd: "23", cxxflags: "", } - { name: "CPU (gcc 15, Release, c++23)", build: "Release", tag: gcc15-cuda12.9, cxxstd: "23", cxxflags: "", } + - { name: "CPU (gcc 15, Release, c++23,noexcept)", build: "Release", tag: gcc15-cuda12.9, cxxstd: "23", cxxflags: "-fno-exceptions", } container: options: -u root image: rapidsai/devcontainers:26.06-cpp-${{ matrix.tag }} From 05c1ca58eb5958cc7809fa8c7b2ec54a66696407 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Mon, 25 May 2026 18:17:51 +0500 Subject: [PATCH 4/7] provide boost::throw_exception implementation for fno-exception builds --- include/exec/asio/asio_thread_pool.hpp | 2 + include/exec/asio/noexcept_boost_throw.hpp | 45 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 include/exec/asio/noexcept_boost_throw.hpp diff --git a/include/exec/asio/asio_thread_pool.hpp b/include/exec/asio/asio_thread_pool.hpp index 589c29d2a..30632033a 100644 --- a/include/exec/asio/asio_thread_pool.hpp +++ b/include/exec/asio/asio_thread_pool.hpp @@ -19,6 +19,8 @@ #include +#include "noexcept_boost_throw.hpp" + #include "../thread_pool_base.hpp" namespace experimental::execution::asio diff --git a/include/exec/asio/noexcept_boost_throw.hpp b/include/exec/asio/noexcept_boost_throw.hpp new file mode 100644 index 000000000..a829a59c4 --- /dev/null +++ b/include/exec/asio/noexcept_boost_throw.hpp @@ -0,0 +1,45 @@ +/* + * 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://llvm.org/LICENSE.txt + * + * 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 +#include + +/** + * This is a boost::throw_exception implementation provided for fno-exceptions builds + */ +#if STDEXEC_ASIO_USES_BOOST && STDEXEC_NO_STDCPP_EXCEPTIONS() + +# include +# include + +# include +# include + +namespace boost +{ + void throw_exception(std::exception const &) + { + std::abort(); + } + + void throw_exception(std::exception const &, boost::source_location const &) + { + std::abort(); + } +} // namespace boost +#endif From 377aecd913cb146a97196cca4f208061a71de9f1 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Mon, 25 May 2026 18:18:05 +0500 Subject: [PATCH 5/7] fix asio tests for -fno-exceptions --- test/exec/asio/test_asio_thread_pool.cpp | 2 ++ test/exec/asio/test_completion_token.cpp | 8 ++++++++ test/exec/asio/test_use_sender.cpp | 4 +++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/test/exec/asio/test_asio_thread_pool.cpp b/test/exec/asio/test_asio_thread_pool.cpp index 1cbcdd3d6..1eb69e39a 100644 --- a/test/exec/asio/test_asio_thread_pool.cpp +++ b/test/exec/asio/test_asio_thread_pool.cpp @@ -136,6 +136,7 @@ namespace CHECK(k == 5); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("asio_thread_pool exceptions", "[asio_thread_pool]") { using namespace STDEXEC; @@ -158,6 +159,7 @@ namespace CHECK(tbb_result == other_result); } } +#endif TEST_CASE("asio_thread_pool async_inclusive_scan", "[asio_thread_pool]") { diff --git a/test/exec/asio/test_completion_token.cpp b/test/exec/asio/test_completion_token.cpp index 8943653e3..ae2458d39 100644 --- a/test/exec/asio/test_completion_token.cpp +++ b/test/exec/asio/test_completion_token.cpp @@ -204,6 +204,7 @@ namespace CHECK(ctx.stopped()); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() template decltype(auto) async_throw_from_initiation(CompletionToken&& token) { @@ -262,6 +263,7 @@ namespace CHECK(ctx.stopped()); CHECK(ex); } +#endif TEST_CASE("When an operation is abandoned this is reported via a stopped " "signal", @@ -346,6 +348,7 @@ namespace CHECK(ptr.use_count() == 1U); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() template decltype(auto) async_indirect_completion_handler_throw_from_completion(Executor const & ex, std::shared_ptr& ptr, @@ -417,6 +420,7 @@ namespace ptr.reset(); CHECK(ex); } +#endif template decltype(auto) async_multishot(CompletionToken&& token) @@ -568,6 +572,7 @@ namespace b.join(); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("When the initiating function posts and then throws, and the " "posted operation simply abandons the completion handler, the operation " "completes after the post with the thrown error", @@ -695,6 +700,7 @@ namespace start_shared(std::move(b)); CHECK(ex); } +#endif struct value_category_receiver { @@ -978,6 +984,7 @@ namespace CHECK(!cancelled); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("Upon exception the stop token is no longer in use", "[asioexec][use_sender]") { bool cancelled = false; @@ -1079,6 +1086,7 @@ namespace CHECK(ctx.stopped()); CHECK(ex); } +#endif TEST_CASE("I/O objects may be transformed to use senders as their default vocabulary with only " "minimal " diff --git a/test/exec/asio/test_use_sender.cpp b/test/exec/asio/test_use_sender.cpp index 457042dbc..5c2f9221a 100644 --- a/test/exec/asio/test_use_sender.cpp +++ b/test/exec/asio/test_use_sender.cpp @@ -203,6 +203,7 @@ namespace token); } +#if !STDEXEC_NO_STDCPP_EXCEPTIONS() TEST_CASE("Error codes native to the version of Asio used are transformed " "into a system_error", "[asioexec][use_sender]") @@ -238,6 +239,7 @@ namespace REQUIRE(ex); CHECK_THROWS_AS(std::rethrow_exception(std::move(ex)), std::system_error); } +#endif TEST_CASE("I/O objects may be transformed to use senders as their default vocabulary", "[asioexec][use_sender]") @@ -270,7 +272,7 @@ namespace CHECK(ctx.stopped()); } -#if !STDEXEC_NO_STDCPP_COROUTINES() +#if !STDEXEC_NO_STDCPP_COROUTINES() && !STDEXEC_NO_STDCPP_EXCEPTIONS() template ::STDEXEC::task test_awaitable_in_stdexec_task(Timer& timer) { From 6d95a0831fe748dd26c853d7efc2bcc53b6611e1 Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Wed, 27 May 2026 11:39:59 +0500 Subject: [PATCH 6/7] suppres Wunsed-parameter with fno-exceptions due to catch2 bug --- CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 217aa5227..ca9cb3798 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,9 +272,16 @@ add_library(STDEXEC::stdexec ALIAS stdexec) # Support target for examples and tests add_library(stdexec_executable_flags INTERFACE) +# suppress Wunused-parameter in cased of fno-exceptions due to Catch2 bug https://github.com/catchorg/Catch2/issues/3114 +if(CMAKE_CXX_FLAGS MATCHES "-fno-exceptions") + set(SUPPRESS_WUNUSED_PARAMETER 1) +else() + set(SUPPRESS_WUNUSED_PARAMETER 0) +endif() + # Enable warnings target_compile_options(stdexec_executable_flags INTERFACE - $<$:-Wall;-Werror=unused-parameter> + $<$:-Wall;$> $<$:-Wall> $<$:/W4>) From 054ccbc2c7ac5b04754a32ce54d8e0f99475df3c Mon Sep 17 00:00:00 2001 From: BartolomeyKant Date: Thu, 4 Jun 2026 11:54:41 +0500 Subject: [PATCH 7/7] make not build relacy tests for gnu with -fno-exceptions --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca9cb3798..2e7525051 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,11 +173,13 @@ endif() # Additionally, we require GCC-12 or newer for Relacy, at __atomic.hpp has fallback # when std::atomic> is not provided, and GCC-12 is the first # libstdc++ that provides it. +# Additionally, realacy is not ready for -fno-exceptions. if( ${STDEXEC_BUILD_TESTS} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12 AND - NOT CMAKE_CXX_FLAGS MATCHES "-fsanitize") + NOT CMAKE_CXX_FLAGS MATCHES "-fsanitize" AND + NOT CMAKE_CXX_FLAGS MATCHES "-fno-exceptions") set(STDEXEC_BUILD_RELACY_TESTS_DEFAULT ON) else() set(STDEXEC_BUILD_RELACY_TESTS_DEFAULT OFF)