]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
coroutines: Fix handling of target cleanup exprs [PR94883]
authorIain Sandoe <iain@sandoe.co.uk>
Wed, 29 Apr 2020 18:46:35 +0000 (19:46 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Thu, 30 Apr 2020 14:58:48 +0000 (15:58 +0100)
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/ChangeLog
gcc/cp/coroutines.cc
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C [new file with mode: 0644]

index 3172f949ee9b3204e50334d10cc1230c74447c9a..62f997eb4592e96bb9bdef4dc4a7101724adb82e 100644 (file)
@@ -1,3 +1,10 @@
+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.
+
 2020-04-30  Iain Sandoe  <iain@sandoe.co.uk>
 
        PR c++/94879
index e2dbeabf48b0f2a32a5669d7154da81f7ab8b18e..cb9074e4c170b4df86e462ad19ea0240020d84f1 100644 (file)
@@ -2757,6 +2757,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.  */
index 7f39eda02779ddc316c9d5d31e67e8463095d20a..369ce423fbcfefb56fb5624d999461ce3f082999 100644 (file)
@@ -1,3 +1,8 @@
+2020-04-30  Iain Sandoe  <iain@sandoe.co.uk>
+
+       PR c++/94883
+       * g++.dg/coroutines/pr94883-folly-2.C: New test.
+
 2020-04-30  Iain Sandoe  <iain@sandoe.co.uk>
 
        PR c++/94879
diff --git a/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C b/gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C
new file mode 100644 (file)
index 0000000..088f133
--- /dev/null
@@ -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, [] {});
+}