aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/lambda.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/lambda.c')
-rw-r--r--gcc/cp/lambda.c130
1 files changed, 129 insertions, 1 deletions
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 78bd89782aa..76f2f29578f 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -297,7 +297,17 @@ void
insert_capture_proxy (tree var)
{
if (is_normal_capture_proxy (var))
- register_local_specialization (var, DECL_CAPTURED_VARIABLE (var));
+ {
+ tree cap = DECL_CAPTURED_VARIABLE (var);
+ if (CHECKING_P)
+ {
+ gcc_assert (!is_normal_capture_proxy (cap));
+ tree old = retrieve_local_specialization (cap);
+ if (old)
+ gcc_assert (DECL_CONTEXT (old) != DECL_CONTEXT (var));
+ }
+ register_local_specialization (var, cap);
+ }
/* Put the capture proxy in the extra body block so that it won't clash
with a later local variable. */
@@ -977,6 +987,121 @@ generic_lambda_fn_p (tree callop)
&& 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. */
@@ -1073,7 +1198,10 @@ maybe_add_lambda_conv_op (tree type)
if (generic_lambda_p)
{
+ /* Avoid capturing variables in this context. */
+ ++cp_unevaluated_operand;
tree a = forward_parm (tgt);
+ --cp_unevaluated_operand;
CALL_EXPR_ARG (call, ix) = a;
if (decltype_call)