-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[coroutines] Clang generates incorrect code for throwing promise.unhandled_exception() #61900
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@llvm/issue-subscribers-coroutines |
If I call |
Update to myself: although I solved the O0 case, the optimized case is more complex than I thought. Because: The coroutine will be transformed to (roughly):
In the reproducer, the optimizer found that the unhandled_exception() here will always throw after inlining. So the final suspend won't be reached. So the optimizer removes the final_suspend part in the early places. Maybe I need to find something tricky to solve this. |
… path Try to address part of #61900. It is not completely addressed since the original reproducer is not fixed due to the final suspend point is optimized out in its special case. But that is a relatively independent issue.
Note to my self: given the transformation from http://eel.is/c++draft/dcl.fct.def.coroutine, the destroy function from the final suspend point should destroy the same thing with the initial suspend point. This may help us to handle the case that the final suspend is optimized out. However, it is problematic since the optimizier don't have knowledge about first suspend and final suspend point. So the best method may still be to add a coro intrinsic to teach the middle end about the semantics of final suspend to not optimize it out. |
Note that destroying at the final suspend point may have different behaviour compared to the initial suspend point depending on the awaitable object. The initial suspend point may have one temporary awaiter returned from The destroy() behaviour from all of these suspend points will have commonalities - they all end up eventually executing the sequence of promise destruction, parameter destruction and frame deallocation. |
Thanks for correcting me. While this is relatively easy to fix: we can fix it by making The condition to trigger the bug including:
Then the optimizer found the final_suspend part is never executed then it got removed. Then, I'd like to see this is really a corner case. https://godbolt.org/z/Tsj7Th41s So I am still trying to find a light-weight solution to users so that the users who don't use such pattern won't get worse code than before. |
Inspired by #64945, the best solution may be to introduce something like
then we will add special information for the final suspend to make it not to be optimized out. Otherwise, we will convert the call to |
… path Try to address part of llvm/llvm-project#61900. It is not completely addressed since the original reproducer is not fixed due to the final suspend point is optimized out in its special case. But that is a relatively independent issue.
The wording for coroutines in
[dcl.fct.def.coroutine]
forunhandled_exception()
says that:However, it seems that the current codegen for Clang does not set the suspend point to be at a final suspend point in this case. Instead, if a coroutine exits the call to
unhandled_exception()
with an exception, which you then catch and then destroy the coroutine, the coroutine behaves as if the coroutine was still suspended at the last suspend-point it suspended at. i.e. it does not seem to be writing a new suspend-point index to the coroutine-state ifunhandled_exception()
exits with an exception, instead it leaves the last-written suspend-point index value unchanged.This can lead to unexpected behaviour. e.g. double-destruction of variables in-scope at the last suspend-point.
For example: Compile the following code with Clang 16.0 and the compiler args
-std=c++20 -stdlib=libc++ -O2
Compiler-Explorer: https://godbolt.org/z/xqY4bbPTW
The expected output is:
The observed output under Clang 16 is:
The text was updated successfully, but these errors were encountered: