diff options
-rw-r--r-- | gcc/cp/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 59 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C | 31 |
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 + }; + }; + } + }; +} |