Commit 174b6f73 by Iain Sandoe

coroutines: Fix for uses of structured binding [PR94701]

Structured binding makes use of the DECL_VALUE_EXPR fields
in local variables.  We need to recognise these and only amend
the expression values, retaining the 'alias' value intact.

gcc/cp/ChangeLog:

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

	PR c++/94701
	* coroutines.cc (struct local_var_info): Add fields for static
	variables and those with DECL_VALUE_EXPR redirection.
	(transform_local_var_uses):  Skip past typedefs and static vars
	and then account for redirected variables.
	(register_local_var_uses): Likewise.

gcc/testsuite/ChangeLog:

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

	PR c++/94701
	* g++.dg/coroutines/torture/local-var-06-structured-binding.C: New test.
parent d8df7c40
2020-04-27 Iain Sandoe <iain@sandoe.co.uk>
PR c++/94701
* coroutines.cc (struct local_var_info): Add fields for static
variables and those with DECL_VALUE_EXPR redirection.
(transform_local_var_uses): Skip past typedefs and static vars
and then account for redirected variables.
(register_local_var_uses): Likewise.
2020-04-27 Jason Merrill <jason@redhat.com> 2020-04-27 Jason Merrill <jason@redhat.com>
PR c++/90750 PR c++/90750
......
...@@ -1774,6 +1774,8 @@ struct local_var_info ...@@ -1774,6 +1774,8 @@ struct local_var_info
tree field_idx; tree field_idx;
tree frame_type; tree frame_type;
bool is_lambda_capture; bool is_lambda_capture;
bool is_static;
bool has_value_expr_p;
location_t def_loc; location_t def_loc;
}; };
...@@ -1819,7 +1821,7 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d) ...@@ -1819,7 +1821,7 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
NULL); NULL);
/* For capture proxies, this could include the decl value expr. */ /* For capture proxies, this could include the decl value expr. */
if (local_var.is_lambda_capture) if (local_var.is_lambda_capture || local_var.has_value_expr_p)
{ {
tree ve = DECL_VALUE_EXPR (lvar); tree ve = DECL_VALUE_EXPR (lvar);
cp_walk_tree (&ve, transform_local_var_uses, d, NULL); cp_walk_tree (&ve, transform_local_var_uses, d, NULL);
...@@ -1852,15 +1854,12 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d) ...@@ -1852,15 +1854,12 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
/* Leave lambda closure captures alone, we replace the *this /* Leave lambda closure captures alone, we replace the *this
pointer with the frame version and let the normal process pointer with the frame version and let the normal process
deal with the rest. */ deal with the rest.
if (local_var.is_lambda_capture) Likewise, variables with their value found elsewhere.
{ Skip past unused ones too. */
pvar = &DECL_CHAIN (*pvar); if (local_var.is_lambda_capture
continue; || local_var.has_value_expr_p
} || local_var.field_id == NULL_TREE)
/* It's not used, but we can let the optimizer deal with that. */
if (local_var.field_id == NULL_TREE)
{ {
pvar = &DECL_CHAIN (*pvar); pvar = &DECL_CHAIN (*pvar);
continue; continue;
...@@ -1894,10 +1893,13 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d) ...@@ -1894,10 +1893,13 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
for the promise and coroutine handle(s), to global vars or to compiler for the promise and coroutine handle(s), to global vars or to compiler
temporaries. Skip past these, we will handle them later. */ temporaries. Skip past these, we will handle them later. */
local_var_info *local_var_i = lvd->local_var_uses->get (var_decl); local_var_info *local_var_i = lvd->local_var_uses->get (var_decl);
if (local_var_i == NULL) if (local_var_i == NULL)
return NULL_TREE; return NULL_TREE;
if (local_var_i->is_lambda_capture) if (local_var_i->is_lambda_capture
|| local_var_i->is_static
|| local_var_i->has_value_expr_p)
return NULL_TREE; return NULL_TREE;
/* This is our revised 'local' i.e. a frame slot. */ /* This is our revised 'local' i.e. a frame slot. */
...@@ -3390,6 +3392,16 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) ...@@ -3390,6 +3392,16 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
tree lvtype = TREE_TYPE (lvar); tree lvtype = TREE_TYPE (lvar);
local_var.frame_type = lvtype; local_var.frame_type = lvtype;
local_var.field_idx = local_var.field_id = NULL_TREE; local_var.field_idx = local_var.field_id = NULL_TREE;
/* Make sure that we only present vars to the tests below. */
if (TREE_CODE (lvar) == TYPE_DECL)
continue;
/* We don't move static vars into the frame. */
local_var.is_static = TREE_STATIC (lvar);
if (local_var.is_static)
continue;
lvd->local_var_seen = true; lvd->local_var_seen = true;
/* If this var is a lambda capture proxy, we want to leave it alone, /* If this var is a lambda capture proxy, we want to leave it alone,
and later rewrite the DECL_VALUE_EXPR to indirect through the and later rewrite the DECL_VALUE_EXPR to indirect through the
...@@ -3398,6 +3410,12 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) ...@@ -3398,6 +3410,12 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
if (local_var.is_lambda_capture) if (local_var.is_lambda_capture)
continue; continue;
/* If a variable has a value expression, then that's what needs
to be processed. */
local_var.has_value_expr_p = DECL_HAS_VALUE_EXPR_P (lvar);
if (local_var.has_value_expr_p)
continue;
/* Make names depth+index unique, so that we can support nested /* Make names depth+index unique, so that we can support nested
scopes with identically named locals. */ scopes with identically named locals. */
tree lvname = DECL_NAME (lvar); tree lvname = DECL_NAME (lvar);
......
2020-04-21 Iain Sandoe <iain@sandoe.co.uk>
PR c++/94701
* g++.dg/coroutines/torture/local-var-06-structured-binding.C:
New test.
2020-04-27 Thomas Koenig <tkoenig@gcc.gnu.org> 2020-04-27 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/93956 PR fortran/93956
......
// { dg-do run }
#include "../coro.h"
struct promise;
struct future
{
using promise_type = promise;
};
struct promise
{
template<typename... Args>
promise (Args&... args) {}
coro::suspend_never initial_suspend() { return {}; }
coro::suspend_never final_suspend() { return {}; }
future get_return_object() { return {}; }
void return_value(int) {}
void unhandled_exception() {}
};
struct pair
{
int i;
};
pair
something ()
{
return { 1 };
}
future
my_coro ()
{
auto ret = something ();
if (ret.i != 1)
abort ();
auto [ i ] = something ();
if (i != 1)
abort ();
co_return 1;
}
int main ()
{
my_coro ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment