[libcxx-commits] [libcxx] [libc++][execution] Implement C++26 std::execution set_value, set_error and set_stopped (PR #229095)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Oct 5 21:50:51 PDT 2026
https://github.com/emmett2020 updated https://github.com/llvm/llvm-project/pull/229095
>From 3d5a8c845547b7dc0742f9e957b20addf626e1fb Mon Sep 17 00:00:00 2001
From: Emmett <emmettzhang2020 at outlook.com>
Date: Mon, 5 Oct 2026 21:44:28 +0800
Subject: [PATCH 1/2] [libc++][execution] Implement C++26
std::execution::set_value, set_error, and set_stopped
---
libcxx/docs/Status/Cxx26Papers.csv | 2 +-
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__configuration/experimental.h | 1 +
.../__execution/completion_functions.h | 84 +++++++++++++
libcxx/include/execution | 10 ++
libcxx/include/module.modulemap.in | 1 +
libcxx/modules/std/execution.inc | 16 +++
.../exec.recv/completion_functions.verify.cpp | 59 +++++++++
.../exec.recv/completion_functions.pass.cpp | 117 ++++++++++++++++++
libcxx/utils/libcxx/test/params.py | 1 +
10 files changed, 291 insertions(+), 1 deletion(-)
create mode 100644 libcxx/include/__execution/completion_functions.h
create mode 100644 libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp
create mode 100644 libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp
diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv
index f3cdf8c53bab4..3ed07bd6ce574 100644
--- a/libcxx/docs/Status/Cxx26Papers.csv
+++ b/libcxx/docs/Status/Cxx26Papers.csv
@@ -74,7 +74,7 @@
"`P2968R2 <https://wg21.link/P2968R2>`__","Make ``std::ignore`` a first-class object","2024-06 (St. Louis)","|Complete|","19","`#105436 <https://github.com/llvm/llvm-project/issues/105436>`__",""
"`P2075R6 <https://wg21.link/P2075R6>`__","Philox as an extension of the C++ RNG engines","2024-06 (St. Louis)","","","`#105437 <https://github.com/llvm/llvm-project/issues/105437>`__",""
"`P2422R1 <https://wg21.link/P2422R1>`__","Remove ``nodiscard`` annotations from the standard library specification","2024-06 (St. Louis)","|Complete|","19","`#105438 <https://github.com/llvm/llvm-project/issues/105438>`__","``nodiscard`` attributes were kept as a conforming extension"
-"`P2300R10 <https://wg21.link/P2300R10>`__","``std::execution``","2024-06 (St. Louis)","","","`#105440 <https://github.com/llvm/llvm-project/issues/105440>`__",""
+"`P2300R10 <https://wg21.link/P2300R10>`__","``std::execution``","2024-06 (St. Louis)","|Partial|","","`#105440 <https://github.com/llvm/llvm-project/issues/105440>`__",""
"","","","","","",""
"`P3136R1 <https://wg21.link/P3136R1>`__","Retiring niebloids","2024-11 (Wrocław)","|Complete|","14","`#118133 <https://github.com/llvm/llvm-project/issues/118133>`__",""
"`P3138R5 <https://wg21.link/P3138R5>`__","``views::cache_latest``","2024-11 (Wrocław)","","","`#118134 <https://github.com/llvm/llvm-project/issues/118134>`__",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1ee2081561fd9..d96cb3c116352 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -367,6 +367,7 @@ set(files
__exception/nested_exception.h
__exception/operations.h
__exception/terminate.h
+ __execution/completion_functions.h
__expected/bad_expected_access.h
__expected/expected.h
__expected/unexpect.h
diff --git a/libcxx/include/__configuration/experimental.h b/libcxx/include/__configuration/experimental.h
index bb38d8297c63d..7445cc7eb3b64 100644
--- a/libcxx/include/__configuration/experimental.h
+++ b/libcxx/include/__configuration/experimental.h
@@ -30,6 +30,7 @@
#endif
#define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+#define _LIBCPP_HAS_EXPERIMENTAL_EXECUTION _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
#define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
#define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
#define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
diff --git a/libcxx/include/__execution/completion_functions.h b/libcxx/include/__execution/completion_functions.h
new file mode 100644
index 0000000000000..3e0e24a3c76a1
--- /dev/null
+++ b/libcxx/include/__execution/completion_functions.h
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___EXECUTION_COMPLETION_FUNCTIONS_H
+#define _LIBCPP___EXECUTION_COMPLETION_FUNCTIONS_H
+
+#include <__config>
+#include <__type_traits/is_const.h>
+#include <__type_traits/is_reference.h>
+#include <__type_traits/is_same.h>
+#include <__utility/forward.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_EXECUTION
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace execution {
+
+// [exec.set.value]
+struct set_value_t {
+ template <class _Receiver, class... _Args>
+ requires(!is_lvalue_reference_v<_Receiver> && !is_const_v<_Receiver>) &&
+ requires(_Receiver&& __rcvr, _Args&&... __args) {
+ std::forward<_Receiver>(__rcvr).set_value(std::forward<_Args>(__args)...);
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Receiver&& __rcvr, _Args&&... __args) const noexcept {
+ static_assert(noexcept(std::forward<_Receiver>(__rcvr).set_value(std::forward<_Args>(__args)...)),
+ "set_value must be noexcept");
+ static_assert(is_same_v<decltype(std::forward<_Receiver>(__rcvr).set_value(std::forward<_Args>(__args)...)), void>,
+ "set_value must return void");
+ std::forward<_Receiver>(__rcvr).set_value(std::forward<_Args>(__args)...);
+ }
+};
+
+// [exec.set.error]
+struct set_error_t {
+ template <class _Receiver, class _Error>
+ requires(!is_lvalue_reference_v<_Receiver> && !is_const_v<_Receiver>) &&
+ requires(_Receiver&& __rcvr, _Error&& __error) {
+ std::forward<_Receiver>(__rcvr).set_error(std::forward<_Error>(__error));
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Receiver&& __rcvr, _Error&& __error) const noexcept {
+ static_assert(noexcept(std::forward<_Receiver>(__rcvr).set_error(std::forward<_Error>(__error))),
+ "set_error must be noexcept");
+ static_assert(is_same_v<decltype(std::forward<_Receiver>(__rcvr).set_error(std::forward<_Error>(__error))), void>,
+ "set_error must return void");
+ std::forward<_Receiver>(__rcvr).set_error(std::forward<_Error>(__error));
+ }
+};
+
+// [exec.set.stopped]
+struct set_stopped_t {
+ template <class _Receiver>
+ requires(!is_lvalue_reference_v<_Receiver> && !is_const_v<_Receiver>) && requires(_Receiver&& __rcvr) {
+ std::forward<_Receiver>(__rcvr).set_stopped();
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Receiver&& __rcvr) const noexcept {
+ static_assert(noexcept(std::forward<_Receiver>(__rcvr).set_stopped()), "set_stopped must be noexcept");
+ static_assert(
+ is_same_v<decltype(std::forward<_Receiver>(__rcvr).set_stopped()), void>, "set_stopped must return void");
+ std::forward<_Receiver>(__rcvr).set_stopped();
+ }
+};
+
+inline constexpr set_value_t set_value{};
+inline constexpr set_error_t set_error{};
+inline constexpr set_stopped_t set_stopped{};
+
+} // namespace execution
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_EXECUTION
+
+#endif // _LIBCPP___EXECUTION_COMPLETION_FUNCTIONS_H
diff --git a/libcxx/include/execution b/libcxx/include/execution
index 49a901282fd9b..9e18989b5b0a1 100644
--- a/libcxx/include/execution
+++ b/libcxx/include/execution
@@ -21,6 +21,15 @@ namespace std::execution {
inline constexpr parallel_policy par = implementation-defined;
inline constexpr parallel_unsequenced_policy par_unseq = implementation-defined;
inline constexpr unsequenced_policy unseq = implementation-defined; // since C++20
+
+ // completion functions, since C++26
+ struct set_value_t;
+ struct set_error_t;
+ struct set_stopped_t;
+
+ inline constexpr set_value_t set_value{};
+ inline constexpr set_error_t set_error{};
+ inline constexpr set_stopped_t set_stopped{};
}
namespace std {
@@ -36,6 +45,7 @@ namespace std {
# include <__cxx03/__config>
#else
# include <__config>
+# include <__execution/completion_functions.h>
# include <__type_traits/is_execution_policy.h>
# include <__type_traits/is_same.h>
# include <__type_traits/remove_cvref.h>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 28ae9ee8de46a..06b669c242d8b 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1266,6 +1266,7 @@ module std {
module execution {
header "execution"
+ header "__execution/completion_functions.h"
export *
}
diff --git a/libcxx/modules/std/execution.inc b/libcxx/modules/std/execution.inc
index 86c1cd7622b9b..928e0285f502e 100644
--- a/libcxx/modules/std/execution.inc
+++ b/libcxx/modules/std/execution.inc
@@ -34,3 +34,19 @@ export namespace std::execution {
using std::execution::unseq;
} // namespace std::execution
#endif // _LIBCPP_ENABLE_EXPERIMENTAL
+
+#if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_EXECUTION
+export namespace std::execution {
+ // [exec.set.value], value completion function
+ using std::execution::set_value;
+ using std::execution::set_value_t;
+
+ // [exec.set.error], error completion function
+ using std::execution::set_error;
+ using std::execution::set_error_t;
+
+ // [exec.set.stopped], stopped completion function
+ using std::execution::set_stopped;
+ using std::execution::set_stopped_t;
+} // namespace std::execution
+#endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_EXECUTION
diff --git a/libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp b/libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp
new file mode 100644
index 0000000000000..7ad34c3db9f15
--- /dev/null
+++ b/libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+// UNSUPPORTED: libcpp-has-no-experimental-execution
+
+// The noexcept and void-return requirements are mandates, not constraints.
+
+#include <execution>
+
+namespace ex = std::execution;
+
+struct ThrowingReceiver {
+ void set_value() && noexcept(false);
+ void set_error(int) && noexcept(false);
+ void set_stopped() && noexcept(false);
+};
+
+struct NonVoidReceiver {
+ int set_value() && noexcept;
+ int set_error(int) && noexcept;
+ int set_stopped() && noexcept;
+};
+
+// Objects of this type can be converted to int, but the conversion may throw.
+struct ThrowingConversion {
+ operator int() noexcept(false);
+};
+
+struct ConversionReceiver {
+ void set_value(int) && noexcept;
+ void set_error(int) && noexcept;
+};
+
+void test() {
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_value must be noexcept}}
+ ex::set_value(ThrowingReceiver{});
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_error must be noexcept}}
+ ex::set_error(ThrowingReceiver{}, 0);
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_stopped must be noexcept}}
+ ex::set_stopped(ThrowingReceiver{});
+
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_value must return void}}
+ ex::set_value(NonVoidReceiver{});
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_error must return void}}
+ ex::set_error(NonVoidReceiver{}, 0);
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_stopped must return void}}
+ ex::set_stopped(NonVoidReceiver{});
+
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_value must be noexcept}}
+ ex::set_value(ConversionReceiver{}, ThrowingConversion{});
+ // expected-error-re@*:* {{static assertion failed{{.*}}set_error must be noexcept}}
+ ex::set_error(ConversionReceiver{}, ThrowingConversion{});
+}
diff --git a/libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp b/libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp
new file mode 100644
index 0000000000000..f6cbb51b728ec
--- /dev/null
+++ b/libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+// UNSUPPORTED: libcpp-has-no-experimental-execution
+
+// [exec.set.value], [exec.set.error], [exec.set.stopped]
+
+#include <execution>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+namespace ex = std::execution;
+
+static_assert(std::is_same_v<decltype(ex::set_value), const ex::set_value_t>);
+static_assert(std::is_same_v<decltype(ex::set_error), const ex::set_error_t>);
+static_assert(std::is_same_v<decltype(ex::set_stopped), const ex::set_stopped_t>);
+
+// Reject receivers that have no set_xxx members.
+struct NoMemberReceiver {};
+static_assert(!std::is_invocable_v<ex::set_value_t, NoMemberReceiver, int>);
+static_assert(!std::is_invocable_v<ex::set_error_t, NoMemberReceiver, int>);
+static_assert(!std::is_invocable_v<ex::set_stopped_t, NoMemberReceiver>);
+
+struct CvrefTestReceiver {
+ void set_value(int) const noexcept;
+ void set_error(int) const noexcept;
+ void set_stopped() const noexcept;
+};
+
+static_assert(std::is_nothrow_invocable_v<ex::set_value_t, CvrefTestReceiver, int>);
+static_assert(std::is_nothrow_invocable_v<ex::set_error_t, CvrefTestReceiver, int>);
+static_assert(std::is_nothrow_invocable_v<ex::set_stopped_t, CvrefTestReceiver>);
+
+static_assert(!std::is_invocable_v<ex::set_value_t, CvrefTestReceiver&, int>);
+static_assert(!std::is_invocable_v<ex::set_error_t, CvrefTestReceiver&, int>);
+static_assert(!std::is_invocable_v<ex::set_stopped_t, CvrefTestReceiver&>);
+
+static_assert(!std::is_invocable_v<ex::set_value_t, const CvrefTestReceiver, int>);
+static_assert(!std::is_invocable_v<ex::set_error_t, const CvrefTestReceiver, int>);
+static_assert(!std::is_invocable_v<ex::set_stopped_t, const CvrefTestReceiver>);
+
+struct StaticReceiver {
+ static void set_value(int) noexcept;
+ static void set_error(int) noexcept;
+ static void set_stopped() noexcept;
+};
+
+static_assert(std::is_nothrow_invocable_v<ex::set_value_t, StaticReceiver, int>);
+static_assert(std::is_nothrow_invocable_v<ex::set_error_t, StaticReceiver, int>);
+static_assert(std::is_nothrow_invocable_v<ex::set_stopped_t, StaticReceiver>);
+
+struct RvalueReceiver {
+ int& result;
+
+ constexpr void set_value() && noexcept { result = 0; }
+ constexpr void set_value(int value) && noexcept { result = value; }
+ constexpr void set_value(int& output, int&& value) && noexcept {
+ output = value;
+ result = value;
+ }
+ constexpr void set_error(int& error) && noexcept { result = error; }
+ constexpr void set_error(int&& error) && noexcept { result = error; }
+ constexpr void set_stopped() && noexcept { result = 0; }
+};
+
+// This receiver accepts at most two values, one error, and no stopped arguments.
+static_assert(!std::is_invocable_v<ex::set_value_t, RvalueReceiver, int, int, int>);
+static_assert(!std::is_invocable_v<ex::set_error_t, RvalueReceiver>);
+static_assert(!std::is_invocable_v<ex::set_error_t, RvalueReceiver, int, int>);
+static_assert(!std::is_invocable_v<ex::set_stopped_t, RvalueReceiver, int>);
+
+constexpr bool test() {
+ int result = -1;
+ RvalueReceiver receiver{result};
+ ex::set_value(std::move(receiver));
+ assert(result == 0);
+
+ result = -1;
+ ex::set_value(RvalueReceiver{result}, 42);
+ assert(result == 42);
+
+ // Forward multiple arguments, preserving lvalue and rvalue references.
+ int output = 0;
+ result = -1;
+ ex::set_value(RvalueReceiver{result}, output, 42);
+ assert(output == 42);
+ assert(result == 42);
+
+ result = -1;
+ ex::set_error(RvalueReceiver{result}, 42);
+ assert(result == 42);
+
+ int error = 42;
+ result = -1;
+ ex::set_error(RvalueReceiver{result}, error);
+ assert(result == 42);
+
+ result = -1;
+ ex::set_stopped(RvalueReceiver{result});
+ assert(result == 0);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index 951b0a4dd9806..9795121c1c18d 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -366,6 +366,7 @@ def getSuitableClangTidy(cfg):
if experimental
else [
AddFeature("libcpp-has-no-incomplete-pstl"),
+ AddFeature("libcpp-has-no-experimental-execution"),
AddFeature("libcpp-has-no-experimental-optional-iterator"),
AddFeature("libcpp-has-no-experimental-tzdb"),
AddFeature("libcpp-has-no-experimental-syncstream"),
>From c2213d10278fa67a948ed69e8b2ea01a0c59332b Mon Sep 17 00:00:00 2001
From: Emmett <emmettzhang2020 at outlook.com>
Date: Tue, 6 Oct 2026 12:50:11 +0800
Subject: [PATCH 2/2] fix some review comments
---
libcxx/include/execution | 15 ++++----
.../exec.recv/completion_functions.verify.cpp | 35 +++++++++++++++++
.../exec.recv/completion_functions.pass.cpp | 38 +++++++++++++++++--
3 files changed, 77 insertions(+), 11 deletions(-)
diff --git a/libcxx/include/execution b/libcxx/include/execution
index 9e18989b5b0a1..ef960f7cfe827 100644
--- a/libcxx/include/execution
+++ b/libcxx/include/execution
@@ -22,14 +22,13 @@ namespace std::execution {
inline constexpr parallel_unsequenced_policy par_unseq = implementation-defined;
inline constexpr unsequenced_policy unseq = implementation-defined; // since C++20
- // completion functions, since C++26
- struct set_value_t;
- struct set_error_t;
- struct set_stopped_t;
-
- inline constexpr set_value_t set_value{};
- inline constexpr set_error_t set_error{};
- inline constexpr set_stopped_t set_stopped{};
+ struct set_value_t; // Since C++26
+ struct set_error_t; // Since C++26
+ struct set_stopped_t; // Since C++26
+
+ inline constexpr set_value_t set_value{}; // Since C++26
+ inline constexpr set_error_t set_error{}; // Since C++26
+ inline constexpr set_stopped_t set_stopped{}; // Since C++26
}
namespace std {
diff --git a/libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp b/libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp
index 7ad34c3db9f15..567b63e26710f 100644
--- a/libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp
+++ b/libcxx/test/libcxx/exec/exec.recv/completion_functions.verify.cpp
@@ -9,6 +9,41 @@
// REQUIRES: std-at-least-c++26
// UNSUPPORTED: libcpp-has-no-experimental-execution
+// <execution>
+//
+// namespace std::execution {
+// struct set_value_t {
+// template<class Receiver, class... Args>
+// requires (!is_lvalue_reference_v<Receiver> && !is_const_v<Receiver>) &&
+// requires(Receiver&& rcvr, Args&&... args) {
+// std::forward<Receiver>(rcvr).set_value(std::forward<Args>(args)...);
+// }
+// constexpr void operator()(Receiver&& rcvr, Args&&... args) const noexcept;
+// };
+//
+// struct set_error_t {
+// template<class Receiver, class Error>
+// requires (!is_lvalue_reference_v<Receiver> && !is_const_v<Receiver>) &&
+// requires(Receiver&& rcvr, Error&& error) {
+// std::forward<Receiver>(rcvr).set_error(std::forward<Error>(error));
+// }
+// constexpr void operator()(Receiver&& rcvr, Error&& error) const noexcept;
+// };
+//
+// struct set_stopped_t {
+// template<class Receiver>
+// requires (!is_lvalue_reference_v<Receiver> && !is_const_v<Receiver>) &&
+// requires(Receiver&& rcvr) {
+// std::forward<Receiver>(rcvr).set_stopped();
+// }
+// constexpr void operator()(Receiver&& rcvr) const noexcept;
+// };
+//
+// inline constexpr set_value_t set_value{};
+// inline constexpr set_error_t set_error{};
+// inline constexpr set_stopped_t set_stopped{};
+// }
+
// The noexcept and void-return requirements are mandates, not constraints.
#include <execution>
diff --git a/libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp b/libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp
index f6cbb51b728ec..a66d6a6521a7b 100644
--- a/libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp
+++ b/libcxx/test/std/exec/exec.recv/completion_functions.pass.cpp
@@ -9,11 +9,43 @@
// REQUIRES: std-at-least-c++26
// UNSUPPORTED: libcpp-has-no-experimental-execution
-// [exec.set.value], [exec.set.error], [exec.set.stopped]
-
-#include <execution>
+// <execution>
+//
+// namespace std::execution {
+// struct set_value_t {
+// template<class Receiver, class... Args>
+// requires (!is_lvalue_reference_v<Receiver> && !is_const_v<Receiver>) &&
+// requires(Receiver&& rcvr, Args&&... args) {
+// std::forward<Receiver>(rcvr).set_value(std::forward<Args>(args)...);
+// }
+// constexpr void operator()(Receiver&& rcvr, Args&&... args) const noexcept;
+// };
+//
+// struct set_error_t {
+// template<class Receiver, class Error>
+// requires (!is_lvalue_reference_v<Receiver> && !is_const_v<Receiver>) &&
+// requires(Receiver&& rcvr, Error&& error) {
+// std::forward<Receiver>(rcvr).set_error(std::forward<Error>(error));
+// }
+// constexpr void operator()(Receiver&& rcvr, Error&& error) const noexcept;
+// };
+//
+// struct set_stopped_t {
+// template<class Receiver>
+// requires (!is_lvalue_reference_v<Receiver> && !is_const_v<Receiver>) &&
+// requires(Receiver&& rcvr) {
+// std::forward<Receiver>(rcvr).set_stopped();
+// }
+// constexpr void operator()(Receiver&& rcvr) const noexcept;
+// };
+//
+// inline constexpr set_value_t set_value{};
+// inline constexpr set_error_t set_error{};
+// inline constexpr set_stopped_t set_stopped{};
+// }
#include <cassert>
+#include <execution>
#include <type_traits>
#include <utility>
More information about the libcxx-commits
mailing list