99namespace conduit ::mixin {
1010enum suspend : bool { always = true , never = false };
1111
12+ #if CONDUIT_USE_GCC_EXCEPTION_WORKAROUND
13+ namespace detail {
14+ using remuse_coro_t = void (*)();
15+ using destroy_coro_t = void (*)();
16+ struct frame_header_t {
17+ remuse_coro_t resume_coro;
18+ destroy_coro_t destroy_coro;
19+ };
20+ } // namespace detail
21+ template <bool suspend>
22+ struct InitialSuspend {
23+ // If CONDUIT_USE_GCC_EXCEPTION_WORKAROUND is defined, then we need to keep
24+ // track of this value in order to destroy the frame manually. This value is
25+ // recorded inside initial_suspend_t
26+ detail::destroy_coro_t destroy_coro = nullptr ;
27+
28+ struct initial_suspend_t {
29+ detail::destroy_coro_t & destroy_coro_ref;
30+
31+ inline constexpr bool await_ready () { return false ; }
32+ inline bool await_suspend (std::coroutine_handle<> h) {
33+ destroy_coro_ref =
34+ ((detail::frame_header_t *)h.address ())->destroy_coro ;
35+ return suspend; // The coroutine is resumed if suspend is false
36+ }
37+ inline constexpr void await_resume () noexcept {}
38+ };
39+
40+ inline constexpr auto initial_suspend () noexcept {
41+ return initial_suspend_t {destroy_coro};
42+ }
43+ };
44+ #else
1245template <bool suspend>
1346struct InitialSuspend {
1447 inline constexpr auto initial_suspend () noexcept {
@@ -19,6 +52,7 @@ struct InitialSuspend {
1952 }
2053 }
2154};
55+ #endif
2256template <bool suspend>
2357struct FinalSuspend {
2458 inline constexpr auto final_suspend () noexcept {
@@ -32,13 +66,25 @@ struct FinalSuspend {
3266struct ReturnVoid {
3367 inline constexpr void return_void () noexcept {}
3468};
35- template <bool IsNoexcept = true >
69+
70+ template <class DerivedPromise >
3671struct UnhandledException {
37- [[noreturn]] void unhandled_exception () noexcept { std::terminate (); }
38- };
39- template <>
40- struct UnhandledException <false > {
41- void unhandled_exception () noexcept {}
72+ void unhandled_exception () {
73+ // NB: for some reason, GCC doesn't destroy the coroutine frame if
74+ // there's an exception raised inside the coroutine. As a result, if
75+ // we're on GCC, we need to destroy it manually.
76+
77+ #ifdef CONDUIT_USE_GCC_EXCEPTION_WORKAROUND
78+ DerivedPromise& promise = static_cast <DerivedPromise&>(*this );
79+ auto coro_frame = static_cast <detail::frame_header_t *>(
80+ std::coroutine_handle<DerivedPromise>::from_promise (promise)
81+ .address ());
82+ coro_frame->destroy_coro = promise.destroy_coro ;
83+ std::coroutine_handle<>::from_address (coro_frame).destroy ();
84+ #endif
85+
86+ std::rethrow_exception (std::current_exception ());
87+ }
4288};
4389template <class Promise , bool IsNoexcept = true >
4490struct GetReturnObject ;
0 commit comments