Home > database >  Is it necessary to have a co_return statement on each execution path of a coroutine that returns voi
Is it necessary to have a co_return statement on each execution path of a coroutine that returns voi

Time:11-16

I wonder whether the below code is valid C code or if not using co_return results in undefined behavior.

IAsyncAction MyClass::MyCoroutine()
{
  co_await someOtherClassInstance.SomeCoroutine();
}

I.e. is it necessary to adjust the code as follows?

IAsyncAction MyClass::MyCoroutine()
{
  co_await someOtherClassInstance.SomeCoroutine();
  co_return;
}

If the behavior is not undefined, what is the best practice (always add co_return or not) and what is the justification for doing so?

CodePudding user response:

Omitting the co_return; statement is well defined here. According to [stmt.return.coroutine] this is allowed as long as p.return_void() is a valid expression (where p is the promise type).

C /WinRT implements return_void() for IAsyncAction and IAsyncActionWithProgress (or rather the internal await adapter structs for those).

Since the co_return; statement is purely optional here, it is down to personal preference on whether to use it or not. Personally, I prefer reading code where the co_return; statement is present, for a few reasons:

  • It allows me to easily comment out part of the coroutine (e.g. for testing) without risking to turn it into a regular function.
  • I don't have to know the intricacies of the complex C /WinRT library to figure out whether the code is correct.
  • The code stays correct if I ever decide to change its return type.

CodePudding user response:

According to cppreference, the first block would only incur in undefined behaviour if the Promise type has no Promise::return_void() member function:

When a coroutine reaches the co_return statement, it performs the following:

  • calls promise.return_void() for
    • co_return;
    • co_return expr where expr has type void
    • falling off the end of a void-returning coroutine. The behavior is undefined if the Promise type has no Promise::return_void() member function in this case.

The Standard draft seems to say the same in other words:

If p.return_­void() is a valid expression, flowing off the end of a coroutine's function-body is equivalent to a co_­return with no operand; otherwise flowing off the end of a coroutine's function-body results in undefined behavior.

[Emphasis mine in both quotes]

  • Related