TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX)
ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
ABI_TAG_IMPLICIT (in the TREE_LIST for the argument of abi_tag)
+ LAMBDA_CAPTURE_EXPLICIT_P (in a TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST)
CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR)
LAMBDA_EXPR_CAPTURES_THIS_P (in LAMBDA_EXPR)
DECLTYPE_FOR_LAMBDA_CAPTURE (in DECLTYPE_TYPE)
CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR)
OVL_HIDDEN_P (in OVERLOAD)
SWITCH_STMT_NO_BREAK_P (in SWITCH_STMT)
+ LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
#define LAMBDA_EXPR_MUTABLE_P(NODE) \
TREE_LANG_FLAG_1 (LAMBDA_EXPR_CHECK (NODE))
+/* True iff uses of a const variable capture were optimized away. */
+#define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \
+ TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
+
+/* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit
+ capture. */
+#define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \
+ TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
+
/* The source location of the lambda. */
#define LAMBDA_EXPR_LOCATION(NODE) \
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->locus)
extern void insert_pending_capture_proxies (void);
extern bool is_capture_proxy (tree);
extern bool is_normal_capture_proxy (tree);
+extern bool is_constant_capture_proxy (tree);
extern void register_capture_members (tree);
extern tree lambda_expr_this_capture (tree, bool);
extern void maybe_generic_this_capture (tree, tree);
extern tree current_nonlambda_function (void);
extern tree nonlambda_method_basetype (void);
extern tree current_nonlambda_scope (void);
+extern tree current_lambda_expr (void);
extern bool generic_lambda_fn_p (tree);
extern tree do_dependent_capture (tree, bool = false);
extern bool lambda_fn_in_template_p (tree);
tree cap = DECL_CAPTURED_VARIABLE (expr);
if (TREE_CODE (TREE_TYPE (cap)) == TREE_CODE (TREE_TYPE (expr))
&& decl_constant_var_p (cap))
- return RECUR (cap);
+ {
+ tree val = RECUR (cap);
+ if (!is_capture_proxy (val))
+ {
+ tree l = current_lambda_expr ();
+ LAMBDA_EXPR_CAPTURE_OPTIMIZED (l) = true;
+ }
+ return val;
+ }
}
if (outer_automatic_var_p (expr)
&& decl_constant_var_p (expr))
tree cap = DECL_CAPTURED_VARIABLE (ref);
if (TREE_CODE (TREE_TYPE (cap)) != REFERENCE_TYPE
&& decl_constant_var_p (cap))
- return RECUR (cap);
+ {
+ tree val = RECUR (cap);
+ if (!is_capture_proxy (val))
+ {
+ tree l = current_lambda_expr ();
+ LAMBDA_EXPR_CAPTURE_OPTIMIZED (l) = true;
+ }
+ return val;
+ }
}
tree r = mark_rvalue_use (ref, loc, reject_builtin);
if (r != ref)
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. */
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;
}
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.. */
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 (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);