semantics.c (outer_lambda_capture_p): New fn.
* semantics.c (outer_lambda_capture_p): New fn. (thisify_lambda_field): Factor out... (add_default_capture): ...from here. (finish_id_expression): Use them. From-SVN: r153510
This commit is contained in:
parent
78dd7466f8
commit
9660afe042
4 changed files with 81 additions and 16 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
31
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C
Normal file
31
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C
Normal file
|
@ -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
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue