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.
This commit is contained in:
JunMa 2020-02-11 16:01:08 +08:00
parent c46da87b9d
commit 7f327e8765
4 changed files with 123 additions and 5 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

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