On Mon, Jan 2, 2023 at 7:24 PM Aaron Jacobs via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hello all,

While working on a C++ coroutine library for use at Google I've found that some
important functionality is hindered by a precondition on
`std::coroutine_handle<Promise>::from_promise` that seems to be very slightly
stronger than necessary, and I'm seeking feedback on a proposal to weaken it
accordingly. I think this can be done while keeping existing implementations
conforming.

[coroutine.handle.con] currently lists the following precondition for
`from_promise(Promise& p)`:

> Preconditions: `p` is a reference to a promise object of a coroutine.

I propose changing it to something like the following (feedback on wording
welcome):

> Preconditions: p is a reference to an object that is
> pointer-interconvertible with the promise object of a coroutine, and
> has the same alignment as the promise.

Just looking at this proposed wording, it doesn't seem like your proposal does anything. A pointer that points to "an object pointer-interconvertible with X, with the same alignment as X" is exactly the same, machine-wise, as a pointer that points to "an X" — all you have to do is cast it to (X*) before passing it to `from_promise`. There's certainly nothing wrong or undefined about taking a pointer-that-physically-points-to-an-X-object and casting it to type pointer-to-X.

struct X { int i; };
void from_promise(X&);
void test() {
  X x;
  int *pi = &x.i;
  from_promise(*pi);  // not allowed, obviously
  from_promise(*(X*)pi);  // already allowed, and perfectly well-defined and safe
}

So if this is all you mean, then you don't need to change the Standard at all; you just need to add a cast to your code.
But maybe you mean something more?

Promise types naturally form a
singly-linked list via coroutine handles to resume when a coroutine completes:
[...]
    template <typename Result>
    struct MoreRealisticPromise {
      [...]
      // The value co_returned by the coroutine.
      std::optional<Result> result;
      // The coroutine to resume when my coroutine finishes.
      std::coroutine_handle<???> waiter;
    };

In the example above we could use `std::coroutine_handle<>` for the waiter, but
then we could no longer use it as a link in a list because there would be no
UB-free way to get hold of the next node given a current node.

You mean, there would be no way to take that std::coroutine_handle<void> and convert it back to a std::coroutine_handle<MoreRealisticPromise<U>>? Well, sure, but that's mainly because you have no idea what type `U` should actually be. It's not guaranteed that `U` is the same type as `Result`. If you knew what type `U` was, then you wouldn't have a problem; and since you don't know what type `U` is, you do have a problem. Messing around with the semantic requirements of `from_promise` doesn't seem to do anything to solve that problem.

Your code snippets don't actually involve any calls to `from_promise`. Maybe it would be clearer if you showed a Tony Table, like "here's something that doesn't compile / doesn't work today" versus "here's how it would work after this proposal."


[...] there
seems to be no UB-free wait to obtain a `std::coroutine_handle<PromiseBase>`. A
reference to the `PromiseBase` sub-object of `Promise<int>` is not technically
a reference to a coroutine's promise object.

It's not clear to me what you mean here. Of course a reference to a given physical object X is a reference to a coroutine's promise object, if and only if the object X is a coroutine's promise object. The type of the reference (whether it's a reference-to-most-derived-object or reference-to-base or whatever) doesn't seem relevant.

I think it'll greatly clarify things if you show a complete compilable example (as simple as possible) that exercises the `from_promise` codepath you want to change.
 
–Arthur