coroutines: Fix for uses of structured binding [PR94701]
authorIain Sandoe <iain@sandoe.co.uk>
Mon, 27 Apr 2020 22:55:00 +0000 (23:55 +0100)
committerIain Sandoe <iain@sandoe.co.uk>
Mon, 27 Apr 2020 22:58:07 +0000 (23:58 +0100)
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.

gcc/cp/ChangeLog
gcc/cp/coroutines.cc
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/coroutines/torture/local-var-06-structured-binding.C [new file with mode: 0644]

index 2b44b24461fd228d9093160fa7720c01d0df2fcf..ae67a3e6c63361273f9442e15040fdbbc0bfe355 100644 (file)
@@ -1,3 +1,12 @@
+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>
 
        PR c++/90750
index 0a5a0c9b1d201a3bbb2fae19a1c42d29f9c0163b..36229c77b4e7212332e27c889d62982c4d32ed45 100644 (file)
@@ -1774,6 +1774,8 @@ struct local_var_info
   tree field_idx;
   tree frame_type;
   bool is_lambda_capture;
+  bool is_static;
+  bool has_value_expr_p;
   location_t def_loc;
 };
 
@@ -1819,7 +1821,7 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
                        NULL);
 
        /* 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);
            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)
 
          /* Leave lambda closure captures alone, we replace the *this
             pointer with the frame version and let the normal process
-            deal with the rest.  */
-         if (local_var.is_lambda_capture)
-           {
-             pvar = &DECL_CHAIN (*pvar);
-             continue;
-           }
-
-         /* It's not used, but we can let the optimizer deal with that.  */
-         if (local_var.field_id == NULL_TREE)
+            deal with the rest.
+            Likewise, variables with their value found elsewhere.
+            Skip past unused ones too.  */
+         if (local_var.is_lambda_capture
+            || local_var.has_value_expr_p
+            || local_var.field_id == NULL_TREE)
            {
              pvar = &DECL_CHAIN (*pvar);
              continue;
@@ -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
      temporaries.  Skip past these, we will handle them later.  */
   local_var_info *local_var_i = lvd->local_var_uses->get (var_decl);
+
   if (local_var_i == NULL)
     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;
 
   /* 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)
          tree lvtype = TREE_TYPE (lvar);
          local_var.frame_type = lvtype;
          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;
          /* 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
@@ -3398,6 +3410,12 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
          if (local_var.is_lambda_capture)
            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
             scopes with identically named locals.  */
          tree lvname = DECL_NAME (lvar);
index bc4d09b204807a401a37dcc4e0254ee371e2b7ec..b6e2f4f819f66f2e666b205a85a936f29f2cdc79 100644 (file)
@@ -1,3 +1,9 @@
+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>
 
        PR fortran/93956
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/local-var-06-structured-binding.C b/gcc/testsuite/g++.dg/coroutines/torture/local-var-06-structured-binding.C
new file mode 100644 (file)
index 0000000..ef3ff47
--- /dev/null
@@ -0,0 +1,55 @@
+//  { 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 ();
+}