coroutines: Fix handling of target cleanup exprs [PR94883]

Message ID 7446DE66-1B94-4EA3-A524-49B49758E80E@sandoe.co.uk
State New
Headers show
Series
  • coroutines: Fix handling of target cleanup exprs [PR94883]
Related show

Commit Message

Iain Sandoe April 30, 2020, 12:53 p.m.
Hi

Another case found building folly’s experimental coros tests.
tested on x86_64-darwin, linux, powerpc64-linux
OK for master?
thanks
Iain

----

The problem here is that target cleanup expressions have been
added to the initialisers for the awaitable (and returns of
non-trivial values from await_suspend() calls).  This is because
the expansion of the co_await into its control flow is not
apparent to the machinery adding the target cleanup expressions.
The solution being tested is simply to recreate target expressions
as the co_awaits are lowered.  Teaching the machinery to handle
walking co_await expressions in different ways at different points
(outside the coroutine transformation) seems overly complex.

gcc/cp/ChangeLog:

2020-04-30  Iain Sandoe  <iain@sandoe.co.uk>

	PR c++/94883
	* coroutines.cc (register_awaits): Update target
	expressions for awaitable and suspend handle
	initializers.

gcc/testsuite/ChangeLog:

2020-04-30  Iain Sandoe  <iain@sandoe.co.uk>

	PR c++/94883
	* g++.dg/coroutines/pr94883-folly-2.C: New test.
---
 gcc/cp/coroutines.cc                          | 11 ++++
 .../g++.dg/coroutines/pr948xx-folly-2.C       | 64 +++++++++++++++++++
 2 files changed, 75 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/coroutines/pr948xx-folly-2.C

-- 
2.24.1

Comments

Nathan Sidwell April 30, 2020, 1:43 p.m. | #1
On 4/30/20 8:53 AM, Iain Sandoe wrote:

> The problem here is that target cleanup expressions have been

> added to the initialisers for the awaitable (and returns of

> non-trivial values from await_suspend() calls).  This is because

> the expansion of the co_await into its control flow is not

> apparent to the machinery adding the target cleanup expressions.

> The solution being tested is simply to recreate target expressions

> as the co_awaits are lowered.  Teaching the machinery to handle

> walking co_await expressions in different ways at different points

> (outside the coroutine transformation) seems overly complex.


ok


-- 
Nathan Sidwell

Patch

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 7bb3e98fe6c..3bff2c7dbdc 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -2754,6 +2754,17 @@  register_awaits (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d)
       free (nam);
     }
 
+  tree o = TREE_OPERAND (aw_expr, 2); /* Initialiser for the frame var.  */
+  /* If this is a target expression, then we need to remake it to strip off
+     any extra cleanups added.  */
+  if (TREE_CODE (o) == TARGET_EXPR)
+    TREE_OPERAND (aw_expr, 2) = get_target_expr (TREE_OPERAND (o, 1));
+
+  tree v = TREE_OPERAND (aw_expr, 3);
+  o = TREE_VEC_ELT (v, 1);
+  if (TREE_CODE (o) == TARGET_EXPR)
+    TREE_VEC_ELT (v, 1) = get_target_expr (TREE_OPERAND (o, 1));
+
   register_await_info (aw_expr, aw_field_type, aw_field_nam);
 
   /* Count how many awaits the current expression contains.  */
diff --git a/gcc/testsuite/g++.dg/coroutines/pr948xx-folly-2.C b/gcc/testsuite/g++.dg/coroutines/pr948xx-folly-2.C
new file mode 100644
index 00000000000..088f1335493
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr948xx-folly-2.C
@@ -0,0 +1,64 @@ 
+
+namespace std {
+template <typename a, typename...> struct coroutine_traits : a {};
+template <typename = void> struct coroutine_handle;
+template <> struct coroutine_handle<> {};
+template <typename> struct coroutine_handle : coroutine_handle<> {};
+struct b {
+  bool await_ready();
+  void await_suspend(coroutine_handle<>);
+  void await_resume();
+};
+} // namespace std
+
+template <typename d> auto ab(int ac, d ad) -> decltype(ad.e(ac));
+int f;
+class h {
+  class j {
+  public:
+    bool await_ready();
+    void await_suspend(std::coroutine_handle<>);
+    void await_resume();
+  };
+
+public:
+  void get_return_object();
+  std::b initial_suspend();
+  j final_suspend();
+  void unhandled_exception();
+  template <typename g> 
+    auto await_transform (g c) { return ab(f, c); }
+};
+template <typename, typename = int> class k {
+public:
+  using promise_type = h;
+  using i = std::coroutine_handle<>;
+  class l {
+  public:
+    ~l();
+    operator bool();
+  };
+  class m {
+  public:
+    bool await_ready();
+    i await_suspend(std::coroutine_handle<>);
+    l await_resume();
+  };
+  class n {
+  public:
+    m e(int);
+  };
+  n ah();
+};
+
+template <typename ai, typename aj, typename ak>
+k<aj> 
+my_coro (k<aj, ak> am, ai) {
+  if (auto an = co_await am.ah())
+    ;
+}
+
+void foo () {
+  k<int> a;
+  my_coro (a, [] {});
+}