[coroutines] Do not strip cleanup_point when promote temporaries out of current stmt
diff mbox series

Message ID b68838b2-bed8-f998-2bb3-bf2771ef0be3@linux.alibaba.com
State New
Headers show
Series
  • [coroutines] Do not strip cleanup_point when promote temporaries out of current stmt
Related show

Commit Message

JunMa Feb. 11, 2020, 2:14 a.m. UTC
Hi
In maybe_promote_captured_temps, the cleanup_point_stmt has been
stripped when handle temporaries captured by reference. However, maybe
there are non-reference temporaries in current stmt which cause ice in
gimpilify pass.

This patch fix this. The testcase comes from cppcoro and is reduced by
creduce.

Bootstrap and test on X86_64, is it OK?

Regards
JunMa

gcc/cp
2020-02-11  Jun Ma <JunMa@linux.alibaba.com>

         * coroutines.cc (maybe_promote_captured_temps): Do not strip
         cleanup_point_stmt.

gcc/testsuite
2020-02-11  Jun Ma <JunMa@linux.alibaba.com>

         * g++.dg/coroutines/torture/lambda-09-capture-object.C: New test.
---
 gcc/cp/coroutines.cc                          |   8 +-
 .../torture/lambda-09-capture-object.C        | 132 ++++++++++++++++++
 2 files changed, 135 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/coroutines/torture/lambda-09-capture-object.C

Patch
diff mbox series

diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 9fcbb647201..3095b46ecb1 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -2681,11 +2681,9 @@  maybe_promote_captured_temps (tree *stmt, void *d)
       location_t sloc = EXPR_LOCATION (*stmt);
       tree aw_bind
 	= build3_loc (sloc, BIND_EXPR, void_type_node, NULL, NULL, NULL);
-      tree aw_statement_current;
-      if (TREE_CODE (*stmt) == CLEANUP_POINT_EXPR)
-	aw_statement_current = TREE_OPERAND (*stmt, 0);
-      else
-	aw_statement_current = *stmt;
+      /* Do not skip cleanup_point since maybe there are other temporaries
+         need cleanup.  */
+      tree aw_statement_current = *stmt;
       /* Collected the scope vars we need move the temps to regular. */
       tree aw_bind_body = push_stmt_list ();
       tree varlist = NULL_TREE;
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-09-capture-object.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-09-capture-object.C
new file mode 100644
index 00000000000..1297b72cc8f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-09-capture-object.C
@@ -0,0 +1,132 @@ 
+//  { dg-do compile }
+//  { dg-additional-options "-Wno-return-type" }
+
+#include "../coro.h"
+#include <tuple>
+#include <functional>
+
+template <typename, typename = std::void_t<>> struct a;
+template <typename b>
+struct a<b, std::void_t<decltype(std::declval<b>().await_resume())>>
+    : std::conjunction<> {};
+template <typename b>
+auto c(b value, int) -> decltype(value.operator co_await());
+template <typename b, std::enable_if_t<a<b>::value, int> = 0> b c(b, int);
+template <typename b> auto d(b value) -> decltype(c(value, 3)) {}
+template <typename b> struct f {
+  using e = decltype(d(std::declval<b>()));
+  using h = decltype(std::declval<e>().await_resume());
+};
+template <typename> class s;
+template <typename... g> class s<std::tuple<g...>> {
+public:
+  s(std::tuple<g...>);
+  auto operator co_await() {
+    struct aa {
+      std::tuple<g...> await_resume() {};
+      s i;
+    };
+    return aa{*this};
+  }
+};
+template <typename j> class k {
+public:
+  using l = std::coroutine_handle<k>;
+  j m();
+};
+template <typename j> class ab {
+public:
+  using promise_type = k<j>;
+  using l = typename promise_type::l;
+  auto m() { return n.promise().m(); }
+  auto ac() { return m(); }
+  l n;
+};
+template <typename o, typename j = typename f<o>::h,
+          std::enable_if_t<!std::is_void_v<j>, int> = 0>
+ab<j> p(o);
+template <typename b> struct u { using ad = b; };
+template <typename b> using t = typename u<b>::ad;
+template <typename... ae, std::enable_if_t<std::conjunction_v<>, int> = 0>
+auto af(ae... ag) {
+  return s<std::tuple<ab<typename f<t<std::remove_reference_t<ae>>>::h>...>>(
+      std::make_tuple(p(ag)...));
+}
+template <typename q, typename o> class ah {
+  using e = typename f<o>::e;
+
+public:
+  ah(q ai, o aj) : r(ai), ak(d(aj)) {}
+  auto await_ready() { return 0; }
+  template <typename v> auto await_suspend(std::coroutine_handle<v>) {}
+  template <typename w = decltype(0),
+            std::enable_if_t<!std::is_void_v<w>, int> = 0>
+  auto await_resume() {
+    return invoke(r, ak.await_resume());
+  }
+  q r;
+  e ak;
+};
+template <typename q, typename o> class x {
+public:
+  template <typename y, typename al,
+            std::enable_if_t<std::is_constructible_v<o, al>, int> = 0>
+  x(y ai, al aj) : r(ai), i(aj) {}
+  auto operator co_await() { return ah(r, i); }
+  q r;
+  o i;
+};
+template <typename q, typename o> auto am(q ai, o aj) {
+  return x<std::remove_cv_t<std::remove_reference_t<q>>,
+           std::remove_cv_t<std::remove_reference_t<o>>>(ai, aj);
+}
+template <typename... ae, std::enable_if_t<std::conjunction_v<>, int> = 0>
+auto an(ae... ag) {
+  return am(
+      [](auto ao) {
+        auto ap =
+            apply([](auto... aq) { return std::make_tuple(aq.ac()...); }, ao);
+        return ap;
+      },
+      af(ag...));
+}
+class ar;
+class z {
+public:
+  ar as();
+};
+class at {
+public:
+  ~at();
+};
+class ar {
+public:
+  at await_resume();
+};
+class au;
+class av {
+  struct aw {
+    bool await_ready();
+    template <typename v> void await_suspend(std::coroutine_handle<v>);
+    void await_resume();
+  };
+
+public:
+  auto initial_suspend() { return std::suspend_always{}; }
+  auto final_suspend() { return aw{}; }
+};
+class ax : public av {
+public:
+  au get_return_object();
+  void unhandled_exception();
+};
+class au {
+public:
+  using promise_type = ax;
+};
+void d() {
+  []() -> au {
+    z ay;
+    co_await an(ay.as());
+  };
+}