Exception support
Currently exception support in TMC is very limited - only throwing functions, or throwing awaitables that are awaited directly, can be caught. So, this is the only form of exception handling in TMC that works:
tmc::task<void> a() {
try {
co_await possibly_throwing_awaitable();
}
catch (std::exception ex) {}
}
tmc::task does not propagate exceptions, nor do any of the spawn*() family of functions. So these examples do not work; std::terminate() will be called if an exception is thrown:
tmc::task<void> terminates_one() {
try {
co_await []() -> tmc::task<void> { co_await possibly_throwing_awaitable(); }();
}
catch (std::exception ex) {}
}
tmc::task<void> terminates_two() {
try {
co_await tmc::spawn(possibly_throwing_awaitable());
}
catch (std::exception ex) {}
}
Implementing exception support across the library would require adding std::exception_ptr in every wrapper struct, and propagating it from the awaitable. This would come at a non-zero runtime cost, even if users don't throw any exceptions, unless they explicitly build with -fno-exceptions.
Additionally there's the question of what to do if multiple awaitables throw an exception (e.g. from spawn_many or spawn_tuple). If space for each awaitable's possible exception is allocated, it is of limited value as only 1 exception can be rethrown anyway. If only a single exception slot is allocated, then it needs to be set atomically as multiple awaitables may write to it simultaneously.
Then there's the question of what to do with the coroutine frame and its resources after the exception is thrown.
This feature is backlogged because it's not useful to me personally, and I think it creates more problems than it solves. I suggest that you return error codes or std::expected from your awaitables instead. Nonetheless, if there is enough community support for this, I will consider implementing it.