From 4022b8a66071e1b95dd0f4cb9442b4dc194a9fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dietmar=20K=C3=BChl?= Date: Tue, 2 Sep 2025 19:29:45 +0200 Subject: [PATCH] add resolution for LWG4339: task's coroutine frame may be released late --- xml/issue4339.xml | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/xml/issue4339.xml b/xml/issue4339.xml index e3a78420c1..b7b8887fb0 100644 --- a/xml/issue4339.xml +++ b/xml/issue4339.xml @@ -44,6 +44,78 @@ Thus, the variant can be replaced with an

+In , add +exposition-only data members result and +error to the exposition-only class +state: +

+
+namespace std::execution {
+  template<class T, class Environment>
+  template<receiver Rcvr>
+  class task<T, Environment>::state {           // exposition only
+  ...
+  Environment               environment;   // exposition only
+  optional<T>               result;        // exposition only; present only if is_void_v<T> is false
+  exception_ptr             error;         // exposition-only
+};
+}
+
+
+

+

+Remove the exposition-only data members +result and errors from +the class promise_type in +: +

+
+namespace std::execution {
+  template<class T, class Environment>
+  class task<T, Environment>::promise_type {
+  ...
+  stop_token_type   token;  // exposition only
+  optional<T>       result; // exposition only; present only if is_void_v<T> is false
+  error-variant     errors; // exposition only
+};
+}
+
+
+

+

+The definition of error-variant isn't needed, i.e., remove paragraph 2: +

+

+-2- error-variant is a variant<monostate, remove_cvref_t<E>...>, with duplicate types removed, where E... are template arguments of the specialization of execution::completion_signatures denoted by error_types. +

+
+

+

+In change paragraph 7 to use the members added to state: +

+
auto final_suspend() noexcept
+

-7- Returns: An awaitable object of unspecified type () whose member functions arrange for the completion of the asynchronous operation associated with STATE(*this) by invoking. Let st be a reference to STATE(*this). The asynchronous completion first destroys the coroutine frame using st.handle.destroy() and then invokes:

+ +
    +
  • -7.1- set_error(std::move(RCVR(*this)st.rcvr), std::move(est.error)) if errors.index() is greater than zero and e is the value held by errorsbool(st.error) is true, otherwise
  • +
  • -7.2- set_value(std::move(RCVR(*this)st.rcvr)) if is_void<T> is true, and otherwise
  • +
  • -7.3- set_value(std::move(RCVR(*this)st.rcvr), *st.result).
  • +
+
+

+

+Change the specification of yield_value to destroy the coroutine frame before invoking the set_error completion, i.e., change paragraph 9: +

+

-9- Returns: An awaitable object of unspecified type ([expr.await]) whose member functions arrange for the calling coroutine to be suspended and then completes the asynchronous operation associated with STATE(*this) by. Let st be a reference to STATE(*this). Then the asynchronous operation completes by first destroying the coroutine frame using st.handle.destroy() and then invoking set_error(std::move(RCVR(*this)st.rcvr), Cerr(std::move(err.error))). +

+
+

+

+Change the specification of unhandled_stopped to destroy the coroutine frame before invoking the set_stopped completion, i.e., change paragraph 13: +

+
coroutine_handle<> unhandled_stopped();
+

-13- Effects: Completes the asynchronous operation associated with STATE(*this) by. Let st be a reference to STATE(*this). The asynchronous operation is completed by first destroying the coroutine frame using st.handle.destroy() and then invoking set_stopped(std::move(RCVR(*this)st.rcvr)).

+