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?