diff gcc/cp/lambda.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
line wrap: on
line diff
--- a/gcc/cp/lambda.c	Fri Oct 27 22:46:09 2017 +0900
+++ b/gcc/cp/lambda.c	Thu Oct 25 07:37:49 2018 +0900
@@ -3,7 +3,7 @@
    building RTL.  These routines are used both during actual parsing
    and during the instantiation of template functions.
 
-   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   Copyright (C) 1998-2018 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -30,7 +30,6 @@
 #include "tree-iterator.h"
 #include "toplev.h"
 #include "gimplify.h"
-#include "cp-cilkplus.h"
 
 /* Constructor for a lambda expression.  */
 
@@ -91,7 +90,7 @@
 	val = build_array_copy (val);
       else if (DECL_NORMAL_CAPTURE_P (field)
 	       && !DECL_VLA_CAPTURE_P (field)
-	       && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE)
+	       && !TYPE_REF_P (TREE_TYPE (field)))
 	{
 	  /* "the entities that are captured by copy are used to
 	     direct-initialize each corresponding non-static data
@@ -201,7 +200,7 @@
   if (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
       && !COMPLETE_OR_OPEN_TYPE_P (type))
     return NULL_TREE;
-  lambda = lookup_member (type, cp_operator_id (CALL_EXPR),
+  lambda = lookup_member (type, call_op_identifier,
 			  /*protect=*/0, /*want_type=*/false,
 			  tf_warning_or_error);
   if (lambda)
@@ -245,7 +244,8 @@
     {
       type = non_reference (unlowered_expr_type (expr));
 
-      if (!is_this && by_reference_p)
+      if (!is_this
+	  && (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE))
 	type = build_reference_type (type);
     }
 
@@ -261,6 +261,7 @@
   return (VAR_P (decl)
 	  && DECL_HAS_VALUE_EXPR_P (decl)
 	  && !DECL_ANON_UNION_VAR_P (decl)
+	  && !DECL_DECOMPOSITION_P (decl)
 	  && LAMBDA_FUNCTION_P (DECL_CONTEXT (decl)));
 }
 
@@ -290,6 +291,17 @@
   return DECL_NORMAL_CAPTURE_P (val);
 }
 
+/* Returns true iff DECL is a capture proxy for a normal capture
+   of a constant variable.  */
+
+bool
+is_constant_capture_proxy (tree decl)
+{
+  if (is_normal_capture_proxy (decl))
+    return decl_constant_var_p (DECL_CAPTURED_VARIABLE (decl));
+  return false;
+}
+
 /* VAR is a capture proxy created by build_capture_proxy; add it to the
    current function, which is the operator() for the appropriate lambda.  */
 
@@ -376,7 +388,7 @@
    inside the operator(), build a placeholder var for future lookups and
    debugging.  */
 
-tree
+static tree
 build_capture_proxy (tree member, tree init)
 {
   tree var, object, fn, closure, name, lam, type;
@@ -399,7 +411,7 @@
 
   type = lambda_proxy_type (object);
 
-  if (name == this_identifier && !POINTER_TYPE_P (type))
+  if (name == this_identifier && !INDIRECT_TYPE_P (type))
     {
       type = build_pointer_type (type);
       type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
@@ -420,6 +432,8 @@
       object = convert (type, ptr);
     }
 
+  complete_type (type);
+
   var = build_decl (input_location, VAR_DECL, name, type);
   SET_DECL_VALUE_EXPR (var, object);
   DECL_HAS_VALUE_EXPR_P (var) = 1;
@@ -439,10 +453,12 @@
 	{
 	  if (PACK_EXPANSION_P (init))
 	    init = PACK_EXPANSION_PATTERN (init);
-	  if (TREE_CODE (init) == INDIRECT_REF)
-	    init = TREE_OPERAND (init, 0);
-	  STRIP_NOPS (init);
 	}
+
+      if (INDIRECT_REF_P (init))
+	init = TREE_OPERAND (init, 0);
+      STRIP_NOPS (init);
+
       gcc_assert (VAR_P (init) || TREE_CODE (init) == PARM_DECL);
       while (is_normal_capture_proxy (init))
 	init = DECL_CAPTURED_VARIABLE (init);
@@ -538,13 +554,13 @@
   else if (!dependent_type_p (type)
 	   && variably_modified_type_p (type, NULL_TREE))
     {
-      error ("capture of variable-size type %qT that is not an N3639 array "
+      sorry ("capture of variably-modified type %qT that is not an N3639 array "
 	     "of runtime bound", type);
       if (TREE_CODE (type) == ARRAY_TYPE
 	  && variably_modified_type_p (TREE_TYPE (type), NULL_TREE))
 	inform (input_location, "because the array element type %qT has "
 		"variable size", TREE_TYPE (type));
-      type = error_mark_node;
+      return error_mark_node;
     }
   else
     {
@@ -555,10 +571,9 @@
 
       if (id == this_identifier && !by_reference_p)
 	{
-	  gcc_assert (POINTER_TYPE_P (type));
+	  gcc_assert (INDIRECT_TYPE_P (type));
 	  type = TREE_TYPE (type);
-	  initializer = cp_build_indirect_ref (initializer, RO_NULL,
-					       tf_warning_or_error);
+	  initializer = cp_build_fold_indirect_ref (initializer);
 	}
 
       if (dependent_type_p (type))
@@ -648,6 +663,7 @@
     return build_capture_proxy (member, initializer);
   /* For explicit captures we haven't started the function yet, so we wait
      and build the proxy from cp_parser_lambda_body.  */
+  LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (lambda)) = true;
   return NULL_TREE;
 }
 
@@ -679,14 +695,10 @@
 add_default_capture (tree lambda_stack, tree id, tree initializer)
 {
   bool this_capture_p = (id == this_identifier);
-
   tree var = NULL_TREE;
-
   tree saved_class_type = current_class_type;
 
-  tree node;
-
-  for (node = lambda_stack;
+  for (tree node = lambda_stack;
        node;
        node = TREE_CHAIN (node))
     {
@@ -704,6 +716,19 @@
 				 == CPLD_REFERENCE)),
 			    /*explicit_init_p=*/false);
       initializer = convert_from_reference (var);
+
+      /* Warn about deprecated implicit capture of this via [=].  */
+      if (cxx_dialect >= cxx2a
+	  && this_capture_p
+	  && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_COPY
+	  && !in_system_header_at (LAMBDA_EXPR_LOCATION (lambda)))
+	{
+	  if (warning_at (LAMBDA_EXPR_LOCATION (lambda), OPT_Wdeprecated,
+			  "implicit capture of %qE via %<[=]%> is deprecated "
+			  "in C++20", this_identifier))
+	    inform (LAMBDA_EXPR_LOCATION (lambda), "add explicit %<this%> or "
+		    "%<*this%> capture");
+	}
     }
 
   current_class_type = saved_class_type;
@@ -727,9 +752,7 @@
     add_capture_p = false;
 
   /* Try to default capture 'this' if we can.  */
-  if (!this_capture
-      && (!add_capture_p
-          || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE))
+  if (!this_capture)
     {
       tree lambda_stack = NULL_TREE;
       tree init = NULL_TREE;
@@ -740,26 +763,41 @@
            3. a non-default capturing lambda function.  */
       for (tree tlambda = lambda; ;)
 	{
-          lambda_stack = tree_cons (NULL_TREE,
-                                    tlambda,
-                                    lambda_stack);
+	  if (add_capture_p
+	      && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE)
+	    /* tlambda won't let us capture 'this'.  */
+	    break;
+
+	  if (add_capture_p)
+	    lambda_stack = tree_cons (NULL_TREE,
+				      tlambda,
+				      lambda_stack);
+
+	  tree closure = LAMBDA_EXPR_CLOSURE (tlambda);
+	  tree containing_function
+	    = decl_function_context (TYPE_NAME (closure));
 
-	  if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)
-	      && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL)
+	  tree ex = LAMBDA_EXPR_EXTRA_SCOPE (tlambda);
+	  if (ex && TREE_CODE (ex) == FIELD_DECL)
 	    {
-	      /* In an NSDMI, we don't have a function to look up the decl in,
-		 but the fake 'this' pointer that we're using for parsing is
-		 in scope_chain.  */
-	      init = scope_chain->x_current_class_ptr;
+	      /* Lambda in an NSDMI.  We don't have a function to look up
+		 'this' in, but we can find (or rebuild) the fake one from
+		 inject_this_parameter.  */
+	      if (!containing_function && !COMPLETE_TYPE_P (closure))
+		/* If we're parsing a lambda in a non-local class,
+		   we can find the fake 'this' in scope_chain.  */
+		init = scope_chain->x_current_class_ptr;
+	      else
+		/* Otherwise it's either gone or buried in
+		   function_context_stack, so make another.  */
+		init = build_this_parm (NULL_TREE, DECL_CONTEXT (ex),
+					TYPE_UNQUALIFIED);
 	      gcc_checking_assert
 		(init && (TREE_TYPE (TREE_TYPE (init))
 			  == current_nonlambda_class_type ()));
 	      break;
 	    }
 
-	  tree closure_decl = TYPE_NAME (LAMBDA_EXPR_CLOSURE (tlambda));
-	  tree containing_function = decl_function_context (closure_decl);
-
 	  if (containing_function == NULL_TREE)
 	    /* We ran out of scopes; there's no 'this' to capture.  */
 	    break;
@@ -782,10 +820,6 @@
 	      init = LAMBDA_EXPR_THIS_CAPTURE (tlambda);
 	      break;
 	    }
-
-	  if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE)
-	    /* An outer lambda won't let us capture 'this'.  */
-	    break;
 	}
 
       if (init)
@@ -829,6 +863,20 @@
   return result;
 }
 
+/* Return the innermost LAMBDA_EXPR we're currently in, if any.  */
+
+tree
+current_lambda_expr (void)
+{
+  tree type = current_class_type;
+  while (type && !LAMBDA_TYPE_P (type))
+    type = decl_type_context (TYPE_NAME (type));
+  if (type)
+    return CLASSTYPE_LAMBDA_EXPR (type);
+  else
+    return NULL_TREE;
+}
+
 /* Return the current LAMBDA_EXPR, if this is a resolvable dummy
    object.  NULL otherwise..  */
 
@@ -845,7 +893,7 @@
       && current_class_type
       && LAMBDA_TYPE_P (current_class_type)
       && lambda_function (current_class_type)
-      && DERIVED_FROM_P (type, current_nonlambda_class_type ()))
+      && DERIVED_FROM_P (type, nonlambda_method_basetype()))
     return CLASSTYPE_LAMBDA_EXPR (current_class_type);
 
   return NULL_TREE;
@@ -862,8 +910,7 @@
   if (tree lam = resolvable_dummy_lambda (object))
     if (tree cap = lambda_expr_this_capture (lam, add_capture_p))
       if (cap != error_mark_node)
-	object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
-				       RO_NULL, tf_warning_or_error);
+	object = build_fold_indirect_ref (cap);
 
   return object;
 }
@@ -911,30 +958,37 @@
   return fn;
 }
 
-/* Returns the method basetype of the innermost non-lambda function, or
-   NULL_TREE if none.  */
+/* Returns the method basetype of the innermost non-lambda function, including
+   a hypothetical constructor if inside an NSDMI, or NULL_TREE if none.  */
 
 tree
 nonlambda_method_basetype (void)
 {
-  tree fn, type;
   if (!current_class_ref)
     return NULL_TREE;
 
-  type = current_class_type;
-  if (!LAMBDA_TYPE_P (type))
+  tree type = current_class_type;
+  if (!type || !LAMBDA_TYPE_P (type))
     return type;
 
-  /* Find the nearest enclosing non-lambda function.  */
-  fn = TYPE_NAME (type);
-  do
-    fn = decl_function_context (fn);
-  while (fn && LAMBDA_FUNCTION_P (fn));
+  while (true)
+    {
+      tree lam = CLASSTYPE_LAMBDA_EXPR (type);
+      tree ex = LAMBDA_EXPR_EXTRA_SCOPE (lam);
+      if (ex && TREE_CODE (ex) == FIELD_DECL)
+	/* Lambda in an NSDMI.  */
+	return DECL_CONTEXT (ex);
 
-  if (!fn || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
-    return NULL_TREE;
-
-  return TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
+      tree fn = TYPE_CONTEXT (type);
+      if (!fn || TREE_CODE (fn) != FUNCTION_DECL
+	  || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+	/* No enclosing non-lambda method.  */
+	return NULL_TREE;
+      if (!LAMBDA_FUNCTION_P (fn))
+	/* Found an enclosing non-lambda method.  */
+	return TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
+      type = DECL_CONTEXT (fn);
+    }
 }
 
 /* Like current_scope, but looking through lambdas.  */
@@ -987,121 +1041,6 @@
 	  && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (callop)));
 }
 
-/* Returns true iff we need to consider default capture for an enclosing
-   generic lambda.  */
-
-bool
-need_generic_capture (void)
-{
-  if (!processing_template_decl)
-    return false;
-
-  tree outer_closure = NULL_TREE;
-  for (tree t = current_class_type; t;
-       t = decl_type_context (TYPE_MAIN_DECL (t)))
-    {
-      tree lam = CLASSTYPE_LAMBDA_EXPR (t);
-      if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE)
-	/* No default capture.  */
-	break;
-      outer_closure = t;
-    }
-
-  if (!outer_closure)
-    /* No lambda.  */
-    return false;
-  else if (dependent_type_p (outer_closure))
-    /* The enclosing context isn't instantiated.  */
-    return false;
-  else
-    return true;
-}
-
-/* A lambda-expression...is said to implicitly capture the entity...if the
-   compound-statement...names the entity in a potentially-evaluated
-   expression where the enclosing full-expression depends on a generic lambda
-   parameter declared within the reaching scope of the lambda-expression.  */
-
-static tree
-dependent_capture_r (tree *tp, int *walk_subtrees, void *data)
-{
-  hash_set<tree> *pset = (hash_set<tree> *)data;
-
-  if (TYPE_P (*tp))
-    *walk_subtrees = 0;
-
-  if (outer_automatic_var_p (*tp))
-    {
-      tree t = process_outer_var_ref (*tp, tf_warning_or_error, /*force*/true);
-      if (t != *tp
-	  && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
-	  && TREE_CODE (TREE_TYPE (*tp)) != REFERENCE_TYPE)
-	t = convert_from_reference (t);
-      *tp = t;
-    }
-
-  if (pset->add (*tp))
-    *walk_subtrees = 0;
-
-  switch (TREE_CODE (*tp))
-    {
-      /* Don't walk into unevaluated context or another lambda.  */
-    case SIZEOF_EXPR:
-    case ALIGNOF_EXPR:
-    case TYPEID_EXPR:
-    case NOEXCEPT_EXPR:
-    case LAMBDA_EXPR:
-      *walk_subtrees = 0;
-      break;
-
-      /* Don't walk into statements whose subexpressions we already
-	 handled.  */
-    case TRY_BLOCK:
-    case EH_SPEC_BLOCK:
-    case HANDLER:
-    case IF_STMT:
-    case FOR_STMT:
-    case RANGE_FOR_STMT:
-    case WHILE_STMT:
-    case DO_STMT:
-    case SWITCH_STMT:
-    case STATEMENT_LIST:
-    case RETURN_EXPR:
-      *walk_subtrees = 0;
-      break;
-
-    case DECL_EXPR:
-      {
-	tree decl = DECL_EXPR_DECL (*tp);
-	if (VAR_P (decl))
-	  {
-	    /* walk_tree_1 won't step in here.  */
-	    cp_walk_tree (&DECL_INITIAL (decl),
-			  dependent_capture_r, &pset, NULL);
-	    *walk_subtrees = 0;
-	  }
-      }
-      break;
-
-    default:
-      break;
-    }
-
-  return NULL_TREE;
-}
-
-tree
-do_dependent_capture (tree expr, bool force)
-{
-  if (!need_generic_capture ()
-      || (!force && !instantiation_dependent_expression_p (expr)))
-    return expr;
-
-  hash_set<tree> pset;
-  cp_walk_tree (&expr, dependent_capture_r, &pset, NULL);
-  return expr;
-}
-
 /* If the closure TYPE has a static op(), also add a conversion to function
    pointer.  */
 
@@ -1154,8 +1093,7 @@
 	 return expression for a deduced return call op to allow for simple
 	 implementation of the conversion operator.  */
 
-      tree instance = cp_build_indirect_ref (thisarg, RO_NULL,
-					     tf_warning_or_error);
+      tree instance = cp_build_fold_indirect_ref (thisarg);
       tree objfn = build_min (COMPONENT_REF, NULL_TREE,
 			      instance, DECL_NAME (callop), NULL_TREE);
       int nargs = list_length (DECL_ARGUMENTS (callop)) - 1;
@@ -1220,7 +1158,6 @@
       }
   }
 
-
   if (generic_lambda_p)
     {
       if (decltype_call)
@@ -1255,10 +1192,10 @@
   tree thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST);
   tree fntype = build_method_type_directly (thistype, rettype, void_list_node);
   tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype);
+  SET_DECL_LANGUAGE (convfn, lang_cplusplus);
   tree fn = convfn;
   DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
   SET_DECL_ALIGN (fn, MINIMUM_METHOD_BOUNDARY);
-  SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR);
   grokclassfn (type, fn, NO_SPECIAL);
   set_linkage_according_to_type (type, fn);
   rest_of_decl_compilation (fn, namespace_bindings_p (), at_eof);
@@ -1286,8 +1223,8 @@
 
   /* Now build up the thunk to be returned.  */
 
-  name = get_identifier ("_FUN");
-  tree statfn = build_lang_decl (FUNCTION_DECL, name, stattype);
+  tree statfn = build_lang_decl (FUNCTION_DECL, fun_identifier, stattype);
+  SET_DECL_LANGUAGE (statfn, lang_cplusplus);
   fn = statfn;
   DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop);
   grokclassfn (type, fn, NO_SPECIAL);
@@ -1312,11 +1249,9 @@
     fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
 
   if (flag_sanitize & SANITIZE_NULL)
-    {
-      /* Don't UBsan this function; we're deliberately calling op() with a null
-	 object argument.  */
-      add_no_sanitize_value (fn, SANITIZE_UNDEFINED);
-    }
+    /* Don't UBsan this function; we're deliberately calling op() with a null
+       object argument.  */
+    add_no_sanitize_value (fn, SANITIZE_UNDEFINED);
 
   add_method (type, fn, false);
 
@@ -1453,6 +1388,24 @@
   LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
 }
 
+/* This lambda is an instantiation of a lambda in a template default argument
+   that got no LAMBDA_EXPR_EXTRA_SCOPE, so this shouldn't either.  But we do
+   need to use and increment the global count to avoid collisions.  */
+
+void
+record_null_lambda_scope (tree lambda)
+{
+  if (vec_safe_is_empty (lambda_scope_stack))
+    record_lambda_scope (lambda);
+  else
+    {
+      tree_int *p = lambda_scope_stack->begin();
+      LAMBDA_EXPR_EXTRA_SCOPE (lambda) = p->t;
+      LAMBDA_EXPR_DISCRIMINATOR (lambda) = p->i++;
+    }
+  gcc_assert (LAMBDA_EXPR_EXTRA_SCOPE (lambda) == NULL_TREE);
+}
+
 void
 finish_lambda_scope (void)
 {
@@ -1484,11 +1437,120 @@
   return body;
 }
 
+/* Subroutine of prune_lambda_captures: CAP is a node in
+   LAMBDA_EXPR_CAPTURE_LIST.  Return the variable it captures for which we
+   might optimize away the capture, or NULL_TREE if there is no such
+   variable.  */
+
+static tree
+var_to_maybe_prune (tree cap)
+{
+  if (LAMBDA_CAPTURE_EXPLICIT_P (cap))
+    /* Don't prune explicit captures.  */
+    return NULL_TREE;
+
+  tree mem = TREE_PURPOSE (cap);
+  if (!DECL_P (mem) || !DECL_NORMAL_CAPTURE_P (mem))
+    /* Packs and init-captures aren't captures of constant vars.  */
+    return NULL_TREE;
+
+  tree init = TREE_VALUE (cap);
+  if (is_normal_capture_proxy (init))
+    init = DECL_CAPTURED_VARIABLE (init);
+  if (decl_constant_var_p (init))
+    return init;
+
+  return NULL_TREE;
+}
+
+/* walk_tree helper for prune_lambda_captures: Remember which capture proxies
+   for constant variables are actually used in the lambda body.
+
+   There will always be a DECL_EXPR for the capture proxy; remember it when we
+   see it, but replace it with any other use.  */
+
+static tree
+mark_const_cap_r (tree *t, int *walk_subtrees, void *data)
+{
+  hash_map<tree,tree*> &const_vars = *(hash_map<tree,tree*>*)data;
+
+  tree var = NULL_TREE;
+  if (TREE_CODE (*t) == DECL_EXPR)
+    {
+      tree decl = DECL_EXPR_DECL (*t);
+      if (is_constant_capture_proxy (decl))
+	var = DECL_CAPTURED_VARIABLE (decl);
+      *walk_subtrees = 0;
+    }
+  else if (is_constant_capture_proxy (*t))
+    var = DECL_CAPTURED_VARIABLE (*t);
+
+  if (var)
+    {
+      tree *&slot = const_vars.get_or_insert (var);
+      if (!slot || VAR_P (*t))
+	slot = t;
+    }
+
+  return NULL_TREE;
+}
+
+/* We're at the end of processing a lambda; go back and remove any captures of
+   constant variables for which we've folded away all uses.  */
+
+static void
+prune_lambda_captures (tree body)
+{
+  tree lam = current_lambda_expr ();
+  if (!LAMBDA_EXPR_CAPTURE_OPTIMIZED (lam))
+    /* No uses were optimized away.  */
+    return;
+  if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE)
+    /* No default captures, and we don't prune explicit captures.  */
+    return;
+
+  hash_map<tree,tree*> const_vars;
+
+  cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars);
+
+  tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam));
+  for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; )
+    {
+      tree cap = *capp;
+      if (tree var = var_to_maybe_prune (cap))
+	{
+	  tree **use = const_vars.get (var);
+	  if (use && TREE_CODE (**use) == DECL_EXPR)
+	    {
+	      /* All uses of this capture were folded away, leaving only the
+		 proxy declaration.  */
+
+	      /* Splice the capture out of LAMBDA_EXPR_CAPTURE_LIST.  */
+	      *capp = TREE_CHAIN (cap);
+
+	      /* And out of TYPE_FIELDS.  */
+	      tree field = TREE_PURPOSE (cap);
+	      while (*fieldp != field)
+		fieldp = &DECL_CHAIN (*fieldp);
+	      *fieldp = DECL_CHAIN (*fieldp);
+
+	      /* And remove the capture proxy declaration.  */
+	      **use = void_node;
+	      continue;
+	    }
+	}
+
+      capp = &TREE_CHAIN (cap);
+    }
+}
+
 void
 finish_lambda_function (tree body)
 {
   finish_function_body (body);
 
+  prune_lambda_captures (body);
+
   /* Finish the function and generate code for it if necessary.  */
   tree fn = finish_function (/*inline_p=*/true);