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:
Jason Merrill 2009-10-23 14:08:18 -04:00 committed by Jason Merrill
parent 78dd7466f8
commit 9660afe042
4 changed files with 81 additions and 16 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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.

View 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
};
};
}
};
}