From 5c263e84ab7e5df28a9055ae533c2d305f4b7b3d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 28 Sep 2017 15:39:38 -0400 Subject: [PATCH] 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. From-SVN: r253265 --- gcc/cp/ChangeLog | 16 ++++++++++++++++ gcc/cp/cp-tree.h | 10 ++++++++-- gcc/cp/lambda.c | 36 +++++++++++++++++++++++++++++++----- gcc/cp/name-lookup.c | 2 +- gcc/cp/parser.c | 2 ++ gcc/cp/pt.c | 13 +++++-------- gcc/cp/semantics.c | 23 +++++++++++++---------- 7 files changed, 76 insertions(+), 26 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index eeea726afdb..2936f22a47e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,21 @@ 2017-09-28 Jason Merrill + 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. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7c1c54c78b5..a6349019543 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 695666abbe3..66d510e6818 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -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; } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index a3a124b9ce2..6763a5b9c68 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bb2a8774aa0..f22c2c091dc 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f12ab2605d8..2bdac6de6c4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 3a3ae55aa44..4e87e47d9b3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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 -- 2.30.2