The curious case of the coroutine that couldn't be killed

Coroutines are a C++20 feature I've fallen in love with recently, especially in the context of asynchronous programming. They certainly take a lot of boilerplate to initially set up, but once you've got that working, async code can be written in a style that looks very similar to synchronous blocking code, making it easier to read and reason about. It's not a perfect honeymoon though, there are some hidden gotchas that can ruin your day, but they can be worked around. People are often surprised at how coroutines and lambdas interact for example, but that's really the only outcome that makes sense given lambdas can be invoked multiple times.

Today though we're going to look at how coroutines and C++ exceptions interact, and what that means for our behind-the-scenes code. Let's start with this basic minimal template, which we'll be making repeated changes to throughout this post:

#include <array>
#include <cassert>
#include <coroutine>
#include <cstdint>
#include <exception>
#include <initializer_list>
#include <new>
#include <print>
#include <stdexcept>
#include <utility>
//simple class to help us track object lifetimes with debug output
template<auto Label>
struct LifetimeDebugger
{
std::uintptr_t addr() const
{
return reinterpret_cast<std::uintptr_t>(this);
}
char const* name() const
{
return Label[0];
}
LifetimeDebugger()
{
std::println(stderr, "[{:016x}] construct `{}` default", addr(), name());
}
LifetimeDebugger(LifetimeDebugger const& l)
{
std::println(stderr, "[{:016x}] construct `{}` from [{:016x}] by copy", addr(), name(), l.addr());
}
LifetimeDebugger& operator=(LifetimeDebugger const& l)
{
std::println(stderr, "[{:016x}] operator= `{}` from [{:016x}] by copy", addr(), name(), l.addr());
return *this;
}
LifetimeDebugger(LifetimeDebugger&& l)
{
std::println(stderr, "[{:016x}] construct `{}` from [{:016x}] by move", addr(), name(), l.addr());
}
LifetimeDebugger& operator=(LifetimeDebugger&& l)
{
std::println(stderr, "[{:016x}] operator= `{}` from [{:016x}] by move", addr(), name(), l.addr());
return *this;
}
~LifetimeDebugger()
{
std::println(stderr, "[{:016x}] ~destruct `{}`", addr(), name());
}
};
#if defined(_MSC_VER) && !defined(__clang__)
#define DEBUG_LIFETIME(name) LifetimeDebugger<std::array{#name}> debugLifetime##name
#else
#define DEBUG_LIFETIME(name) struct Label_##name { char const* operator[](int) const { return #name; } }; LifetimeDebugger<Label_##name{}> debugLifetime_##name
#endif
DEBUG_LIFETIME(global);
//surprise tool to help us later - no peeking!
struct ThrowOnDestruct
{
~ThrowOnDestruct() noexcept(false)
{
std::println(stderr, "~ThrowOnDestruct, uncaught_exceptions = {}", std::uncaught_exceptions());
if(std::uncaught_exceptions() <= 0)
{
throw std::runtime_error("ThrowOnDestruct");
}
}
};
//we'll use these for testing different combinations
enum struct Operation
: char
{
Return = 'R', //coroutine uses co_return
Await = 'A', //coroutine uses co_await
Throw = 'T', //coroutine throws an exception
};
enum struct AwaitBehavior
: char
{
AwaitReadyTrue = 'R', //await_ready returns true, await_suspend is never called, await_resume is called immediately
AwaitSuspendTrue = 'S', //await_ready returns false, await_suspend returns true, coroutine is suspended and await_resume is called only if it is resumed
AwaitSuspendFalse = 'U', //await_ready returns false, await_suspend returns false, await_resume is called immediately
};
//these are made global only for test convenience/simplicity, in practice they can be passed as parameters and stored locally
AwaitBehavior initialSuspendBehavior;
AwaitBehavior middleSuspendBehavior;
AwaitBehavior finalSuspendBehavior;
//a single test pass
struct TestCase
{
Operation o;
AwaitBehavior i, m, f;
};
//edit this function to suppress tests of disinterest
template<typename... Cases>
consteval std::size_t buildTestCasesImpl(Cases&... cases)
{
using enum Operation;
using enum AwaitBehavior;
std::size_t index{};
for(Operation const o : {Return, Await, Throw})
{
for(AwaitBehavior const i : {AwaitReadyTrue, AwaitSuspendTrue, AwaitSuspendFalse})
{
for(AwaitBehavior const m : {AwaitReadyTrue, AwaitSuspendTrue, AwaitSuspendFalse})
{
for(AwaitBehavior const f : {AwaitReadyTrue, AwaitSuspendTrue, AwaitSuspendFalse})
{
((cases[index] = {o, i, m, f}), ...);
++index;
}
}
}
}
return index;
}
constexpr std::size_t NUM_TEST_CASES{buildTestCasesImpl()};
consteval auto buildTestCases()
{
std::array<TestCase, NUM_TEST_CASES> cases;
buildTestCasesImpl(cases);
return cases;
}
constexpr auto TEST_CASES{buildTestCases()};
struct Task
{
struct promise_type
{
DEBUG_LIFETIME(promise_type);
void* operator new(std::size_t s)
{
std::println(stderr, "operator new({})", s);
return ::operator new(s);
}
void operator delete(void* p)
{
std::println(stderr, "operator delete");
return ::operator delete(p);
}
Task get_return_object()
{
std::println(stderr, "get_return_object");
return {std::coroutine_handle<promise_type>::from_promise(*this)};
}
using enum AwaitBehavior;
struct InitialSuspend
{
DEBUG_LIFETIME(InitialSuspend);
bool await_ready()
{
std::println(stderr, "InitialSuspend::await_ready");
return initialSuspendBehavior == AwaitReadyTrue;
}
bool await_suspend(std::coroutine_handle<promise_type>)
{
std::println(stderr, "InitialSuspend::await_suspend");
return initialSuspendBehavior == AwaitSuspendTrue;
}
void await_resume()
{
std::println(stderr, "InitialSuspend::await_resume");
}
};
struct MiddleSuspend
{
DEBUG_LIFETIME(MiddleSuspend);
bool await_ready()
{
std::println(stderr, "MiddleSuspend::await_ready");
return middleSuspendBehavior == AwaitReadyTrue;
}
bool await_suspend(std::coroutine_handle<promise_type>)
{
std::println(stderr, "MiddleSuspend::await_suspend");
return middleSuspendBehavior == AwaitSuspendTrue;
}
void await_resume()
{
std::println(stderr, "MiddleSuspend::await_resume");
}
};
struct FinalSuspend
{
DEBUG_LIFETIME(FinalSuspend);
bool await_ready() noexcept
{
std::println(stderr, "FinalSuspend::await_ready");
return finalSuspendBehavior == AwaitReadyTrue;
}
bool await_suspend(std::coroutine_handle<promise_type>) noexcept
{
std::println(stderr, "FinalSuspend::await_suspend");
return finalSuspendBehavior == AwaitSuspendTrue;
}
void await_resume() noexcept
{
std::println(stderr, "FinalSuspend::await_resume");
}
};
InitialSuspend initial_suspend()
{
std::println(stderr, "initial_suspend");
return {};
}
FinalSuspend final_suspend() noexcept
{
std::println(stderr, "final_suspend");
return {};
}
void return_void()
{
std::println(stderr, "return_void");
}
void unhandled_exception()
{
std::println(stderr, "unhandled_exception");
try
{
std::rethrow_exception(std::current_exception());
}
catch(std::exception const& e)
{
std::println(stderr, "\texception: {}", e.what());
}
catch(...)
{
std::println(stderr, "\tunknown exception");
}
}
MiddleSuspend await_transform(std::suspend_always)
{
std::println(stderr, "await_transform");
return {};
}
};
std::coroutine_handle<promise_type> h;
DEBUG_LIFETIME(Task);
};
//this is our one and only coroutine
Task makeTask(Operation const o)
{
DEBUG_LIFETIME(coroutine_local);
try
{
DEBUG_LIFETIME(coroutine_try);
switch(o)
{
case Operation::Return: co_return;
case Operation::Await : co_await std::suspend_always{}; break;
case Operation::Throw : throw std::runtime_error("coroutine throw");
}
std::println(stderr, "coroutine try end");
}
catch(...)
{
std::println(stderr, "coroutine catch");
throw;
}
std::println(stderr, "coroutine function end");
}
int main()
{
DEBUG_LIFETIME(main);
std::println(stderr, "main start\n");
using enum Operation;
using enum AwaitBehavior;
for(auto const [o, i, m, f] : TEST_CASES)
{
std::println(stderr, "main test start {}|{}{}{}", std::to_underlying(o), std::to_underlying(i), std::to_underlying(m), std::to_underlying(f));
/**/ initialSuspendBehavior = i;
/***/ middleSuspendBehavior = m;
/****/ finalSuspendBehavior = f;
try
{
Task t(makeTask(o));
std::println(stderr, "main after makeTask");
if(i == AwaitSuspendTrue)
{ //coroutine suspended at start
std::println(stderr, "main resume");
t.h.resume();
}
if((o == Await && m == AwaitSuspendTrue) || f == AwaitSuspendTrue)
{ //coroutine suspended after start
std::println(stderr, "main destroy");
t.h.destroy();
}
}
catch(std::exception const& e)
{
std::println(stderr, "main exception: {}", e.what());
}
catch(...)
{
std::println(stderr, "main unknown exception");
}
std::println(stderr, "main test end {}|{}{}{}\n", std::to_underlying(o), std::to_underlying(i), std::to_underlying(m), std::to_underlying(f));
}
std::println(stderr, "main end");
}

Nothing especially asynchronous happens in this code, since we're not focusing on things like synchronization today. We just output some debug messages using C++23's std::println to get a quick picture of the program flow when we run. Already though, we can see that we are required to mark some functions as noexcept in order for the code to be accepted by the compiler, because the standard says that the final_suspend operations must not be potentially-throwing. Everything else is apparently fair-game. Anyway, here's the output for our starting template:

Operation:
Initial suspend AwaitBehavior:
Middle suspend AwaitBehavior:
Final suspend AwaitBehavior:
[00007ff769fb7863] construct `global` default
[000000bf916fec74] construct `main` default
main start
main test start R|RRR
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|RRR
main test start R|RRS
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|RRS
main test start R|RRU
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|RRU
main test start R|RSR
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|RSR
main test start R|RSS
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|RSS
main test start R|RSU
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|RSU
main test start R|RUR
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|RUR
main test start R|RUS
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|RUS
main test start R|RUU
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|RUU
main test start R|SRR
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SRR
main test start R|SRS
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SRS
main test start R|SRU
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SRU
main test start R|SSR
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SSR
main test start R|SSS
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SSS
main test start R|SSU
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SSU
main test start R|SUR
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SUR
main test start R|SUS
operator new(272)
[000002b53a242130] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a242131] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a242131] ~destruct `InitialSuspend`
[000002b53a242138] construct `coroutine_local` default
[000002b53a242139] construct `coroutine_try` default
return_void
[000002b53a242139] ~destruct `coroutine_try`
[000002b53a242138] ~destruct `coroutine_local`
final_suspend
[000002b53a242168] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a242168] ~destruct `FinalSuspend`
[000002b53a242130] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SUS
main test start R|SUU
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
return_void
[000002b53a2469e9] ~destruct `coroutine_try`
[000002b53a2469e8] ~destruct `coroutine_local`
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|SUU
main test start R|URR
operator new(272)
[000002b53a2465f0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2465f1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2465f1] ~destruct `InitialSuspend`
[000002b53a2465f8] construct `coroutine_local` default
[000002b53a2465f9] construct `coroutine_try` default
return_void
[000002b53a2465f9] ~destruct `coroutine_try`
[000002b53a2465f8] ~destruct `coroutine_local`
final_suspend
[000002b53a246628] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246628] ~destruct `FinalSuspend`
[000002b53a2465f0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|URR
main test start R|URS
operator new(272)
[000002b53a246890] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246891] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246891] ~destruct `InitialSuspend`
[000002b53a246898] construct `coroutine_local` default
[000002b53a246899] construct `coroutine_try` default
return_void
[000002b53a246899] ~destruct `coroutine_try`
[000002b53a246898] ~destruct `coroutine_local`
final_suspend
[000002b53a2468c8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a2468c8] ~destruct `FinalSuspend`
[000002b53a246890] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|URS
main test start R|URU
operator new(272)
[000002b53a246350] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246351] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246351] ~destruct `InitialSuspend`
[000002b53a246358] construct `coroutine_local` default
[000002b53a246359] construct `coroutine_try` default
return_void
[000002b53a246359] ~destruct `coroutine_try`
[000002b53a246358] ~destruct `coroutine_local`
final_suspend
[000002b53a246388] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246388] ~destruct `FinalSuspend`
[000002b53a246350] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|URU
main test start R|USR
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
return_void
[000002b53a2469e9] ~destruct `coroutine_try`
[000002b53a2469e8] ~destruct `coroutine_local`
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|USR
main test start R|USS
operator new(272)
[000002b53a246740] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246741] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246741] ~destruct `InitialSuspend`
[000002b53a246748] construct `coroutine_local` default
[000002b53a246749] construct `coroutine_try` default
return_void
[000002b53a246749] ~destruct `coroutine_try`
[000002b53a246748] ~destruct `coroutine_local`
final_suspend
[000002b53a246778] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246778] ~destruct `FinalSuspend`
[000002b53a246740] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|USS
main test start R|USU
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
return_void
[000002b53a2469e9] ~destruct `coroutine_try`
[000002b53a2469e8] ~destruct `coroutine_local`
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|USU
main test start R|UUR
operator new(272)
[000002b53a246dd0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246dd1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246dd1] ~destruct `InitialSuspend`
[000002b53a246dd8] construct `coroutine_local` default
[000002b53a246dd9] construct `coroutine_try` default
return_void
[000002b53a246dd9] ~destruct `coroutine_try`
[000002b53a246dd8] ~destruct `coroutine_local`
final_suspend
[000002b53a246e08] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246e08] ~destruct `FinalSuspend`
[000002b53a246dd0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|UUR
main test start R|UUS
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
return_void
[000002b53a2469e9] ~destruct `coroutine_try`
[000002b53a2469e8] ~destruct `coroutine_local`
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end R|UUS
main test start R|UUU
operator new(272)
[000002b53a2464a0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2464a1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2464a1] ~destruct `InitialSuspend`
[000002b53a2464a8] construct `coroutine_local` default
[000002b53a2464a9] construct `coroutine_try` default
return_void
[000002b53a2464a9] ~destruct `coroutine_try`
[000002b53a2464a8] ~destruct `coroutine_local`
final_suspend
[000002b53a2464d8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a2464d8] ~destruct `FinalSuspend`
[000002b53a2464a0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end R|UUU
main test start A|RRR
operator new(272)
[000002b53a246200] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246201] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246201] ~destruct `InitialSuspend`
[000002b53a246208] construct `coroutine_local` default
[000002b53a246209] construct `coroutine_try` default
await_transform
[000002b53a246219] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246219] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246209] ~destruct `coroutine_try`
coroutine function end
[000002b53a246208] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246238] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246238] ~destruct `FinalSuspend`
[000002b53a246200] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|RRR
main test start A|RRS
operator new(272)
[000002b53a246b30] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246b31] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246b31] ~destruct `InitialSuspend`
[000002b53a246b38] construct `coroutine_local` default
[000002b53a246b39] construct `coroutine_try` default
await_transform
[000002b53a246b49] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246b49] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246b39] ~destruct `coroutine_try`
coroutine function end
[000002b53a246b38] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246b68] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246b68] ~destruct `FinalSuspend`
[000002b53a246b30] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|RRS
main test start A|RRU
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
await_transform
[000002b53a246c99] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246c99] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246c89] ~destruct `coroutine_try`
coroutine function end
[000002b53a246c88] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|RRU
main test start A|RSR
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
await_transform
[000002b53a2469f9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002b53a2469f9] ~destruct `MiddleSuspend`
[000002b53a2469e9] ~destruct `coroutine_try`
[000002b53a2469e8] ~destruct `coroutine_local`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|RSR
main test start A|RSS
operator new(272)
[000002b53a246890] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246891] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246891] ~destruct `InitialSuspend`
[000002b53a246898] construct `coroutine_local` default
[000002b53a246899] construct `coroutine_try` default
await_transform
[000002b53a2468a9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002b53a2468a9] ~destruct `MiddleSuspend`
[000002b53a246899] ~destruct `coroutine_try`
[000002b53a246898] ~destruct `coroutine_local`
[000002b53a246890] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|RSS
main test start A|RSU
operator new(272)
[000002b53a246740] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246741] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246741] ~destruct `InitialSuspend`
[000002b53a246748] construct `coroutine_local` default
[000002b53a246749] construct `coroutine_try` default
await_transform
[000002b53a246759] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246759] ~destruct `MiddleSuspend`
[000002b53a246749] ~destruct `coroutine_try`
[000002b53a246748] ~destruct `coroutine_local`
[000002b53a246740] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|RSU
main test start A|RUR
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
await_transform
[000002b53a246c99] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a246c99] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246c89] ~destruct `coroutine_try`
coroutine function end
[000002b53a246c88] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|RUR
main test start A|RUS
operator new(272)
[000002b53a2465f0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2465f1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a2465f1] ~destruct `InitialSuspend`
[000002b53a2465f8] construct `coroutine_local` default
[000002b53a2465f9] construct `coroutine_try` default
await_transform
[000002b53a246609] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a246609] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a2465f9] ~destruct `coroutine_try`
coroutine function end
[000002b53a2465f8] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246628] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246628] ~destruct `FinalSuspend`
[000002b53a2465f0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|RUS
main test start A|RUU
operator new(272)
[000002b53a246350] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246351] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246351] ~destruct `InitialSuspend`
[000002b53a246358] construct `coroutine_local` default
[000002b53a246359] construct `coroutine_try` default
await_transform
[000002b53a246369] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a246369] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246359] ~destruct `coroutine_try`
coroutine function end
[000002b53a246358] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246388] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246388] ~destruct `FinalSuspend`
[000002b53a246350] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|RUU
main test start A|SRR
operator new(272)
[000002b53a246dd0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246dd1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246dd1] ~destruct `InitialSuspend`
[000002b53a246dd8] construct `coroutine_local` default
[000002b53a246dd9] construct `coroutine_try` default
await_transform
[000002b53a246de9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246de9] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246dd9] ~destruct `coroutine_try`
coroutine function end
[000002b53a246dd8] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246e08] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246e08] ~destruct `FinalSuspend`
[000002b53a246dd0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SRR
main test start A|SRS
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
await_transform
[000002b53a246c99] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246c99] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246c89] ~destruct `coroutine_try`
coroutine function end
[000002b53a246c88] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SRS
main test start A|SRU
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
await_transform
[000002b53a246c99] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246c99] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246c89] ~destruct `coroutine_try`
coroutine function end
[000002b53a246c88] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SRU
main test start A|SSR
operator new(272)
[000002b53a2465f0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2465f1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a2465f1] ~destruct `InitialSuspend`
[000002b53a2465f8] construct `coroutine_local` default
[000002b53a2465f9] construct `coroutine_try` default
await_transform
[000002b53a246609] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main destroy
[000002b53a246609] ~destruct `MiddleSuspend`
[000002b53a2465f9] ~destruct `coroutine_try`
[000002b53a2465f8] ~destruct `coroutine_local`
[000002b53a2465f0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SSR
main test start A|SSS
operator new(272)
[000002b53a246b30] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246b31] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246b31] ~destruct `InitialSuspend`
[000002b53a246b38] construct `coroutine_local` default
[000002b53a246b39] construct `coroutine_try` default
await_transform
[000002b53a246b49] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main destroy
[000002b53a246b49] ~destruct `MiddleSuspend`
[000002b53a246b39] ~destruct `coroutine_try`
[000002b53a246b38] ~destruct `coroutine_local`
[000002b53a246b30] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SSS
main test start A|SSU
operator new(272)
[000002b53a246350] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246351] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246351] ~destruct `InitialSuspend`
[000002b53a246358] construct `coroutine_local` default
[000002b53a246359] construct `coroutine_try` default
await_transform
[000002b53a246369] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main destroy
[000002b53a246369] ~destruct `MiddleSuspend`
[000002b53a246359] ~destruct `coroutine_try`
[000002b53a246358] ~destruct `coroutine_local`
[000002b53a246350] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SSU
main test start A|SUR
operator new(272)
[000002b53a246740] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246741] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246741] ~destruct `InitialSuspend`
[000002b53a246748] construct `coroutine_local` default
[000002b53a246749] construct `coroutine_try` default
await_transform
[000002b53a246759] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a246759] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246749] ~destruct `coroutine_try`
coroutine function end
[000002b53a246748] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246778] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246778] ~destruct `FinalSuspend`
[000002b53a246740] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SUR
main test start A|SUS
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
await_transform
[000002b53a2469f9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a2469f9] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a2469e9] ~destruct `coroutine_try`
coroutine function end
[000002b53a2469e8] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SUS
main test start A|SUU
operator new(272)
[000002b53a246200] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246201] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246201] ~destruct `InitialSuspend`
[000002b53a246208] construct `coroutine_local` default
[000002b53a246209] construct `coroutine_try` default
await_transform
[000002b53a246219] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a246219] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246209] ~destruct `coroutine_try`
coroutine function end
[000002b53a246208] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246238] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246238] ~destruct `FinalSuspend`
[000002b53a246200] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|SUU
main test start A|URR
operator new(272)
[000002b53a246350] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246351] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246351] ~destruct `InitialSuspend`
[000002b53a246358] construct `coroutine_local` default
[000002b53a246359] construct `coroutine_try` default
await_transform
[000002b53a246369] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246369] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246359] ~destruct `coroutine_try`
coroutine function end
[000002b53a246358] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246388] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246388] ~destruct `FinalSuspend`
[000002b53a246350] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|URR
main test start A|URS
operator new(272)
[000002b53a246b30] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246b31] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246b31] ~destruct `InitialSuspend`
[000002b53a246b38] construct `coroutine_local` default
[000002b53a246b39] construct `coroutine_try` default
await_transform
[000002b53a246b49] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a246b49] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246b39] ~destruct `coroutine_try`
coroutine function end
[000002b53a246b38] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a246b68] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246b68] ~destruct `FinalSuspend`
[000002b53a246b30] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|URS
main test start A|URU
operator new(272)
[000002b53a2460b0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2460b1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2460b1] ~destruct `InitialSuspend`
[000002b53a2460b8] construct `coroutine_local` default
[000002b53a2460b9] construct `coroutine_try` default
await_transform
[000002b53a2460c9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_resume
[000002b53a2460c9] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a2460b9] ~destruct `coroutine_try`
coroutine function end
[000002b53a2460b8] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a2460e8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a2460e8] ~destruct `FinalSuspend`
[000002b53a2460b0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|URU
main test start A|USR
operator new(272)
[000002b53a246200] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246201] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246201] ~destruct `InitialSuspend`
[000002b53a246208] construct `coroutine_local` default
[000002b53a246209] construct `coroutine_try` default
await_transform
[000002b53a246219] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246219] ~destruct `MiddleSuspend`
[000002b53a246209] ~destruct `coroutine_try`
[000002b53a246208] ~destruct `coroutine_local`
[000002b53a246200] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|USR
main test start A|USS
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
await_transform
[000002b53a246c99] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246c99] ~destruct `MiddleSuspend`
[000002b53a246c89] ~destruct `coroutine_try`
[000002b53a246c88] ~destruct `coroutine_local`
[000002b53a246c80] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|USS
main test start A|USU
operator new(272)
[000002b53a246b30] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246b31] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246b31] ~destruct `InitialSuspend`
[000002b53a246b38] construct `coroutine_local` default
[000002b53a246b39] construct `coroutine_try` default
await_transform
[000002b53a246b49] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246b49] ~destruct `MiddleSuspend`
[000002b53a246b39] ~destruct `coroutine_try`
[000002b53a246b38] ~destruct `coroutine_local`
[000002b53a246b30] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|USU
main test start A|UUR
operator new(272)
[000002b53a2460b0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2460b1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2460b1] ~destruct `InitialSuspend`
[000002b53a2460b8] construct `coroutine_local` default
[000002b53a2460b9] construct `coroutine_try` default
await_transform
[000002b53a2460c9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a2460c9] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a2460b9] ~destruct `coroutine_try`
coroutine function end
[000002b53a2460b8] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a2460e8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a2460e8] ~destruct `FinalSuspend`
[000002b53a2460b0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|UUR
main test start A|UUS
operator new(272)
[000002b53a246890] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246891] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246891] ~destruct `InitialSuspend`
[000002b53a246898] construct `coroutine_local` default
[000002b53a246899] construct `coroutine_try` default
await_transform
[000002b53a2468a9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a2468a9] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a246899] ~destruct `coroutine_try`
coroutine function end
[000002b53a246898] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a2468c8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a2468c8] ~destruct `FinalSuspend`
[000002b53a246890] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end A|UUS
main test start A|UUU
operator new(272)
[000002b53a2460b0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2460b1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2460b1] ~destruct `InitialSuspend`
[000002b53a2460b8] construct `coroutine_local` default
[000002b53a2460b9] construct `coroutine_try` default
await_transform
[000002b53a2460c9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
MiddleSuspend::await_resume
[000002b53a2460c9] ~destruct `MiddleSuspend`
coroutine try end
[000002b53a2460b9] ~destruct `coroutine_try`
coroutine function end
[000002b53a2460b8] ~destruct `coroutine_local`
return_void
final_suspend
[000002b53a2460e8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a2460e8] ~destruct `FinalSuspend`
[000002b53a2460b0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end A|UUU
main test start T|RRR
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
[000002b53a246c89] ~destruct `coroutine_try`
coroutine catch
[000002b53a246c88] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|RRR
main test start T|RRS
operator new(272)
[000002b53a246740] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246741] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246741] ~destruct `InitialSuspend`
[000002b53a246748] construct `coroutine_local` default
[000002b53a246749] construct `coroutine_try` default
[000002b53a246749] ~destruct `coroutine_try`
coroutine catch
[000002b53a246748] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246778] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246778] ~destruct `FinalSuspend`
[000002b53a246740] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|RRS
main test start T|RRU
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
[000002b53a2469e9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2469e8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|RRU
main test start T|RSR
operator new(272)
[000002b53a2464a0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2464a1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a2464a1] ~destruct `InitialSuspend`
[000002b53a2464a8] construct `coroutine_local` default
[000002b53a2464a9] construct `coroutine_try` default
[000002b53a2464a9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2464a8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a2464d8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a2464d8] ~destruct `FinalSuspend`
[000002b53a2464a0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|RSR
main test start T|RSS
operator new(272)
[000002b53a246200] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246201] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246201] ~destruct `InitialSuspend`
[000002b53a246208] construct `coroutine_local` default
[000002b53a246209] construct `coroutine_try` default
[000002b53a246209] ~destruct `coroutine_try`
coroutine catch
[000002b53a246208] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246238] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246238] ~destruct `FinalSuspend`
[000002b53a246200] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|RSS
main test start T|RSU
operator new(272)
[000002b53a2464a0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2464a1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a2464a1] ~destruct `InitialSuspend`
[000002b53a2464a8] construct `coroutine_local` default
[000002b53a2464a9] construct `coroutine_try` default
[000002b53a2464a9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2464a8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a2464d8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a2464d8] ~destruct `FinalSuspend`
[000002b53a2464a0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|RSU
main test start T|RUR
operator new(272)
[000002b53a246740] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246741] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a246741] ~destruct `InitialSuspend`
[000002b53a246748] construct `coroutine_local` default
[000002b53a246749] construct `coroutine_try` default
[000002b53a246749] ~destruct `coroutine_try`
coroutine catch
[000002b53a246748] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246778] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246778] ~destruct `FinalSuspend`
[000002b53a246740] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|RUR
main test start T|RUS
operator new(272)
[000002b53a2465f0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2465f1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a2465f1] ~destruct `InitialSuspend`
[000002b53a2465f8] construct `coroutine_local` default
[000002b53a2465f9] construct `coroutine_try` default
[000002b53a2465f9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2465f8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246628] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246628] ~destruct `FinalSuspend`
[000002b53a2465f0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|RUS
main test start T|RUU
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
[000002b53a2469e9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2469e8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|RUU
main test start T|SRR
operator new(272)
[000002b53a2464a0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2464a1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a2464a1] ~destruct `InitialSuspend`
[000002b53a2464a8] construct `coroutine_local` default
[000002b53a2464a9] construct `coroutine_try` default
[000002b53a2464a9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2464a8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a2464d8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a2464d8] ~destruct `FinalSuspend`
[000002b53a2464a0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SRR
main test start T|SRS
operator new(272)
[000002b53a246dd0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246dd1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246dd1] ~destruct `InitialSuspend`
[000002b53a246dd8] construct `coroutine_local` default
[000002b53a246dd9] construct `coroutine_try` default
[000002b53a246dd9] ~destruct `coroutine_try`
coroutine catch
[000002b53a246dd8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246e08] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a246e08] ~destruct `FinalSuspend`
[000002b53a246dd0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SRS
main test start T|SRU
operator new(272)
[000002b53a246350] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246351] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246351] ~destruct `InitialSuspend`
[000002b53a246358] construct `coroutine_local` default
[000002b53a246359] construct `coroutine_try` default
[000002b53a246359] ~destruct `coroutine_try`
coroutine catch
[000002b53a246358] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246388] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246388] ~destruct `FinalSuspend`
[000002b53a246350] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SRU
main test start T|SSR
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
[000002b53a246c89] ~destruct `coroutine_try`
coroutine catch
[000002b53a246c88] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SSR
main test start T|SSS
operator new(272)
[000002b53a246200] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246201] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246201] ~destruct `InitialSuspend`
[000002b53a246208] construct `coroutine_local` default
[000002b53a246209] construct `coroutine_try` default
[000002b53a246209] ~destruct `coroutine_try`
coroutine catch
[000002b53a246208] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246238] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a246238] ~destruct `FinalSuspend`
[000002b53a246200] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SSS
main test start T|SSU
operator new(272)
[000002b53a246890] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246891] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246891] ~destruct `InitialSuspend`
[000002b53a246898] construct `coroutine_local` default
[000002b53a246899] construct `coroutine_try` default
[000002b53a246899] ~destruct `coroutine_try`
coroutine catch
[000002b53a246898] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a2468c8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a2468c8] ~destruct `FinalSuspend`
[000002b53a246890] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SSU
main test start T|SUR
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
[000002b53a246c89] ~destruct `coroutine_try`
coroutine catch
[000002b53a246c88] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SUR
main test start T|SUS
operator new(272)
[000002b53a246890] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246891] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246891] ~destruct `InitialSuspend`
[000002b53a246898] construct `coroutine_local` default
[000002b53a246899] construct `coroutine_try` default
[000002b53a246899] ~destruct `coroutine_try`
coroutine catch
[000002b53a246898] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a2468c8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main destroy
[000002b53a2468c8] ~destruct `FinalSuspend`
[000002b53a246890] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SUS
main test start T|SUU
operator new(272)
[000002b53a246350] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246351] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002b53a246351] ~destruct `InitialSuspend`
[000002b53a246358] construct `coroutine_local` default
[000002b53a246359] construct `coroutine_try` default
[000002b53a246359] ~destruct `coroutine_try`
coroutine catch
[000002b53a246358] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246388] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246388] ~destruct `FinalSuspend`
[000002b53a246350] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|SUU
main test start T|URR
operator new(272)
[000002b53a246b30] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246b31] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246b31] ~destruct `InitialSuspend`
[000002b53a246b38] construct `coroutine_local` default
[000002b53a246b39] construct `coroutine_try` default
[000002b53a246b39] ~destruct `coroutine_try`
coroutine catch
[000002b53a246b38] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246b68] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246b68] ~destruct `FinalSuspend`
[000002b53a246b30] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|URR
main test start T|URS
operator new(272)
[000002b53a2464a0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2464a1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2464a1] ~destruct `InitialSuspend`
[000002b53a2464a8] construct `coroutine_local` default
[000002b53a2464a9] construct `coroutine_try` default
[000002b53a2464a9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2464a8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a2464d8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a2464d8] ~destruct `FinalSuspend`
[000002b53a2464a0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|URS
main test start T|URU
operator new(272)
[000002b53a246890] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246891] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246891] ~destruct `InitialSuspend`
[000002b53a246898] construct `coroutine_local` default
[000002b53a246899] construct `coroutine_try` default
[000002b53a246899] ~destruct `coroutine_try`
coroutine catch
[000002b53a246898] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a2468c8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a2468c8] ~destruct `FinalSuspend`
[000002b53a246890] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|URU
main test start T|USR
operator new(272)
[000002b53a246350] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246351] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246351] ~destruct `InitialSuspend`
[000002b53a246358] construct `coroutine_local` default
[000002b53a246359] construct `coroutine_try` default
[000002b53a246359] ~destruct `coroutine_try`
coroutine catch
[000002b53a246358] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246388] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246388] ~destruct `FinalSuspend`
[000002b53a246350] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|USR
main test start T|USS
operator new(272)
[000002b53a2469e0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2469e1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2469e1] ~destruct `InitialSuspend`
[000002b53a2469e8] construct `coroutine_local` default
[000002b53a2469e9] construct `coroutine_try` default
[000002b53a2469e9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2469e8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246a18] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246a18] ~destruct `FinalSuspend`
[000002b53a2469e0] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|USS
main test start T|USU
operator new(272)
[000002b53a246b30] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246b31] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246b31] ~destruct `InitialSuspend`
[000002b53a246b38] construct `coroutine_local` default
[000002b53a246b39] construct `coroutine_try` default
[000002b53a246b39] ~destruct `coroutine_try`
coroutine catch
[000002b53a246b38] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246b68] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246b68] ~destruct `FinalSuspend`
[000002b53a246b30] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|USU
main test start T|UUR
operator new(272)
[000002b53a246c80] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246c81] ~destruct `InitialSuspend`
[000002b53a246c88] construct `coroutine_local` default
[000002b53a246c89] construct `coroutine_try` default
[000002b53a246c89] ~destruct `coroutine_try`
coroutine catch
[000002b53a246c88] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000002b53a246cb8] ~destruct `FinalSuspend`
[000002b53a246c80] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|UUR
main test start T|UUS
operator new(272)
[000002b53a246200] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a246201] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a246201] ~destruct `InitialSuspend`
[000002b53a246208] construct `coroutine_local` default
[000002b53a246209] construct `coroutine_try` default
[000002b53a246209] ~destruct `coroutine_try`
coroutine catch
[000002b53a246208] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246238] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
main after makeTask
main destroy
[000002b53a246238] ~destruct `FinalSuspend`
[000002b53a246200] ~destruct `promise_type`
operator delete
[000000bf916fed20] ~destruct `Task`
main test end T|UUS
main test start T|UUU
operator new(272)
[000002b53a2465f0] construct `promise_type` default
get_return_object
[000000bf916fed20] construct `Task` default
initial_suspend
[000002b53a2465f1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002b53a2465f1] ~destruct `InitialSuspend`
[000002b53a2465f8] construct `coroutine_local` default
[000002b53a2465f9] construct `coroutine_try` default
[000002b53a2465f9] ~destruct `coroutine_try`
coroutine catch
[000002b53a2465f8] ~destruct `coroutine_local`
unhandled_exception
exception: coroutine throw
final_suspend
[000002b53a246628] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
FinalSuspend::await_resume
[000002b53a246628] ~destruct `FinalSuspend`
[000002b53a2465f0] ~destruct `promise_type`
operator delete
main after makeTask
[000000bf916fed20] ~destruct `Task`
main test end T|UUU
main end
[000000bf916fec74] ~destruct `main`
[00007ff769fb7863] ~destruct `global`

Nothing surprising here, the coroutine does what it's asked to do in each case and everything is cleaned up before the next pass. You can use your counting search feature to see that the text main test start appears 81 times, which makes sense for 34 test passes, and similarly both ~destruct `promise_type` and operator delete also appear 81 times each, so there's no leaks happening yet. The reason there are so many test passes is to account for each combination of the three Operations and the three AwaitBehaviors for each of the three points where an awaitable is used (initial suspend, middle suspend, and final suspend). Actually, some of these test passes are redundant, and there are some things we could also test that we aren't yet, but I leave those matters as an exercise for the reader to figure out. If you're only curious about the combinations that pertain to your use cases, feel free to edit the buildTestCasesImpl function to suppress the test cases you don't care about, and the output will shrink considerably. (You can also play with the checkboxes above the output if your browser supports the necessary CSS functionality.)

Anyway, let's start throwing exceptions! Well, actually the entire bottom third of the output is from throwing an exception from the coroutine body while not suspended, but that's ordinary. Let's start throwing exceptions from strange locations too. For starters, trying to throw from operator new doesn't yield any interesting results, it just gets caught in main as expected in all test cases. But things get interesting with operator delete - it's implicitly noexcept by default even though we didn't specify, so first we have to explicitly mark it as noexcept(false) to let the exception escape without calling std::terminate early:

Show full source Show source diff
}
void operator delete(void* p) noexcept(false)
{
std::println(stderr, "operator delete");
if(p)
{
throw std::runtime_error("operator delete");
}
return ::operator delete(p);
}
Task get_return_object()
{
#include <array>
#include <cassert>
#include <coroutine>
#include <cstdint>
#include <exception>
#include <initializer_list>
#include <new>
#include <print>
#include <stdexcept>
#include <utility>
//simple class to help us track object lifetimes with debug output
template<auto Label>
struct LifetimeDebugger
{
std::uintptr_t addr() const
{
return reinterpret_cast<std::uintptr_t>(this);
}
char const* name() const
{
return Label[0];
}
LifetimeDebugger()
{
std::println(stderr, "[{:016x}] construct `{}` default", addr(), name());
}
LifetimeDebugger(LifetimeDebugger const& l)
{
std::println(stderr, "[{:016x}] construct `{}` from [{:016x}] by copy", addr(), name(), l.addr());
}
LifetimeDebugger& operator=(LifetimeDebugger const& l)
{
std::println(stderr, "[{:016x}] operator= `{}` from [{:016x}] by copy", addr(), name(), l.addr());
return *this;
}
LifetimeDebugger(LifetimeDebugger&& l)
{
std::println(stderr, "[{:016x}] construct `{}` from [{:016x}] by move", addr(), name(), l.addr());
}
LifetimeDebugger& operator=(LifetimeDebugger&& l)
{
std::println(stderr, "[{:016x}] operator= `{}` from [{:016x}] by move", addr(), name(), l.addr());
return *this;
}
~LifetimeDebugger()
{
std::println(stderr, "[{:016x}] ~destruct `{}`", addr(), name());
}
};
#if defined(_MSC_VER) && !defined(__clang__)
#define DEBUG_LIFETIME(name) LifetimeDebugger<std::array{#name}> debugLifetime##name
#else
#define DEBUG_LIFETIME(name) struct Label_##name { char const* operator[](int) const { return #name; } }; LifetimeDebugger<Label_##name{}> debugLifetime_##name
#endif
DEBUG_LIFETIME(global);
//surprise tool to help us later - no peeking!
struct ThrowOnDestruct
{
~ThrowOnDestruct() noexcept(false)
{
std::println(stderr, "~ThrowOnDestruct, uncaught_exceptions = {}", std::uncaught_exceptions());
if(std::uncaught_exceptions() <= 0)
{
throw std::runtime_error("ThrowOnDestruct");
}
}
};
//we'll use these for testing different combinations
enum struct Operation
: char
{
Return = 'R', //coroutine uses co_return
Await = 'A', //coroutine uses co_await
Throw = 'T', //coroutine throws an exception
};
enum struct AwaitBehavior
: char
{
AwaitReadyTrue = 'R', //await_ready returns true, await_suspend is never called, await_resume is called immediately
AwaitSuspendTrue = 'S', //await_ready returns false, await_suspend returns true, coroutine is suspended and await_resume is called only if it is resumed
AwaitSuspendFalse = 'U', //await_ready returns false, await_suspend returns false, await_resume is called immediately
};
//these are made global only for test convenience/simplicity, in practice they can be passed as parameters and stored locally
AwaitBehavior initialSuspendBehavior;
AwaitBehavior middleSuspendBehavior;
AwaitBehavior finalSuspendBehavior;
//a single test pass
struct TestCase
{
Operation o;
AwaitBehavior i, m, f;
};
//edit this function to suppress tests of disinterest
template<typename... Cases>
consteval std::size_t buildTestCasesImpl(Cases&... cases)
{
using enum Operation;
using enum AwaitBehavior;
std::size_t index{};
for(Operation const o : {Return, Await, Throw})
{
for(AwaitBehavior const i : {AwaitReadyTrue, AwaitSuspendTrue, AwaitSuspendFalse})
{
for(AwaitBehavior const m : {AwaitReadyTrue, AwaitSuspendTrue, AwaitSuspendFalse})
{
for(AwaitBehavior const f : {AwaitReadyTrue, AwaitSuspendTrue, AwaitSuspendFalse})
{
((cases[index] = {o, i, m, f}), ...);
++index;
}
}
}
}
return index;
}
constexpr std::size_t NUM_TEST_CASES{buildTestCasesImpl()};
consteval auto buildTestCases()
{
std::array<TestCase, NUM_TEST_CASES> cases;
buildTestCasesImpl(cases);
return cases;
}
constexpr auto TEST_CASES{buildTestCases()};
struct Task
{
struct promise_type
{
DEBUG_LIFETIME(promise_type);
void* operator new(std::size_t s)
{
std::println(stderr, "operator new({})", s);
return ::operator new(s);
}
void operator delete(void* p) noexcept(false)
{
std::println(stderr, "operator delete");
if(p)
{
throw std::runtime_error("operator delete");
}
return ::operator delete(p);
}
Task get_return_object()
{
std::println(stderr, "get_return_object");
return {std::coroutine_handle<promise_type>::from_promise(*this)};
}
using enum AwaitBehavior;
struct InitialSuspend
{
DEBUG_LIFETIME(InitialSuspend);
bool await_ready()
{
std::println(stderr, "InitialSuspend::await_ready");
return initialSuspendBehavior == AwaitReadyTrue;
}
bool await_suspend(std::coroutine_handle<promise_type>)
{
std::println(stderr, "InitialSuspend::await_suspend");
return initialSuspendBehavior == AwaitSuspendTrue;
}
void await_resume()
{
std::println(stderr, "InitialSuspend::await_resume");
}
};
struct MiddleSuspend
{
DEBUG_LIFETIME(MiddleSuspend);
bool await_ready()
{
std::println(stderr, "MiddleSuspend::await_ready");
return middleSuspendBehavior == AwaitReadyTrue;
}
bool await_suspend(std::coroutine_handle<promise_type>)
{
std::println(stderr, "MiddleSuspend::await_suspend");
return middleSuspendBehavior == AwaitSuspendTrue;
}
void await_resume()
{
std::println(stderr, "MiddleSuspend::await_resume");
}
};
struct FinalSuspend
{
DEBUG_LIFETIME(FinalSuspend);
bool await_ready() noexcept
{
std::println(stderr, "FinalSuspend::await_ready");
return finalSuspendBehavior == AwaitReadyTrue;
}
bool await_suspend(std::coroutine_handle<promise_type>) noexcept
{
std::println(stderr, "FinalSuspend::await_suspend");
return finalSuspendBehavior == AwaitSuspendTrue;
}
void await_resume() noexcept
{
std::println(stderr, "FinalSuspend::await_resume");
}
};
InitialSuspend initial_suspend()
{
std::println(stderr, "initial_suspend");
return {};
}
FinalSuspend final_suspend() noexcept
{
std::println(stderr, "final_suspend");
return {};
}
void return_void()
{
std::println(stderr, "return_void");
}
void unhandled_exception()
{
std::println(stderr, "unhandled_exception");
try
{
std::rethrow_exception(std::current_exception());
}
catch(std::exception const& e)
{
std::println(stderr, "\texception: {}", e.what());
}
catch(...)
{
std::println(stderr, "\tunknown exception");
}
}
MiddleSuspend await_transform(std::suspend_always)
{
std::println(stderr, "await_transform");
return {};
}
};
std::coroutine_handle<promise_type> h;
DEBUG_LIFETIME(Task);
};
//this is our one and only coroutine
Task makeTask(Operation const o)
{
DEBUG_LIFETIME(coroutine_local);
try
{
DEBUG_LIFETIME(coroutine_try);
switch(o)
{
case Operation::Return: co_return;
case Operation::Await : co_await std::suspend_always{}; break;
case Operation::Throw : throw std::runtime_error("coroutine throw");
}
std::println(stderr, "coroutine try end");
}
catch(...)
{
std::println(stderr, "coroutine catch");
throw;
}
std::println(stderr, "coroutine function end");
}
int main()
{
DEBUG_LIFETIME(main);
std::println(stderr, "main start\n");
using enum Operation;
using enum AwaitBehavior;
for(auto const [o, i, m, f] : TEST_CASES)
{
std::println(stderr, "main test start {}|{}{}{}", std::to_underlying(o), std::to_underlying(i), std::to_underlying(m), std::to_underlying(f));
/**/ initialSuspendBehavior = i;
/***/ middleSuspendBehavior = m;
/****/ finalSuspendBehavior = f;
try
{
Task t(makeTask(o));
std::println(stderr, "main after makeTask");
if(i == AwaitSuspendTrue)
{ //coroutine suspended at start
std::println(stderr, "main resume");
t.h.resume();
}
if((o == Await && m == AwaitSuspendTrue) || f == AwaitSuspendTrue)
{ //coroutine suspended after start
std::println(stderr, "main destroy");
t.h.destroy();
}
}
catch(std::exception const& e)
{
std::println(stderr, "main exception: {}", e.what());
}
catch(...)
{
std::println(stderr, "main unknown exception");
}
std::println(stderr, "main test end {}|{}{}{}\n", std::to_underlying(o), std::to_underlying(i), std::to_underlying(m), std::to_underlying(f));
}
std::println(stderr, "main end");
}

Whatever you think should happen here, you're wrong, because compilers don't even agree (and the standard is too terse and spread out for me to puzzle out). GCC 14.1 propagates the exception out of the coroutine stuff and back to whoever called makeTask(), .resume(), or even .destroy() - yes, even though .destroy() is marked noexcept, GCC propagates the exception out of it! Clang 17.0.3 propagates the exception out of makeTask() or .resume() if the coroutine doesn't suspend at its final_suspend, but otherwise calling .destroy() results in process termination. MSVC v143 14.40.33807 does the unthinkable and calls promise_type::unhandled_exception() and peforms a final_suspend. If that doesn't suspend the coroutine, it tries the destruction process over again. In a production app, this will likely result in double frees and other terrible things, eventually (hopefully quickly) culminating in a crash. However, since our test coroutine promise_type has no state, we just get stuck in a loop on the first test case, and the stack doesn't grow either, so it just loops infinitely.

[00007ff669267863] construct `global` default
[000000b3cbefef64] construct `main` default
main start
main test start R|RRR
operator new(272)
[000001e59e202300] construct `promise_type` default
get_return_object
[000000b3cbeff010] construct `Task` default
initial_suspend
[000001e59e202301] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000001e59e202301] ~destruct `InitialSuspend`
[000001e59e202308] construct `coroutine_local` default
[000001e59e202309] construct `coroutine_try` default
return_void
[000001e59e202309] ~destruct `coroutine_try`
[000001e59e202308] ~destruct `coroutine_local`
final_suspend
[000001e59e202338] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000001e59e202338] ~destruct `FinalSuspend`
[000001e59e202300] ~destruct `promise_type`
operator delete
unhandled_exception
exception: operator delete
final_suspend
[000001e59e202338] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000001e59e202338] ~destruct `FinalSuspend`
[000001e59e202300] ~destruct `promise_type`
operator delete
unhandled_exception
exception: operator delete
final_suspend
[000001e59e202338] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_resume
[000001e59e202338] ~destruct `FinalSuspend`
[000001e59e202300] ~destruct `promise_type`
operator delete
...ad infinitum...

Ok, that's hilariously terrifying, but also extremely unrealistic. Most people don't even write explicit overloads of operator new and operator delete in the first place, let alone going through the effort to make operator delete explicitly noexcept(false) and doing something that could throw an exception from it. It's an unrealistic scenario. Let's look at a more realistic scenario instead: user-provided types. Imagine our Task type is a template which takes the expected return type, and once the result has been calculated we store it in our promise_type, maybe wrapped in another type to handle cases like void or references. Maybe you even did some optimization where instead of using a standard library wrapper, you used a union so you could compact or make atomic the state flags, as some coroutine guides teach.

Pop quiz: what is the default noexcept specification for destructors? I can already hear you thinking, it's noexcept(true) even if not explicitly specified. Unfortunately, that intuition is wrong - the default specification is inhereted from the weakest class data member, meaning if any class data member has a noexcept(false) destructor, the enclosing class' destructor automatically becomes noexcept(false) too unless it was explicitly marked otherwise! So uh, about that hypothetical scenario we were discussing... you see how storing a user-provided type can be problematic, right? Let's simulate it. Start fresh with our original template and add this data member to our promise_type:

struct Task
{
struct promise_type
{
DEBUG_LIFETIME(promise_type);
ThrowOnDestruct tod;
void* operator new(std::size_t s)
{

Yep, just like with our previous deranged code modifcation, MSVC loops infinitely and Clang sometimes propagates and sometimes terminates. Interestingly, GCC fails with an internal compiler error, but we can get around that by deleting or commenting out the DEBUG_LIFETIME(promise_type); line (and optionally doing it manually by adding a constructor and destructor to promise_type), after which point it dutifully also does the same thing as in the operator delete case: propagating the exception out of .destroy(). You might think that MSVC won't loop because ThrowOnDestruct only throws when there's no uncaught exceptions, but returning from promise_type::uncaught_exception() exits the catch block of the compiler-generated state machine, meaning there's no longer any active exceptions, so it is free to offend again. The lesson here is you should always explicitly add the noexcept specifier to your destructors, and you should manually destruct any user-provided types at an opportune time so you can transmit any exception from it.

You might wonder how an exception could be transmitted anywhere useful if we're in the promise_type destructor, and indeed if you don't control who is allowed to destroy the coroutine and all your shared state is in the coroutine promise_type there's not much you can do. But if you can make the Task in charge of the coroutine destruction, even if only sometimes, then you just need to set a pointer in the promise_type to where it can store the exception, destroy the coroutine, and then look in your goodie bag for a treat to pass out to someone else.

So, that's one problem solved! We can now properly store user-provided types with throwing destructors in our promise_type, hooray! And with this achievement, we've opened Pandora's box. What are some other places that types with throwing destructors can end up at? Hm, how about... a local variable of the coroutine function body? Let's revert to our original template code and make this change:

//this is our one and only coroutine
Task makeTask(Operation const o)
{
DEBUG_LIFETIME(coroutine_local);
ThrowOnDestruct tod;
try
{
DEBUG_LIFETIME(coroutine_try);
switch(o)
{

Well, the code runs and doesn't crash, but what does it actually do? If we use our counting search feature on the new output, we see that both ~destruct `promise_type` and operator delete appear 78 times. Wait, 78 is less than 81! We have a leak in three test cases! Looking at the output, most of the time things go as normal: when we return from the coroutine the destructor exception is treated as an ordinary exception, and when we throw our own exception it suppresses the destructor exception thanks to our guard. But something strange happens in the specific instances where we're suspended in a co_await and the coroutine is destroyed; I've isolated the output of the leaking cases, see if you can figure it out:

main test start A|RSS
operator new(272)
[000002bb39cc6c80] construct `promise_type` default
get_return_object
[000000f90d7dece0] construct `Task` default
initial_suspend
[000002bb39cc6c81] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_resume
[000002bb39cc6c81] ~destruct `InitialSuspend`
[000002bb39cc6c88] construct `coroutine_local` default
[000002bb39cc6c8a] construct `coroutine_try` default
await_transform
[000002bb39cc6c99] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002bb39cc6c99] ~destruct `MiddleSuspend`
[000002bb39cc6c8a] ~destruct `coroutine_try`
~ThrowOnDestruct, uncaught_exceptions = 0
[000002bb39cc6c88] ~destruct `coroutine_local`
unhandled_exception
exception: ThrowOnDestruct
final_suspend
[000002bb39cc6cb8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
[000000f90d7dece0] ~destruct `Task`
main test end A|RSS
main test start A|SSS
operator new(272)
[000002bb39cc6dd0] construct `promise_type` default
get_return_object
[000000f90d7dece0] construct `Task` default
initial_suspend
[000002bb39cc6dd1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
main after makeTask
main resume
InitialSuspend::await_resume
[000002bb39cc6dd1] ~destruct `InitialSuspend`
[000002bb39cc6dd8] construct `coroutine_local` default
[000002bb39cc6dda] construct `coroutine_try` default
await_transform
[000002bb39cc6de9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main destroy
[000002bb39cc6de9] ~destruct `MiddleSuspend`
[000002bb39cc6dda] ~destruct `coroutine_try`
~ThrowOnDestruct, uncaught_exceptions = 0
[000002bb39cc6dd8] ~destruct `coroutine_local`
unhandled_exception
exception: ThrowOnDestruct
final_suspend
[000002bb39cc6e08] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
[000000f90d7dece0] ~destruct `Task`
main test end A|SSS
main test start A|USS
operator new(272)
[000002bb39cc60b0] construct `promise_type` default
get_return_object
[000000f90d7dece0] construct `Task` default
initial_suspend
[000002bb39cc60b1] construct `InitialSuspend` default
InitialSuspend::await_ready
InitialSuspend::await_suspend
InitialSuspend::await_resume
[000002bb39cc60b1] ~destruct `InitialSuspend`
[000002bb39cc60b8] construct `coroutine_local` default
[000002bb39cc60ba] construct `coroutine_try` default
await_transform
[000002bb39cc60c9] construct `MiddleSuspend` default
MiddleSuspend::await_ready
MiddleSuspend::await_suspend
main after makeTask
main destroy
[000002bb39cc60c9] ~destruct `MiddleSuspend`
[000002bb39cc60ba] ~destruct `coroutine_try`
~ThrowOnDestruct, uncaught_exceptions = 0
[000002bb39cc60b8] ~destruct `coroutine_local`
unhandled_exception
exception: ThrowOnDestruct
final_suspend
[000002bb39cc60e8] construct `FinalSuspend` default
FinalSuspend::await_ready
FinalSuspend::await_suspend
[000000f90d7dece0] ~destruct `Task`
main test end A|USS

The initial suspend doesn't seem to matter, but all three cases use the co_await middle awaiter to suspend and also suspend during the final_suspend. From the output we can see that during the call to .destroy(), the destructor of the local variable throws the exception and triggers the normal unhandled exception handling: promise_type::unhandled_exception() is called, followed by final_suspend, which doesn't resume the coroutine, and the compiler looks at a job well done for putting the coroutine at its final suspend point, and then returns from .destroy() with the caller none the wiser. All three of MSVC, Clang, and GCC agree on this behavior for once!

Whether it's a compiler bug or a dark corner of the C++ standard, we can actually work around this problem too, but with a twist: in addition to the escape hatch for transmitting an exception during destruction, we also need to transform all awaiters with await_transform so we can set a flag in the promise state to know whether the coroutine is currently suspended. Then, in promise_type::unhandled_exception(), we can see that the coroutine is suspended while the exception occurred, and we can store the exception and/or set another flag in the promise state to note that that exception needs to be transferred too, since now there's two different places we could receive an exception from during destruction. Most importantly, our final suspend awaiter needs to be updated to detect this circumstance and convince the compiler to finish destroying the coroutine, usually by returning false from await_suspend, or by destroying the coroutine handle if your return type is a coroutine handle since it's not allowed to return the same handle that was passed in for final suspend. (Yes, this does mean .destroy() is called twice, and yes, it is also called recursively in this case, and yes, it really does work this way.)

Also be careful to remember that the awaiter you're transforming could throw an exception from await_suspend as a valid way to resume the coroutine without going through await_resume, so you need to temporarily catch the exception, mark the coroutine as resumed, and then rethrow it. As for actually figuring out the awaiter type given the possibilities of overloading operator co_await, just remember you can use requires clauses in if constexpr statements within await_transform to dramatically simplify things.

That's certainly a lot of effort to handle a seldom-used feature of the C++ language, but hey, we did it! We solved the interactions between throwing destructors and coroutines! Why is the boss music still playing...? Wait... oh no... What does this do...?

//this is our one and only coroutine
Task makeTask(Operation const o)
{
DEBUG_LIFETIME(coroutine_local);
ThrowOnDestruct tod;
try
{
DEBUG_LIFETIME(coroutine_try);
ThrowOnDestruct tod;
switch(o)
{

You... you see it too, right? Those coroutine catch lines weren't there in the output before, right? Do you have any idea what this means!?

...

Hahaha...

...

I present to you... the coroutine that couldn't be killed:

#include <coroutine>
#include <print>
struct ThrowOnDestruct { ~ThrowOnDestruct() noexcept(false) { throw 1; } };
bool destructed{false};
struct Task
{
struct promise_type
{
~promise_type(){ destructed = true; }
Task get_return_object(){ return {std::coroutine_handle<promise_type>::from_promise(*this)}; }
std::suspend_never initial_suspend(){ return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void(){}
void unhandled_exception(){ throw; }
};
std::coroutine_handle<promise_type> h;
};
Task makeTask()
{
while(true)
{
try
{
ThrowOnDestruct tod;
co_await std::suspend_always{};
}
catch(...)
{
}
std::println(stderr, "coroutine lives");
}
}
int main()
{
std::println(stderr, "main start\n");
try
{
Task t(makeTask());
while(!destructed)
{
std::println(stderr, "main destroy");
t.h.destroy();
}
}
catch(...)
{
std::println(stderr, "main exception");
}
std::println(stderr, "main end");
}

All three compilers output this...

main start
main destroy
coroutine lives
main destroy
coroutine lives
main destroy
coroutine lives
main destroy
coroutine lives
main destroy
coroutine lives
main destroy
coroutine lives
main destroy
coroutine lives
...ad infinitum...
...ad infinitum...

There is no hope. All is lost. You can't even detect this by counting the number of active uncaught exceptions, because who knows what exception shenangians other code got up to while the coroutine was suspended. This is undetectable and unkillable.

...

Well, I suppose if the promise_type knew it was supposed to be getting destructed, it could subvert the coroutine's wishes during its await_transform... but that's even assuming the coroutine ever suspends again. Besides, who would repeatedly call .destroy() in a loop until the ~promise_type() reported that it ran? The coroutine not only gets to escape, it gets notified that an attempt was made on its life, and it can do whatever it wants with that information. If I were you, I'd stay a few address spaces away from it.

I have no idea if this is standards-compliant. I've tried reading the C++ standard before and learned that my eyes glaze over at subtle details like the difference between resuming a coroutine and resume()ing a coroutine. All I know is, this coroutine is out on the prowl, and at least three compilers are enabling its devious behavior. Please, be careful out there.

Comments