Use local_specializations to find capture proxies.
authorJason Merrill <jason@redhat.com>
Thu, 28 Sep 2017 19:39:38 +0000 (15:39 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 28 Sep 2017 19:39:38 +0000 (15:39 -0400)
* cp-tree.h (DECL_CAPTURED_VARIABLE): New.
* lambda.c (build_capture_proxy): Set it.
(add_capture): Pass initializer to build_capture_proxy.
(start_lambda_function): Likewise.
(insert_capture_proxy): Use register_local_specialization.
(is_lambda_ignored_entity): Always ignore proxies.
* name-lookup.c (qualify_lookup): Don't check
is_lambda_ignored_entity if LOOKUP_HIDDEN is set.
* semantics.c (process_outer_var_ref): Use
retrieve_local_specialization.
* parser.c (cp_parser_lambda_body): Push local_specializations.
* pt.c (tsubst_expr): Pass LOOKUP_HIDDEN when looking for a proxy.
(tsubst_lambda_expr): Push local_specializations sooner.
(tsubst_copy_and_build): Don't register_local_specialization.

From-SVN: r253265

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/lambda.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c

index eeea726..2936f22 100644 (file)
@@ -1,5 +1,21 @@
 2017-09-28  Jason Merrill  <jason@redhat.com>
 
+       Use local_specializations to find capture proxies.
+       * cp-tree.h (DECL_CAPTURED_VARIABLE): New.
+       * lambda.c (build_capture_proxy): Set it.
+       (add_capture): Pass initializer to build_capture_proxy.
+       (start_lambda_function): Likewise.
+       (insert_capture_proxy): Use register_local_specialization.
+       (is_lambda_ignored_entity): Always ignore proxies.
+       * name-lookup.c (qualify_lookup): Don't check
+       is_lambda_ignored_entity if LOOKUP_HIDDEN is set.
+       * semantics.c (process_outer_var_ref): Use
+       retrieve_local_specialization.
+       * parser.c (cp_parser_lambda_body): Push local_specializations.
+       * pt.c (tsubst_expr): Pass LOOKUP_HIDDEN when looking for a proxy.
+       (tsubst_lambda_expr): Push local_specializations sooner.
+       (tsubst_copy_and_build): Don't register_local_specialization.
+
        * call.c (build_special_member_call): Use the return value of
        mark_lvalue_use.
        * decl.c (compute_array_index_type): Likewise.
index 7c1c54c..a634901 100644 (file)
@@ -2471,10 +2471,12 @@ struct GTY(()) lang_decl_min {
   union lang_decl_u2 {
     /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
        THUNK_VIRTUAL_OFFSET.
+       In a VAR_DECL for which DECL_HAS_VALUE_EXPR_P holds,
+       this is DECL_CAPTURED_VARIABLE.
        Otherwise this is DECL_ACCESS.  */
     tree GTY ((tag ("0"))) access;
 
-    /* For VAR_DECL in function, this is DECL_DISCRIMINATOR.  */
+    /* For TREE_STATIC VAR_DECL in function, this is DECL_DISCRIMINATOR.  */
     int GTY ((tag ("1"))) discriminator;
   } GTY ((desc ("%0.u.base.u2sel"))) u2;
 };
@@ -3240,6 +3242,10 @@ extern void decl_shadowed_for_var_insert (tree, tree);
   (DECL_LANG_SPECIFIC (VAR_TEMPL_TYPE_FIELD_OR_FUNCTION_DECL_CHECK (NODE)) \
    ->u.min.template_info)
 
+/* For a lambda capture proxy, its captured variable.  */
+#define DECL_CAPTURED_VARIABLE(NODE) \
+  (LANG_DECL_U2_CHECK (NODE, 0)->access)
+
 /* For a VAR_DECL, indicates that the variable is actually a
    non-static data member of anonymous union that has been promoted to
    variable status.  */
@@ -6793,7 +6799,7 @@ extern tree lambda_function                       (tree);
 extern void apply_deduced_return_type           (tree, tree);
 extern tree add_capture                         (tree, tree, tree, bool, bool);
 extern tree add_default_capture                 (tree, tree, tree);
-extern tree build_capture_proxy                        (tree);
+extern tree build_capture_proxy                        (tree, tree);
 extern void insert_capture_proxy               (tree);
 extern void insert_pending_capture_proxies     (void);
 extern bool is_capture_proxy                   (tree);
index 695666a..66d510e 100644 (file)
@@ -296,6 +296,9 @@ is_normal_capture_proxy (tree decl)
 void
 insert_capture_proxy (tree var)
 {
+  if (is_normal_capture_proxy (var))
+    register_local_specialization (var, DECL_CAPTURED_VARIABLE (var));
+
   /* Put the capture proxy in the extra body block so that it won't clash
      with a later local variable.  */
   pushdecl_outermost_localscope (var);
@@ -364,7 +367,7 @@ lambda_proxy_type (tree ref)
    debugging.  */
 
 tree
-build_capture_proxy (tree member)
+build_capture_proxy (tree member, tree init)
 {
   tree var, object, fn, closure, name, lam, type;
 
@@ -414,6 +417,29 @@ build_capture_proxy (tree member)
   TREE_USED (var) = 1;
   DECL_CONTEXT (var) = fn;
 
+  if (DECL_NORMAL_CAPTURE_P (member))
+    {
+      if (DECL_VLA_CAPTURE_P (member))
+       {
+         init = CONSTRUCTOR_ELT (init, 0)->value;
+         init = TREE_OPERAND (init, 0); // Strip ADDR_EXPR.
+         init = TREE_OPERAND (init, 0); // Strip ARRAY_REF.
+       }
+      else
+       {
+         if (PACK_EXPANSION_P (init))
+           init = PACK_EXPANSION_PATTERN (init);
+         if (TREE_CODE (init) == INDIRECT_REF)
+           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);
+      retrofit_lang_decl (var);
+      DECL_CAPTURED_VARIABLE (var) = init;
+    }
+
   if (name == this_identifier)
     {
       gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member);
@@ -609,7 +635,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
     = tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
 
   if (LAMBDA_EXPR_CLOSURE (lambda))
-    return build_capture_proxy (member);
+    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.  */
   return NULL_TREE;
@@ -1243,8 +1269,8 @@ lambda_static_thunk_p (tree fn)
 bool
 is_lambda_ignored_entity (tree val)
 {
-  /* In unevaluated context, look past normal capture proxies.  */
-  if (cp_unevaluated_operand && is_normal_capture_proxy (val))
+  /* Look past normal capture proxies.  */
+  if (is_normal_capture_proxy (val))
     return true;
 
   /* Always ignore lambda fields, their names are only for debugging.  */
@@ -1325,7 +1351,7 @@ start_lambda_function (tree fco, tree lambda_expr)
   /* Push the proxies for any explicit captures.  */
   for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
        cap = TREE_CHAIN (cap))
-    build_capture_proxy (TREE_PURPOSE (cap));
+    build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap));
 
   return body;
 }
index a3a124b..6763a5b 100644 (file)
@@ -5296,7 +5296,7 @@ qualify_lookup (tree val, int flags)
   if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
     return false;
   /* Look through lambda things that we shouldn't be able to see.  */
-  if (is_lambda_ignored_entity (val))
+  if (!(flags & LOOKUP_HIDDEN) && is_lambda_ignored_entity (val))
     return false;
   return true;
 }
index bb2a877..f22c2c0 100644 (file)
@@ -10560,6 +10560,8 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
      + function_definition_after_declarator
      + ctor_initializer_opt_and_function_body  */
   {
+    local_specialization_stack s (lss_copy);
+
     tree fco = lambda_function (lambda_expr);
     tree body = start_lambda_function (fco, lambda_expr);
     bool done = false;
index f12ab26..2bdac6d 100644 (file)
@@ -15986,7 +15986,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
          {
            /* We're in tsubst_lambda_expr, we've already inserted a new
               capture proxy, so look it up and register it.  */
-           tree inst = lookup_name (DECL_NAME (decl));
+           tree inst = lookup_name_real (DECL_NAME (decl), 0, 0,
+                                         /*block_p=*/true, 0, LOOKUP_HIDDEN);
            gcc_assert (inst != decl && is_capture_proxy (inst));
            register_local_specialization (inst, decl);
            break;
@@ -16906,10 +16907,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       if (nested)
        push_function_context ();
 
-      tree body = start_lambda_function (fn, r);
-
       local_specialization_stack s (lss_copy);
 
+      tree body = start_lambda_function (fn, r);
+
       register_parameter_specializations (oldfn, fn);
 
       tsubst_expr (DECL_SAVED_TREE (oldfn), args, complain, r,
@@ -18136,11 +18137,7 @@ tsubst_copy_and_build (tree t,
              r = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
          }
        else if (outer_automatic_var_p (r))
-         {
-           r = process_outer_var_ref (r, complain);
-           if (is_capture_proxy (r) && !DECL_PACK_P (t))
-             register_local_specialization (r, t);
-         }
+         r = process_outer_var_ref (r, complain);
 
        if (TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
          /* If the original type was a reference, we'll be wrapped in
index 3a3ae55..4e87e47 100644 (file)
@@ -3303,16 +3303,19 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
   if (parsing_nsdmi ())
     containing_function = NULL_TREE;
 
-  if (containing_function && DECL_TEMPLATE_INFO (context)
-      && LAMBDA_FUNCTION_P (containing_function))
-    {
-      /* Check whether we've already built a proxy;
-        insert_pending_capture_proxies doesn't update
-        local_specializations.  */
-      tree d = lookup_name (DECL_NAME (decl));
-      if (d && is_capture_proxy (d)
-         && DECL_CONTEXT (d) == containing_function)
-       return d;
+  if (containing_function && LAMBDA_FUNCTION_P (containing_function))
+    {
+      /* Check whether we've already built a proxy.  */
+      tree d = retrieve_local_specialization (decl);
+      if (d && is_capture_proxy (d))
+       {
+         if (DECL_CONTEXT (d) == containing_function)
+           /* We already have an inner proxy.  */
+           return d;
+         else
+           /* We need to capture an outer proxy.  */
+           return process_outer_var_ref (d, complain);
+       }
     }
 
   /* If we are in a lambda function, we can move out until we hit