diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 0c2ec32d7db..1bc2ed7f89c 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1790,6 +1790,11 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
 	  cp_walk_tree (&DECL_SIZE (lvar), transform_local_var_uses, d, NULL);
 	  cp_walk_tree (&DECL_SIZE_UNIT (lvar), transform_local_var_uses, d,
 			NULL);
+	  if (DECL_HAS_VALUE_EXPR_P (lvar))
+	    {
+	      tree t  = DECL_VALUE_EXPR (lvar);
+	      cp_walk_tree (&t, transform_local_var_uses, d, NULL);
+	    }
 
 	  /* TODO: implement selective generation of fields when vars are
 	     known not-used.  */
@@ -1815,9 +1820,9 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
 	  gcc_checking_assert (existed);
 
 	  if (local_var.field_id == NULL_TREE)
-	    pvar = &DECL_CHAIN (*pvar); /* Wasn't used.  */
-
-	  *pvar = DECL_CHAIN (*pvar); /* discard this one, we replaced it.  */
+	    pvar = &DECL_CHAIN (*pvar); /* Wasn't used or was an alias.  */
+	  else
+	    *pvar = DECL_CHAIN (*pvar); /* discard this one, we replaced it.  */
 	}
 
       *do_subtree = 0; /* We've done the body already.  */
@@ -1847,8 +1852,16 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
   if (local_var_i == NULL)
     return NULL_TREE;
 
-  /* This is our revised 'local' i.e. a frame slot.  */
-  tree revised = local_var_i->field_idx;
+  /* This is our revised 'local' i.e. a frame slot or an alias.  */
+  tree revised  = NULL_TREE;
+  if (local_var_i->field_id == NULL_TREE)
+    {
+      gcc_checking_assert (DECL_HAS_VALUE_EXPR_P (var_decl));
+      /* If the decl is an alias for another expression, substitute it.  */
+      revised = DECL_VALUE_EXPR (var_decl);
+    }
+  else
+    revised = local_var_i->field_idx;
   gcc_checking_assert (DECL_CONTEXT (var_decl) == lvd->context);
 
   if (decl_expr_p && DECL_INITIAL (var_decl))
@@ -2796,6 +2809,12 @@ register_param_uses (tree *stmt, int *do_subtree ATTRIBUTE_UNUSED, void *d)
 {
   param_frame_data *data = (param_frame_data *) d;
 
+  if (VAR_P (*stmt) && DECL_HAS_VALUE_EXPR_P (*stmt))
+    {
+      tree x = DECL_VALUE_EXPR (*stmt);
+      cp_walk_tree (&x, register_param_uses, d, NULL);
+    }
+
   if (TREE_CODE (*stmt) != PARM_DECL)
     return NULL_TREE;
 
@@ -2840,7 +2859,6 @@ struct local_vars_frame_data
 {
   tree *field_list;
   hash_map<tree, local_var_info> *local_var_uses;
-  vec<local_var_info> *captures;
   unsigned int nest_depth, bind_indx;
   location_t loc;
   bool saw_capture;
@@ -2869,26 +2887,27 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
 	  local_var_info &local_var
 	    = lvd->local_var_uses->get_or_insert (lvar, &existed);
 	  gcc_checking_assert (!existed);
+	  /* For var as an alias, just leave it.  */
+	  if (DECL_HAS_VALUE_EXPR_P (lvar))
+	    continue;
 	  tree lvtype = TREE_TYPE (lvar);
 	  tree lvname = DECL_NAME (lvar);
-	  bool captured = is_normal_capture_proxy (lvar);
 	  /* Make names depth+index unique, so that we can support nested
 	     scopes with identically named locals.  */
 	  char *buf;
 	  size_t namsize = sizeof ("__lv...") + 18;
-	  const char *nm = (captured ? "cp" : "lv");
 	  if (lvname != NULL_TREE)
 	    {
 	      namsize += IDENTIFIER_LENGTH (lvname);
 	      buf = (char *) alloca (namsize);
-	      snprintf (buf, namsize, "__%s.%u.%u.%s", nm, lvd->bind_indx,
+	      snprintf (buf, namsize, "__lv.%u.%u.%s", lvd->bind_indx,
 			lvd->nest_depth, IDENTIFIER_POINTER (lvname));
 	    }
 	  else
 	    {
 	      namsize += 10; /* 'D' followed by an unsigned.  */
 	      buf = (char *) alloca (namsize);
-	      snprintf (buf, namsize, "__%s.%u.%u.D%u", nm, lvd->bind_indx,
+	      snprintf (buf, namsize, "__lv.%u.%u.D%u", lvd->bind_indx,
 			lvd->nest_depth, DECL_UID (lvar));
 	    }
 	  /* TODO: Figure out if we should build a local type that has any
@@ -2898,15 +2917,6 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d)
 	  local_var.def_loc = DECL_SOURCE_LOCATION (lvar);
 	  local_var.frame_type = lvtype;
 	  local_var.field_idx = NULL_TREE;
-	  if (captured)
-	    {
-	      gcc_checking_assert (DECL_INITIAL (lvar) == NULL_TREE);
-	      local_var.captured = lvar;
-	      lvd->captures->safe_push (local_var);
-	      lvd->saw_capture = true;
-	    }
-	  else
-	    local_var.captured = NULL;
 	  lvd->local_var_seen = true;
 	  /* We don't walk any of the local var sub-trees, they won't contain
 	     any bind exprs.  */
@@ -3177,10 +3187,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
   /* 4. Now make space for local vars, this is conservative again, and we
      would expect to delete unused entries later.  */
   hash_map<tree, local_var_info> local_var_uses;
-  auto_vec<local_var_info> captures;
 
   local_vars_frame_data local_vars_data
-    = {&field_list, &local_var_uses, &captures, 0, 0, fn_start, false, false};
+    = {&field_list, &local_var_uses, 0, 0, fn_start, false, false};
   cp_walk_tree (&fnbody, register_local_var_uses, &local_vars_data, NULL);
 
   /* Tie off the struct for now, so that we can build offsets to the
@@ -3202,16 +3211,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
   tree coro_fp = build_lang_decl (VAR_DECL, get_identifier ("coro.frameptr"),
 				  coro_frame_ptr);
   tree varlist = coro_fp;
-  local_var_info *cap;
-  if (!captures.is_empty())
-    for (int ix = 0; captures.iterate (ix, &cap); ix++)
-      {
-	if (cap->field_id == NULL_TREE)
-	  continue;
-	tree t = cap->captured;
-	DECL_CHAIN (t) = varlist;
-	varlist = t;
-      }
 
   /* Collected the scope vars we need ... only one for now. */
   BIND_EXPR_VARS (ramp_bind) = nreverse (varlist);
@@ -3477,62 +3476,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer)
 	}
     }
 
-  vec<tree, va_gc> *captures_dtor_list = NULL;
-  while (!captures.is_empty())
-    {
-      local_var_info cap = captures.pop();
-      if (cap.field_id == NULL_TREE)
-	continue;
-
-      tree fld_ref = lookup_member (coro_frame_type, cap.field_id,
-				    /*protect=*/1, /*want_type=*/0,
-				    tf_warning_or_error);
-      tree fld_idx
-	= build_class_member_access_expr (deref_fp, fld_ref, NULL_TREE,
-					  false, tf_warning_or_error);
-
-      tree cap_type = cap.frame_type;
-
-      /* When we have a reference, we do not want to change the referenced
-	 item, but actually to set the reference to the proxy var.  */
-      if (REFERENCE_REF_P (fld_idx))
-	fld_idx = TREE_OPERAND (fld_idx, 0);
-
-      if (TYPE_NEEDS_CONSTRUCTING (cap_type))
-	{
-	  vec<tree, va_gc> *p_in;
-	      if (TYPE_REF_P (cap_type)
-		  && (CLASSTYPE_LAZY_MOVE_CTOR (cap_type)
-		      || CLASSTYPE_LAZY_MOVE_ASSIGN (cap_type)
-		      || classtype_has_move_assign_or_move_ctor_p
-			    (cap_type, /*user_declared=*/true)))
-	    p_in = make_tree_vector_single (rvalue (cap.captured));
-	  else
-	    p_in = make_tree_vector_single (cap.captured);
-	  /* Construct in place or move as relevant.  */
-	  r = build_special_member_call (fld_idx, complete_ctor_identifier,
-					 &p_in, cap_type, LOOKUP_NORMAL,
-					 tf_warning_or_error);
-	  release_tree_vector (p_in);
-	  if (captures_dtor_list == NULL)
-	    captures_dtor_list = make_tree_vector ();
-	  vec_safe_push (captures_dtor_list, cap.field_id);
-	}
-      else
-	{
-	  if (!same_type_p (cap_type, TREE_TYPE (cap.captured)))
-	    r = build1_loc (DECL_SOURCE_LOCATION (cap.captured), CONVERT_EXPR,
-			    cap_type, cap.captured);
-	  else
-	    r = cap.captured;
-	  r = build_modify_expr (fn_start, fld_idx, cap_type,
-				 INIT_EXPR, DECL_SOURCE_LOCATION (cap.captured),
-				 r, TREE_TYPE (r));
-	}
-      r = coro_build_cvt_void_expr_stmt (r, fn_start);
-      add_stmt (r);
-    }
-
   /* Set up a new bind context for the GRO.  */
   tree gro_context_bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
   /* Make and connect the scope blocks.  */
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/lambda-07-multi-capture.C b/gcc/testsuite/g++.dg/coroutines/torture/lambda-07-multi-capture.C
new file mode 100644
index 00000000000..fb760472368
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/lambda-07-multi-capture.C
@@ -0,0 +1,55 @@
+//  { dg-do run }
+
+// lambda with parm and local state
+
+#include "../coro.h"
+
+// boiler-plate for tests of codegen
+#include "../coro1-ret-int-yield-int.h"
+
+int main ()
+{
+  int a_copy = 20;
+
+  auto f = [&a_ref = a_copy, a_copy = a_copy + 10]() -> coro1
+  {
+    a_ref += 20;
+    co_return a_ref + a_copy;
+  };
+
+  {
+    coro1 A = f ();
+    A.handle.resume();
+    if (a_copy != 40)
+      {
+        PRINT ("main: [a_copy = 40]");
+	abort ();
+      }
+  
+    int y = A.handle.promise().get_value();
+    if (y != 70)
+      {
+	PRINTF ("main: A co-ret = %d, should be 30\n", y);
+	abort ();
+      }
+  }
+
+  a_copy = 5;
+
+  coro1 B = f ();
+  B.handle.resume();
+  if (a_copy != 25)
+    {
+      PRINT ("main: [a_copy = 25]");
+      abort ();
+    }
+
+  int y = B.handle.promise().get_value();
+  if (y != 55)
+    {
+      PRINTF ("main: B co-ret = %d, should be 55\n", y);
+      abort ();
+    }
+  
+  return 0;
+}
