[gcc/devel/c++-modules] coroutines: Handle component_ref in captures_temporary

Nathan Sidwell nathan@gcc.gnu.org
Tue Mar 10 13:08:21 GMT 2020


https://gcc.gnu.org/g:7f327e8765c25552a1a6ae7d8747f74786f243dd

commit 7f327e8765c25552a1a6ae7d8747f74786f243dd
Author: JunMa <JunMa@linux.alibaba.com>
Date:   Tue Feb 11 16:01:08 2020 +0800

    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.

Diff:
---
 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(-)

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  <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 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 <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.
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<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();
+}


More information about the Gcc-cvs mailing list