coroutines-ts icon indicating copy to clipboard operation
coroutines-ts copied to clipboard

Allow functions to be conditionally compiled as coroutines through use of 'if constexpr'

Open lewissbaker opened this issue 6 years ago • 1 comments

Should we be supporting the ability for template functions to be conditionally compiled as coroutines in cases where one branch of an if constexpr branch contains the co_await keyword and the other branch does not?

For example: See https://godbolt.org/g/23jB2U

template<typename T>
auto foo(T value) -> std::conditional<is_awaitable_v<T>, task<void>, void>
{
  // Lots of common setup code here.

  if constexpr (is_awaitable_v<T>)
  {
    // Only usage of co_await is here.
    bar(co_await value);
  }
  else
  {
    bar(value);
  }
}

The current wording of N4680 8.4.4(1) says:

A function is a coroutine if it contains a coroutine-return-statement (6.6.3.1), an await-expression (5.3.8), a yield-expression (5.20), or a range-based for (6.5.4) with co_await. The parameter-declaration-clause of the coroutine shall not terminate with an ellipsis that is not part of a parameter-declaration.

And N4713 9.4.1(2) says:

... If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity (Clause 17), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated. ...

There seems to be some ambiguity of wording between these two sections as to whether or not a co_await/co_return/co_yield keyword that occurs within a statement discarded due to an if constexpr is still 'contained' within the function.

@modocache Also found a potentially relevant precedence of wording from N4713 10.1.7.4(7):

If a function with a declared return type that contains a placeholder type has multiple non-discarded return statements, the return type is deduced for each such return statement. If the type deduced is not the same in each deduction, the program is ill-formed.

This section is also using the term 'contains' but directly addresses the issue of whether or not statements discarded due to if constexpr should be considered by restricting it to consider only non-discarded return statements.

Should the wording of N4680 8.4.4(1) be updated to also use the term non-discarded when referring to coroutine-return-statement, await-expression and yield-expression to allow interaction with if constexpr?

Note that the current state of the Clang compiler (as of 2018/02/08) still triggers compilation of a function as a coroutine even if the only occurrences of the co_xxx keywords are within a discarded statement.

lewissbaker avatar Feb 08 '18 07:02 lewissbaker