Skip to content

Commit dc95ead

Browse files
committed
Add operator co_await to psyqo::Coroutine
Transfers the coroutine handle to a separate ChainAwaiter that GCC reliably promotes to the coroutine frame, working around known temporary lifetime bugs in GCC 10-15+. Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
1 parent 4466451 commit dc95ead

1 file changed

Lines changed: 33 additions & 11 deletions

File tree

src/mips/psyqo/coroutine.hh

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -232,18 +232,40 @@ struct Coroutine {
232232
public:
233233
using promise_type = Promise;
234234

235-
constexpr bool await_ready() { return m_handle.done(); }
236-
template <typename U>
237-
constexpr void await_suspend(std::coroutine_handle<U> h) {
238-
m_handle.promise().m_awaitingCoroutine = h;
239-
resume();
240-
}
241-
constexpr T await_resume() {
242-
if constexpr (std::is_void<T>::value) {
243-
return;
244-
} else {
245-
return eastl::move(m_handle.promise().m_value);
235+
/**
236+
* @brief The awaiter type for coroutine-to-coroutine chaining via co_await.
237+
*
238+
* @details GCC has known bugs across versions 10-15+ where the awaitable temporary
239+
* in a `co_await` expression is not correctly promoted to the coroutine frame.
240+
* By using `operator co_await()`, we transfer the coroutine handle to this
241+
* awaiter object that GCC's coroutine pass reliably stores in the frame.
242+
*/
243+
struct ChainAwaiter {
244+
std::coroutine_handle<Promise> handle;
245+
246+
constexpr bool await_ready() { return handle.done(); }
247+
248+
void await_suspend(std::coroutine_handle<> h) {
249+
handle.promise().m_awaitingCoroutine = h;
250+
if (!handle.done()) handle.resume();
246251
}
252+
253+
constexpr T await_resume() {
254+
if constexpr (std::is_void<T>::value) {
255+
handle.destroy();
256+
return;
257+
} else {
258+
auto val = eastl::move(handle.promise().m_value);
259+
handle.destroy();
260+
return val;
261+
}
262+
}
263+
};
264+
265+
ChainAwaiter operator co_await() && {
266+
auto h = m_handle;
267+
m_handle = nullptr;
268+
return ChainAwaiter{h};
247269
}
248270
};
249271

0 commit comments

Comments
 (0)