Language Extension for better, more deterministic HALO for C++ Coroutines

Thanks for the written up. @ych and I have talked privately on this topic. I am in favor of this in the high level.

And I actually did the pretty same work in the downstream. The reason why I didn’t upstream it is I don’t feel good with my FE codes. There are too many pattern matches which I don’t like. And I feel the ME part is pretty straight forward and stable. This is exactly the opposite from the poster : )
(In a privarte chat, @ych mentioned an idea to implement a more general coro elide frame in the middle end which don’t depends on inlining. But I assume that one is not inclued here).

Some comments:

This patch proposes C++ struct/class attribute [[clang::coro_inplace_task]] (feel free to suggest a better name.)

I prefer the name as coro_elide_after_awaited. I feel it is much more straight forward. And this may not be limited to so-called Task type.

that describes to the compiler that the attributed Task type won’t expose APIs or pointers that allows callee coroutines to continue running after caller is destroyed.

This description looks not natural and incorrect to me.

I’d like to describe it as:

  • We call a coroutine which returns the attributed type as attributed coroutine.
  • In an attributed coroutine A, if an just constructed attributed coroutine B gets **immediately ** co_awaited, the lifetime of coroutine B should be guaranteed to be enclosing in the lifetime
    of coroutine A. Otherwise, the behavior is undefined.
  • Then the compiler is allowed to allocate the frame of B as a local variable in A.

Here the concept of immediately co_awaited may not be very clear and may need improved.

So that it will be clear:

Task foo() { ... }
Task bar() {
    co_return co_await foo();
} 

The body of foo() will be elided. But

Task foo() { ... }
Task bar() {
    Task f = foo();
    co_return co_await f;
} 

won’t be elided. And

Task foo() { ... }
Task forward(Task &&f) { return f; }
Task bar() {
    co_return co_await forward(foo());
} 

won’t be elided.


@avogelsgesang We may need new attribute to do that. Your proposed [[coro_awaited]] attribute in parameters looks good. (Although it might be slightly hard to implement). Another idea can handle this and easier to implement, is something like [[coro_always_eliding]], which will elide all the calls:

[[clang::coro_always_eliding]] auto [size1, size2] = auto [size1, size2] = co_await when_all(get_file_size("file1"), get_file_size("file 2"));

While it is more powerful, it would be more dangerous.

And after all, we can do such things as a new attribute, it is not conflicting with the being proposed one.