Date: Fri, 12 Sep 2025 18:40:44 +0300
On Thu, 2025-09-11 at 17:27 -0400, Jason McKesson via Std-Proposals
wrote:
> On Thu, Sep 11, 2025 at 7:21 AM Avi Kivity via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > The Standard says
> >
> > > If searches for the names return_void and return_value in the
> > > scope
> > of the promise type each find any declarations, the program is ill-
> > formed.
> >
> > However, there are cases where one wants both "co_return;" and
> > co_return something;" statements in the same coroutine.
> >
> > The cases are when the coroutine returns a sum type such as
> > std::future
> > or std::expected, and one of the options is void (e.g.
> > std::future<void> or std::expected<void, something>. In these
> > cases,
> > one would want
> >
> >
> > co_return;
> >
> > to select the void branch of the sum type
> >
> > and
> >
> > co_return std::make_exception_ptr(...) // for std::future<void>
> >
> > or
> >
> > co_return something(...) // for std::expected<void, something>.
> >
> >
> > to select the non-void branch.
> >
> > Early versions of gcc did not error when both return_value() and
> > return_void() were defined; no problems were observed.
>
> From a conceptual perspective, `return` and `co_return` should behave
> similarly. As it currently stands, any function for which `return
> <expr>;` is valid is one where `return;` would not be valid. So it
> conceptually makes sense that `co_return` would behave the same way.
>
> That having been said, there's a reasonable argument to be made that
> the behavior of `co_return` is already fairly divergent from
> `return`.
> Of particular note is the fact that the relationship between the
> returned expression type (if any) and the function's apparent return
> type is not nearly as clear as it is for `return`. You may have to
> dig
> deeply into the coroutine machinery to figure out exactly what type
> you need to provide, if any.
>
> Also, there's the fact that coroutines can already have *multiple*
> different "return types": the type you can put into `co_return`. So
> you can already do `co_return X;` and `co_return Y;` where those two
> types have no conversion relationship between them or with some other
> third type. Adding `co_return;` to that list seems pretty reasonable,
> even if it does call a differently named function internally.
Even for plain `return`, sum types make the case for both return; and
return expr; in the same function.
A function f that returns std::expected<T, E> can "return T();" or it
can "return std::unexpected(E());".
A function g that returns std::unexpected<void, E> cannot do the
analogous and "return;" for the good case and "return
std::unexpected(E());" for the bad case.
I suppose we could make "return;" work for a function returning a T
that has a default constructor, but I'm not brave enough to propose it.
There's also "return {};" that works equally well and is concise.
For coroutines, there are no concise alternatives, and the solution is
deleting a line from the spec and a line from the compiler (or at least
making a compiler check conditional on the supported standard version).
wrote:
> On Thu, Sep 11, 2025 at 7:21 AM Avi Kivity via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > The Standard says
> >
> > > If searches for the names return_void and return_value in the
> > > scope
> > of the promise type each find any declarations, the program is ill-
> > formed.
> >
> > However, there are cases where one wants both "co_return;" and
> > co_return something;" statements in the same coroutine.
> >
> > The cases are when the coroutine returns a sum type such as
> > std::future
> > or std::expected, and one of the options is void (e.g.
> > std::future<void> or std::expected<void, something>. In these
> > cases,
> > one would want
> >
> >
> > co_return;
> >
> > to select the void branch of the sum type
> >
> > and
> >
> > co_return std::make_exception_ptr(...) // for std::future<void>
> >
> > or
> >
> > co_return something(...) // for std::expected<void, something>.
> >
> >
> > to select the non-void branch.
> >
> > Early versions of gcc did not error when both return_value() and
> > return_void() were defined; no problems were observed.
>
> From a conceptual perspective, `return` and `co_return` should behave
> similarly. As it currently stands, any function for which `return
> <expr>;` is valid is one where `return;` would not be valid. So it
> conceptually makes sense that `co_return` would behave the same way.
>
> That having been said, there's a reasonable argument to be made that
> the behavior of `co_return` is already fairly divergent from
> `return`.
> Of particular note is the fact that the relationship between the
> returned expression type (if any) and the function's apparent return
> type is not nearly as clear as it is for `return`. You may have to
> dig
> deeply into the coroutine machinery to figure out exactly what type
> you need to provide, if any.
>
> Also, there's the fact that coroutines can already have *multiple*
> different "return types": the type you can put into `co_return`. So
> you can already do `co_return X;` and `co_return Y;` where those two
> types have no conversion relationship between them or with some other
> third type. Adding `co_return;` to that list seems pretty reasonable,
> even if it does call a differently named function internally.
Even for plain `return`, sum types make the case for both return; and
return expr; in the same function.
A function f that returns std::expected<T, E> can "return T();" or it
can "return std::unexpected(E());".
A function g that returns std::unexpected<void, E> cannot do the
analogous and "return;" for the good case and "return
std::unexpected(E());" for the bad case.
I suppose we could make "return;" work for a function returning a T
that has a default constructor, but I'm not brave enough to propose it.
There's also "return {};" that works equally well and is concise.
For coroutines, there are no concise alternatives, and the solution is
deleting a line from the spec and a line from the compiler (or at least
making a compiler check conditional on the supported standard version).
Received on 2025-09-12 15:40:48