1616
1717#pragma once
1818
19- #include < folly/Utility.h>
2019#include < folly/coro/Coroutine.h> // delete with clang-15 support
2120#include < folly/result/result.h>
2221
@@ -31,15 +30,13 @@ template <typename>
3130struct result_promise_base ;
3231
3332template <typename T>
34- class result_promise_return {
35- private:
36- result<T> storage_{typename result<T>::has_value_sigil_t {}};
37- result<T>*& ptr_;
33+ struct result_promise_return {
34+ result<T> storage_{expected_detail::EmptyTag{}};
35+ result<T>*& pointer_;
3836
39- public:
4037 /* implicit */ result_promise_return(result_promise_base<T>& p) noexcept
41- : ptr_ {p.value_ } {
42- ptr_ = &storage_;
38+ : pointer_ {p.value_ } {
39+ pointer_ = &storage_;
4340 }
4441 result_promise_return (result_promise_return const &) = delete ;
4542 void operator =(result_promise_return const &) = delete ;
@@ -52,15 +49,14 @@ class result_promise_return {
5249 /* implicit */ operator result<T>() {
5350 // Simplify this once clang 15 is well-forgotten, and remove the dep on
5451 // `Coroutine.h`. From D42260201: handle both deferred and eager
55- // return-object conversion behaviors; see docs for
52+ // return-object conversion behaviors see docs for
5653 // detect_promise_return_object_eager_conversion
57- //
58- // Storage is in "has value" sigil state with uninitialized `value_`;
59- // `return_value` / `unhandled_exception` will initialize it.
60- if (coro::detect_promise_return_object_eager_conversion ()) { // eager
61- return result<T>{typename result<T>::has_value_sigil_t {}, ptr_};
62- } else { // deferred
63- return std::move (storage_);
54+ if (coro::detect_promise_return_object_eager_conversion ()) {
55+ assert (storage_.is_expected_empty ());
56+ return result<T>{expected_detail::EmptyTag{}, pointer_}; // eager
57+ } else {
58+ assert (!storage_.is_expected_empty ());
59+ return std::move (storage_); // deferred
6460 }
6561 }
6662};
@@ -79,9 +75,7 @@ struct result_promise_base {
7975 std::suspend_never initial_suspend () const noexcept { return {}; }
8076 std::suspend_never final_suspend () const noexcept { return {}; }
8177 void unhandled_exception () noexcept {
82- // Directly set `eos_` -- using `result` assignment would try to destroy
83- // uninitialized `value_` (UB since we start in "has value" sigil state).
84- value_->eos_ = error_or_stopped::from_current_exception ();
78+ *value_ = result<T>{error_or_stopped::from_current_exception ()};
8579 }
8680
8781 result_promise_return<T> get_return_object () noexcept { return *this ; }
@@ -96,35 +90,17 @@ struct result_promise<T, typename std::enable_if<!std::is_void_v<T>>::type>
9690 // The default for `U` is tested in `returnImplicitCtor`.
9791 template <typename U = T>
9892 void return_value (U&& u) {
99- // We're in "has value" sigil state with uninitialized `value_`. Use
100- // placement `new` -- NEVER assignment, which would call `operator=(T&)` on
101- // garbage (UB!). This supports non-default-constructible `T`, helps perf.
10293 auto & v = *this ->value_ ;
103- if constexpr (std::is_same_v<std::remove_cvref_t <U>, error_or_stopped>) {
104- v.eos_ = static_cast <U&&>(u);
105- } else if constexpr (std::is_same_v<std::remove_cvref_t <U>, result<T>>) {
106- // Returning `result<T>` (with `T` matching ours) acts like `or_unwind()`:
107- if (static_cast <U&&>(u).has_value ()) {
108- return_value (static_cast <U&&>(u).value_or_throw ());
109- } else {
110- // NOLINTNEXTLINE(facebook-hte-MissingStdForward): false positive
111- return_value (forward_like<U>(u.eos_ ));
112- }
113- } else {
114- // Returning a value; `eos_` already says "has value"
115- new (&v.value_ )
116- typename std::remove_reference_t <decltype (v)>::storage_type (
117- static_cast <U&&>(u));
118- }
94+ expected_detail::ExpectedHelper::assume_empty (v.exp_ );
95+ v = static_cast <U&&>(u);
11996 }
12097};
12198
12299template <typename T>
123100struct result_promise <T, typename std::enable_if<std::is_void_v<T>>::type>
124101 : public result_promise_base<T> {
125102 // You can fail via `co_await err` since void coros only allow `co_return;`.
126- // NB: `has_value_sigil_t` sets `eos_` to "has value", nothing to do.
127- void return_void () {}
103+ void return_void () { this ->value_ ->exp_ .emplace (unit); }
128104};
129105
130106template <typename T> // Need an alias since nested types cannot be deduced.
0 commit comments