diff options
author | Bin Cheng <bin.cheng@linux.alibaba.com> | 2020-03-09 18:54:57 +0800 |
---|---|---|
committer | Bin Cheng <bin.cheng@linux.alibaba.com> | 2020-03-09 18:54:57 +0800 |
commit | 016d0f9e43c1d2bd8227751b5b20a309c94edc90 (patch) | |
tree | 865c048244c3f8f01427e8bd3afc581227a75513 /gcc/cp | |
parent | cb2c60206f4f2218f84ccde21663b00de068d8c7 (diff) | |
download | gcc-016d0f9e43c1d2bd8227751b5b20a309c94edc90.zip gcc-016d0f9e43c1d2bd8227751b5b20a309c94edc90.tar.gz gcc-016d0f9e43c1d2bd8227751b5b20a309c94edc90.tar.bz2 |
Insert default return_void at the end of coroutine body
Exception in coroutine is not correctly handled because the default
return_void call is now inserted before the finish suspend point,
rather than at the end of the original coroutine body. This patch
fixes the issue by expanding code as following:
co_await promise.initial_suspend();
try {
// The original coroutine body
promise.return_void(); // The default return_void call.
} catch (...) {
promise.unhandled_exception();
}
final_suspend:
// ...
gcc/cp/
* coroutines.cc (build_actor_fn): Factor out code inserting the
default return_void call to...
(morph_fn_to_coro): ...here, also hoist local var declarations.
gcc/testsuite/
* g++.dg/coroutines/torture/co-ret-15-default-return_void.C: New.
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 68 |
2 files changed, 43 insertions, 31 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f32c27e..128880b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2020-03-09 Bin Cheng <bin.cheng@linux.alibaba.com> + + * coroutines.cc (build_actor_fn): Factor out code inserting the + default return_void call to... + (morph_fn_to_coro): ...here, also hoist local var declarations. + 2020-03-08 Patrick Palka <ppalka@redhat.com> PR c++/93729 diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index bca4f1e..920575b 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2161,21 +2161,6 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, r = coro_build_expr_stmt (initial_await, loc); add_stmt (r); - /* Now we've built the promise etc, process fnbody for co_returns. - We want the call to return_void () below and it has no params so - we can create it once here. - Calls to return_value () will have to be checked and created as - required. */ - - tree return_void = NULL_TREE; - tree rvm - = lookup_promise_method (orig, coro_return_void_identifier, loc, - /*musthave=*/false); - if (rvm && rvm != error_mark_node) - return_void - = build_new_method_call (ap, rvm, NULL, NULL_TREE, LOOKUP_NORMAL, NULL, - tf_warning_or_error); - /* co_return branches to the final_suspend label, so declare that now. */ tree fs_label = create_named_label_with_ctx (loc, "final.suspend", actor); @@ -2190,15 +2175,6 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, /* Add in our function body with the co_returns rewritten to final form. */ add_stmt (fnbody); - /* [stmt.return.coroutine] (2.2 : 3) if p.return_void() is a valid - expression, flowing off the end of a coroutine is equivalent to - co_return; otherwise UB. - We just inject the call to p.return_void() here, and fall through to - the final_suspend: label (eliding the goto). If the function body has - a co_return, then this statement will be unreachable and DCEd. */ - if (return_void != NULL_TREE) - add_stmt (return_void); - /* Final suspend starts here. */ r = build_stmt (loc, LABEL_EXPR, fs_label); add_stmt (r); @@ -3815,18 +3791,48 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) BIND_EXPR_BLOCK (first) = replace_blk; } + /* actor's version of the promise. */ + tree actor_frame = build1_loc (fn_start, INDIRECT_REF, coro_frame_type, + DECL_ARGUMENTS (actor)); + tree ap_m = lookup_member (coro_frame_type, get_identifier ("__p"), 1, 0, + tf_warning_or_error); + tree ap = build_class_member_access_expr (actor_frame, ap_m, NULL_TREE, + false, tf_warning_or_error); + + /* Now we've built the promise etc, process fnbody for co_returns. + We want the call to return_void () below and it has no params so + we can create it once here. + Calls to return_value () will have to be checked and created as + required. */ + + tree return_void = NULL_TREE; + tree rvm + = lookup_promise_method (orig, coro_return_void_identifier, fn_start, + /*musthave=*/false); + if (rvm && rvm != error_mark_node) + return_void + = build_new_method_call (ap, rvm, NULL, NULL_TREE, LOOKUP_NORMAL, NULL, + tf_warning_or_error); + + /* [stmt.return.coroutine] (2.2 : 3) if p.return_void() is a valid + expression, flowing off the end of a coroutine is equivalent to + co_return; otherwise UB. + We just inject the call to p.return_void() here, and fall through to + the final_suspend: label (eliding the goto). If the function body has + a co_return, then this statement will be unreachable and DCEd. */ + if (return_void != NULL_TREE) + { + tree append = push_stmt_list (); + add_stmt (fnbody); + add_stmt (return_void); + fnbody = pop_stmt_list(append); + } + if (flag_exceptions) { tree ueh_meth = lookup_promise_method (orig, coro_unhandled_exception_identifier, fn_start, /*musthave=*/true); - /* actor's version of the promise. */ - tree actor_frame = build1_loc (fn_start, INDIRECT_REF, coro_frame_type, - DECL_ARGUMENTS (actor)); - tree ap_m = lookup_member (coro_frame_type, get_identifier ("__p"), 1, 0, - tf_warning_or_error); - tree ap = build_class_member_access_expr (actor_frame, ap_m, NULL_TREE, - false, tf_warning_or_error); /* Build promise.unhandled_exception(); */ tree ueh = build_new_method_call (ap, ueh_meth, NULL, NULL_TREE, LOOKUP_NORMAL, |