From 7f327e8765c25552a1a6ae7d8747f74786f243dd Mon Sep 17 00:00:00 2001 From: JunMa Date: Tue, 11 Feb 2020 16:01:08 +0800 Subject: [PATCH] coroutines: Handle component_ref in captures_temporary gcc/cp * coroutines.cc (captures_temporary): Strip component_ref to its base object. gcc/testsuite * g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C: New test. --- gcc/cp/ChangeLog | 5 + gcc/cp/coroutines.cc | 20 +++- gcc/testsuite/ChangeLog | 4 + .../torture/co-await-15-capture-comp-ref.C | 99 +++++++++++++++++++ 4 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e776110f8ee..7c22aeaaedc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -7,6 +7,11 @@ 2020-03-03 Jun Ma + * coroutines.cc (captures_temporary): Strip component_ref + to its base object. + +2020-03-03 Jun Ma + * coroutines.cc (finish_co_await_expr): Build co_await_expr with unknown_type_node. (finish_co_yield_expr): Ditto. diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 966ec0583aa..bca4f1eeeae 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2613,12 +2613,22 @@ captures_temporary (tree *stmt, int *do_subtree, void *d) continue; parm = TREE_OPERAND (parm, 0); - if (TREE_CODE (parm) == VAR_DECL && !DECL_ARTIFICIAL (parm)) - /* This isn't a temporary... */ - continue; - if (TREE_CODE (parm) == PARM_DECL) - /* .. nor is this... */ + /* In case of component_ref, we need to capture the object of base + class as if it is temporary object. There are two possibilities: + (*base).field and base->field. */ + while (TREE_CODE (parm) == COMPONENT_REF) + { + parm = TREE_OPERAND (parm, 0); + if (TREE_CODE (parm) == INDIRECT_REF) + parm = TREE_OPERAND (parm, 0); + parm = STRIP_NOPS (parm); + } + + /* This isn't a temporary. */ + if ((TREE_CODE (parm) == VAR_DECL && !DECL_ARTIFICIAL (parm)) + || TREE_CODE (parm) == PARM_DECL + || TREE_CODE (parm) == NON_LVALUE_EXPR) continue; if (TREE_CODE (parm) == TARGET_EXPR) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index db579e36974..fdc7768f93e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -29,6 +29,10 @@ * gcc.c-torture/compile/pr93927-1.c: New test. * gcc.c-torture/compile/pr93927-2.c: New test. +2020-03-03 Jun Ma + + * g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C: New test. + 2020-03-03 Jun Ma * g++.dg/coroutines/torture/co-await-14-template-traits.C: New test. diff --git a/gcc/testsuite/g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C b/gcc/testsuite/g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C new file mode 100644 index 00000000000..93a43fbd298 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C @@ -0,0 +1,99 @@ +// { dg-do run } + +#include "../coro.h" + +class resumable { +public: + struct promise_type; + using coro_handle = std::coroutine_handle; + resumable(coro_handle handle) : handle_(handle) { } + resumable(resumable&) = delete; + resumable(resumable&&) = delete; + ~resumable() { handle_.destroy(); } + coro_handle handle_; +}; + +struct resumable::promise_type { + using coro_handle = std::coroutine_handle; + int used; + auto get_return_object() { + return coro_handle::from_promise(*this); + } + auto initial_suspend() { return std::suspend_never(); } + auto final_suspend() { return std::suspend_always(); } + void return_value(int x) {used = x;} + void unhandled_exception() {} + + struct TestAwaiter { + int recent_test; + TestAwaiter(int test) : recent_test{test} {} + bool await_ready() { return false; } + void await_suspend(std::coroutine_handle) {} + int await_resume() { + return recent_test; + } + auto operator co_await() { + return *this; + } + }; + + struct TestAwaiterCH :TestAwaiter { + TestAwaiterCH(int test) : TestAwaiter(test) {}; + }; + + struct TestAwaiterCHCH :TestAwaiterCH { + TestAwaiterCHCH(int test) : TestAwaiterCH(test) {}; + + resumable foo(){ + int x = co_await *this; + co_return x; + } + }; +}; + +struct TestP { + resumable::promise_type::TestAwaiterCHCH tp = resumable::promise_type::TestAwaiterCHCH(6); +}; + +resumable foo1(int t){ + int x = co_await resumable::promise_type::TestAwaiterCH(t); + co_return x; +} + +resumable foo2(){ + struct TestP TP; + int x = co_await TP.tp; + co_return x; +} + +resumable foo3(){ + int x = co_await TestP{}.tp; + co_return x; +} + +int main(){ + auto t = resumable::promise_type::TestAwaiterCHCH(4); + resumable res = t.foo(); + while (!res.handle_.done()) + res.handle_.resume(); + if (res.handle_.promise().used != 4) + abort(); + + resumable res1 = foo1(5); + while (!res1.handle_.done()) + res1.handle_.resume(); + if (res1.handle_.promise().used != 5) + abort(); + + resumable res2 = foo2(); + while (!res2.handle_.done()) + res2.handle_.resume(); + if (res2.handle_.promise().used != 6) + abort(); + + resumable res3 = foo2(); + while (!res3.handle_.done()) + res3.handle_.resume(); + if (res3.handle_.promise().used != 6) + abort(); +}