diff options
author | Iain Sandoe <iain@sandoe.co.uk> | 2020-06-02 16:47:54 +0100 |
---|---|---|
committer | Iain Sandoe <iain@sandoe.co.uk> | 2020-06-02 19:10:28 +0100 |
commit | 324276ff9b1aa5128e5cb9f5d43182d1ebab0752 (patch) | |
tree | d38572dea31e7d15363b5f645da700f6c6396638 | |
parent | ce95db102aab4dea9af24a20de78db2f57c0a37b (diff) | |
download | gcc-324276ff9b1aa5128e5cb9f5d43182d1ebab0752.zip gcc-324276ff9b1aa5128e5cb9f5d43182d1ebab0752.tar.gz gcc-324276ff9b1aa5128e5cb9f5d43182d1ebab0752.tar.bz2 |
coroutines: Wrap co_await in a target expr where needed [PR95050]
Since the co_await expression is mostly opaque to the existing
machinery, we were hiding the details of the await_resume return
value. If that needs to be wrapped in a target expression, then
emulate this with the whole co_await. Similarly, if the await
expression we build in response to co_await p.yield_value (e)
is wrapped in a target expression, then we need to transfer that
wrapper to the resultant CO_YIELD_EXPR (which is, itself, just
a proxy for the underlying co_await).
gcc/cp/ChangeLog:
PR c++/95050
* coroutines.cc (build_co_await): Wrap the co_await expression
in a TARGET_EXPR, where needed.
(finish_co_yield_expr): Likewise.
gcc/testsuite/ChangeLog:
PR c++/95050
* g++.dg/coroutines/pr95050.C: New test.
-rw-r--r-- | gcc/cp/coroutines.cc | 29 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/pr95050.C | 49 |
2 files changed, 76 insertions, 2 deletions
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index e90387b..e689625 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -816,6 +816,12 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) tree awaiter_calls = make_tree_vec (3); TREE_VEC_ELT (awaiter_calls, 0) = awrd_call; /* await_ready(). */ TREE_VEC_ELT (awaiter_calls, 1) = awsp_call; /* await_suspend(). */ + tree te = NULL_TREE; + if (TREE_CODE (awrs_call) == TARGET_EXPR) + { + te = awrs_call; + awrs_call = TREE_OPERAND (awrs_call, 1); + } TREE_VEC_ELT (awaiter_calls, 2) = awrs_call; /* await_resume(). */ tree await_expr = build5_loc (loc, CO_AWAIT_EXPR, @@ -823,7 +829,13 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind) a, e_proxy, o, awaiter_calls, build_int_cst (integer_type_node, (int) suspend_kind)); - return convert_from_reference (await_expr); + if (te) + { + TREE_OPERAND (te, 1) = await_expr; + await_expr = te; + } + tree t = convert_from_reference (await_expr); + return t; } tree @@ -960,8 +972,21 @@ finish_co_yield_expr (location_t kw, tree expr) tree op = build_co_await (kw, yield_call, CO_YIELD_SUSPEND_POINT); if (op != error_mark_node) { - op = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (op), expr, op); + if (REFERENCE_REF_P (op)) + op = TREE_OPERAND (op, 0); + /* If the await expression is wrapped in a TARGET_EXPR, then transfer + that wrapper to the CO_YIELD_EXPR, since this is just a proxy for + its contained await. Otherwise, just build the CO_YIELD_EXPR. */ + if (TREE_CODE (op) == TARGET_EXPR) + { + tree t = TREE_OPERAND (op, 1); + t = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (t), expr, t); + TREE_OPERAND (op, 1) = t; + } + else + op = build2_loc (kw, CO_YIELD_EXPR, TREE_TYPE (op), expr, op); TREE_SIDE_EFFECTS (op) = 1; + op = convert_from_reference (op); } return op; diff --git a/gcc/testsuite/g++.dg/coroutines/pr95050.C b/gcc/testsuite/g++.dg/coroutines/pr95050.C new file mode 100644 index 0000000..fd1516d --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr95050.C @@ -0,0 +1,49 @@ +#if __has_include (<coroutine>) +#include <coroutine> +using namespace std; +#elif defined (__clang__) && __has_include (<experimental/coroutine>) +#include <experimental/coroutine> +using namespace std::experimental; +#endif +#include <utility> + +struct ret_type +{ + ret_type () = default; + ret_type (const ret_type&) = delete; + //ret_type (ret_type&&) = default; + ~ret_type() {} +}; + +struct task +{ + struct promise_type + { + auto get_return_object () -> task { return {}; } + auto initial_suspend () -> suspend_always { return {}; } + auto final_suspend () -> suspend_always { return {}; } + void return_void () {} + void unhandled_exception () { } + void thing (ret_type x) {} + }; +}; + +struct awaiter +{ + bool await_ready() const { return true; } + void await_suspend (coroutine_handle<>) {} + ret_type await_resume() { return {}; } +}; + +task +my_coro () +{ + ret_type r2{co_await awaiter{}}; + //ret_type r3 (std::move(r2)); +} + +int main() +{ + auto x = my_coro (); + return 0; +} |