* 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
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.
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;
};
(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. */
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);
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);
debugging. */
tree
-build_capture_proxy (tree member)
+build_capture_proxy (tree member, tree init)
{
tree var, object, fn, closure, name, lam, type;
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);
= 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;
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. */
/* 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;
}
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;
}
+ 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;
{
/* 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;
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,
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
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