aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJunMa <JunMa@linux.alibaba.com>2020-02-11 16:01:08 +0800
committerJunMa <JunMa@linux.alibaba.com>2020-03-04 09:08:37 +0800
commit7f327e8765c25552a1a6ae7d8747f74786f243dd (patch)
treeab2c915a426775274fcd03f91a690721d686fdb7 /gcc
parentc46da87b9d35f709dea8d569cdb9a23dec8a4c04 (diff)
downloadgcc-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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/coroutines.cc20
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/coroutines/torture/co-await-15-capture-comp-ref.C99
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();
+}