aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2009-10-23 18:08:18 +0000
committerJason Merrill <jason@redhat.com>2009-10-23 18:08:18 +0000
commit4305ca1e7fb07a4366633371d39928486f440d40 (patch)
tree051c608ab728620701b9c69fbbb4409d799cf03c
parent3c6454217c757cd055e82b15a8aa7014d885ac36 (diff)
* semantics.c (outer_lambda_capture_p): New fn.
(thisify_lambda_field): Factor out... (add_default_capture): ...from here. (finish_id_expression): Use them. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@153510 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/semantics.c59
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C31
4 files changed, 81 insertions, 16 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 49a5ad2f4fd..e0bf4f2e6de 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,10 @@
2009-10-23 Jason Merrill <jason@redhat.com>
+ * semantics.c (outer_lambda_capture_p): New fn.
+ (thisify_lambda_field): Factor out...
+ (add_default_capture): ...from here.
+ (finish_id_expression): Use them.
+
Core issue 899
* call.c (add_function_candidate): Only permit explicit conversion
ops if copy ctor was called with a single argument.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 6cf22204a5e..3e39f3765e1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see
static tree maybe_convert_cond (tree);
static tree finalize_nrv_r (tree *, int *, void *);
static tree capture_decltype (tree);
+static tree thisify_lambda_field (tree);
/* Deferred Access Checking Overview
@@ -1447,14 +1448,13 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
return error_mark_node;
}
- /* If decl is a field, object has a lambda type, and decl is not a member
- of that type, then we have a reference to a member of 'this' from a
+ /* If decl is a non-capture field and object has a lambda type,
+ then we have a reference to a member of 'this' from a
lambda inside a non-static member function, and we must get to decl
through the 'this' capture. If decl is not a member of that object,
either, then its access will still fail later. */
if (LAMBDA_TYPE_P (TREE_TYPE (object))
- && !same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (decl),
- TREE_TYPE (object)))
+ && !LAMBDA_TYPE_P (DECL_CONTEXT (decl)))
object = cp_build_indirect_ref (lambda_expr_this_capture
(CLASSTYPE_LAMBDA_EXPR
(TREE_TYPE (object))),
@@ -2648,6 +2648,18 @@ outer_automatic_var_p (tree decl)
&& DECL_CONTEXT (decl) != current_function_decl);
}
+/* Returns true iff DECL is a capture field from a lambda that is not our
+ immediate context. */
+
+static bool
+outer_lambda_capture_p (tree decl)
+{
+ return (TREE_CODE (decl) == FIELD_DECL
+ && LAMBDA_TYPE_P (DECL_CONTEXT (decl))
+ && (!current_class_type
+ || !DERIVED_FROM_P (DECL_CONTEXT (decl), current_class_type)));
+}
+
/* ID_EXPRESSION is a representation of parsed, but unprocessed,
id-expression. (See cp_parser_id_expression for details.) SCOPE,
if non-NULL, is the type or namespace used to explicitly qualify
@@ -2751,7 +2763,8 @@ finish_id_expression (tree id_expression,
/* Disallow uses of local variables from containing functions, except
within lambda-expressions. */
- if (outer_automatic_var_p (decl)
+ if ((outer_automatic_var_p (decl)
+ || outer_lambda_capture_p (decl))
/* It's not a use (3.2) if we're in an unevaluated context. */
&& !cp_unevaluated_operand)
{
@@ -2759,6 +2772,7 @@ finish_id_expression (tree id_expression,
tree containing_function = current_function_decl;
tree lambda_stack = NULL_TREE;
tree lambda_expr = NULL_TREE;
+ tree initializer = decl;
/* Core issue 696: "[At the July 2009 meeting] the CWG expressed
support for an approach in which a reference to a local
@@ -2770,6 +2784,13 @@ finish_id_expression (tree id_expression,
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
return integral_constant_value (decl);
+ if (TYPE_P (context))
+ {
+ /* Implicit capture of an explicit capture. */
+ context = lambda_function (context);
+ initializer = thisify_lambda_field (decl);
+ }
+
/* If we are in a lambda function, we can move out until we hit
1. the context,
2. a non-lambda function, or
@@ -2796,7 +2817,7 @@ finish_id_expression (tree id_expression,
{
decl = add_default_capture (lambda_stack,
/*id=*/DECL_NAME (decl),
- /*initializer=*/decl);
+ initializer);
}
else if (lambda_expr)
{
@@ -5604,6 +5625,21 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
return member;
}
+/* Given a FIELD_DECL decl belonging to a closure type, return a
+ COMPONENT_REF of it relative to the 'this' parameter of the op() for
+ that type. */
+
+static tree
+thisify_lambda_field (tree decl)
+{
+ tree context = lambda_function (DECL_CONTEXT (decl));
+ tree object = cp_build_indirect_ref (DECL_ARGUMENTS (context),
+ /*errorstring*/"",
+ tf_warning_or_error);
+ return finish_non_static_data_member (decl, object,
+ /*qualifying_scope*/NULL_TREE);
+}
+
/* Similar to add_capture, except this works on a stack of nested lambdas.
BY_REFERENCE_P in this case is derived from the default capture mode.
Returns the capture for the lambda at the bottom of the stack. */
@@ -5634,16 +5670,7 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
&& (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
== CPLD_REFERENCE)),
/*explicit_init_p=*/false);
-
- {
- /* Have to get the old value of current_class_ref. */
- tree object = cp_build_indirect_ref (DECL_ARGUMENTS
- (lambda_function (lambda)),
- /*errorstring=*/"",
- /*complain=*/tf_warning_or_error);
- initializer = finish_non_static_data_member
- (member, object, /*qualifying_scope=*/NULL_TREE);
- }
+ initializer = thisify_lambda_field (member);
}
current_class_type = saved_class_type;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f42dd32ebda..4d6eb811876 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,7 @@
2009-10-23 Jason Merrill <jason@redhat.com>
+ * g++.dg/cpp0x/lambda/lambda-nested2.C: New.
+
Core issue 899
* g++.dg/cpp0x/explicit4.C: New.
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C
new file mode 100644
index 00000000000..b7887485595
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C
@@ -0,0 +1,31 @@
+// Testcase from N2998
+// { dg-options -std=c++0x }
+
+void f1(int i) {
+ int const N = 20;
+ auto m1 = [=]{
+ int const M = 30;
+ auto m2 = [i]{
+ int x[N][M]; // OK: N and M are not "used"
+ x[0][0] = i; // OK: i is explicitly captured by m2
+ // and implicitly captured by m1
+ };
+ };
+ struct s1 {
+ int f;
+ int work(int n) {
+ int m = n*n;
+ int j = 40;
+ auto m3 = [this,m]{
+ /*auto m4=*/[&,j]{ // { dg-error "j. is not captured" }
+ int x = n; // { dg-error "n. is not captured" }
+ x += m; // OK: m implicitly captured by m4
+ // and explicitly captured by m3
+ x += i; // { dg-error "i. is not captured" }
+ x += f; // OK: this captured implicitly by m4
+ // and explicitly by m3
+ };
+ };
+ }
+ };
+}