diff options
author | JunMa <JunMa@linux.alibaba.com> | 2020-02-11 16:01:08 +0800 |
---|---|---|
committer | JunMa <JunMa@linux.alibaba.com> | 2020-03-04 09:08:37 +0800 |
commit | 7f327e8765c25552a1a6ae7d8747f74786f243dd (patch) | |
tree | ab2c915a426775274fcd03f91a690721d686fdb7 | |
parent | c46da87b9d35f709dea8d569cdb9a23dec8a4c04 (diff) | |
download | gcc-7f327e8765c25552a1a6ae7d8747f74786f243dd.zip gcc-7f327e8765c25552a1a6ae7d8747f74786f243dd.tar.gz gcc-7f327e8765c25552a1a6ae7d8747f74786f243dd.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 20 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C | 99 |
4 files changed, 123 insertions, 5 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e776110..7c22aea 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -7,6 +7,11 @@ 2020-03-03 Jun Ma <JunMa@linux.alibaba.com> + * coroutines.cc (captures_temporary): Strip component_ref + to its base object. + +2020-03-03 Jun Ma <JunMa@linux.alibaba.com> + * 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 966ec05..bca4f1e 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 db579e3..fdc7768 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -31,6 +31,10 @@ 2020-03-03 Jun Ma <JunMa@linux.alibaba.com> + * g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C: New test. + +2020-03-03 Jun Ma <JunMa@linux.alibaba.com> + * g++.dg/coroutines/torture/co-await-14-template-traits.C: New test. 2020-03-02 David Malcolm <dmalcolm@redhat.com> 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 0000000..93a43fb --- /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<promise_type>; + 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<promise_type>; + 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<promise_type>) {} + 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(); +} |