https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124594

            Bug ID: 124594
           Summary: [coroutines] Behavior when `await_suspend()`
                    explicitly resumes its coroutine and then throws
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ddvamp007 at gmail dot com
  Target Milestone: ---

Consider an example:

```cpp
#include <coroutine>
#include <iostream>

struct Tag {
  struct promise_type {
    Tag get_return_object() { return {}; }
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    void return_void() {}
    void unhandled_exception() {}
  };
};

struct ResumeAndThrowAwaiter {
  bool await_ready() { return false; }
  void await_suspend(std::coroutine_handle<> h) {
    std::cout << 1;
    h.resume(); // #3
    std::cout << 3;
    throw 0; // #4
  }
  void await_resume() {}
};

Tag Coroutine() {
  try {
    co_await ResumeAndThrowAwaiter{}; // #1
  } catch (...) {
    std::cout << '?';
  }

  std::cout << 2;

  try {
    co_await std::suspend_always{}; // #2
  } catch (...) {
    std::cout << 4;
  }

  std::cout << 5;
}

void StartCoro() {
  Coroutine();
}

int main() {
  StartCoro();
}
```

In my reading of the standard, the execution is as follows. Coroutine is
suspended at `#1`. At `#3` the coroutine is already
[suspended](https://eel.is/c++draft/expr.await#5.1.sentence-1), which means it
can be [resumed](https://eel.is/c++draft/dcl.fct.def.coroutine#9.sentence-1) at
`#3` and continue execution from `#1`. After suspending at `#2`, we return to
`#3`, after which the evaluation of `await-suspend` exits via an exception
thrown at `#4`. This exception is
[rethrown](https://eel.is/c++draft/expr.await#5.1.sentence-3) from `#2` and
should be caught by the try block associated with this point. So I expect the
output to be `12345`. However, I see some problems with this reading/behavior,
which I described more generally in [cwg issue
872](https://github.com/cplusplus/CWG/issues/872) (in short, the evaluation of
two `await-expression`s is mixed here).

At the same time, [major compilers](https://godbolt.org/z/f1rEcbM9G) output
`123?2`

I would appreciate input from compiler implementers on what the expected
behavior should be in this case. Is this behavior (producing `123?2`):
- intended and consistent with the current standard wording,
- a compiler bug,
- or does this point to an ambiguity or issue in the standard?

Reply via email to