c++c++20c++-coroutine

Coroutine final_suspend: is it undefined behavior?


My question is regarding a passage in cppreference that I find confusing:

If the coroutine ends with an uncaught exception, it performs the following:

  • catches the exception and calls promise.unhandled_exception() from within the catch-block
  • calls promise.final_suspend() and co_awaits the result (e.g. to resume a continuation or publish a result). It's undefined behavior to resume a coroutine from this point.

(see https://en.cppreference.com/w/cpp/language/coroutines)

The second bullet point is what confuses me. They say final_suspend is intended to execute continuations, but then they say resuming a coroutine "from this point" is undefined behavior. That seems almost contradictory. What exactly is undefined behavior here? I can think of 3 scenarios:

  1. Is it undefined behavior to, directly or indirectly, call resume on a coroutine_handle in the body of final_suspend?
  2. Is it undefined behavior to, directly or indirectly, resume a coroutine_handle from the body of await_suspend of the final awaiter?
  3. Is it undefined behavior to return a coroutine_handle from await_suspend of the final awaiter?

If one or all of these are undefined behavior, is that also true for final_suspend after a return_void or return_value, or only after unhandled_exception?

(I've created some sample code for scenario 3 on godbolt. It's not necessary for this question, but it might be helpful. Does my handling of exceptions and continuations produce undefined behavior in that example?)


Solution

  • coroutine_handle::resume yields undefined behavior for any coroutine that is suspended at its final suspend point. This is always true of any coroutine so suspended.

    Cppreference is simply pointing out that, in not catching an exception, the coroutine is considered suspended at its final suspend point.