llvm / llvm/llvm-project

[coroutines] Behavior when `await_suspend()` explicitly resumes its coroutine and then throws

Open
#187,852 5 comments 0 reactions 0 assignees View on GitHub
coroutines
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Consider an example:

```cpp
#include
#include

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?

P.S. I asked a similar question on [gcc bugzilla](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124594)

Contributor guide

Open the contributing guide

Research direction

Start by compiling the provided C++ coroutine reproducer and comparing the `123?2` result with the `expr.await` and `dcl.fct.def.coroutine` wording linked in the issue. Review the related CWG issue 872 and GCC bug 124594; done means determining whether the behavior is standard-conforming, an implementation bug, or a wording ambiguity.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.