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 <ju...@linux.alibaba.com> * coroutines.cc (maybe_promote_captured_temps): Do not strip cleanup_point_stmt. gcc/testsuite 2020-02-11 Jun Ma <ju...@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 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()); + }; +} -- 2.19.1.3.ge56e4f7