re PR c++/43912 ([C++0x] lambda debug info does not describe captured variables)
PR c++/43912 Generate proxy VAR_DECLs for better lambda debug info. * cp-tree.h (FUNCTION_NEEDS_BODY_BLOCK): Add lambda operator(). (LAMBDA_EXPR_PENDING_PROXIES): New. (struct tree_lambda_expr): Add pending_proxies. * name-lookup.c (pushdecl_maybe_friend_1): Handle capture shadowing. (qualify_lookup): Use is_lambda_ignored_entity. * parser.c (cp_parser_lambda_expression): Don't adjust field names. Call insert_pending_capture_proxies. (cp_parser_lambda_introducer): Use this_identifier. (cp_parser_lambda_declarator_opt): Call the object parameter of the op() "__closure" instead of "this". (cp_parser_lambda_body): Call build_capture_proxy. * semantics.c (build_capture_proxy, is_lambda_ignored_entity): New. (insert_pending_capture_proxies, insert_capture_proxy): New. (is_normal_capture_proxy, is_capture_proxy): New. (add_capture): Add __ to field names here, return capture proxy. (add_default_capture): Use this_identifier, adjust to expect add_capture to return a capture proxy. (outer_lambda_capture_p, thisify_lambda_field): Remove. (finish_id_expression, lambda_expr_this_capture): Adjust. (build_lambda_expr): Initialize LAMBDA_EXPR_PENDING_PROXIES. * pt.c (tsubst_copy_and_build): Check that LAMBDA_EXPR_PENDING_PROXIES is null. From-SVN: r175158
This commit is contained in:
parent
7e7666aed8
commit
61ca4737a8
11 changed files with 299 additions and 81 deletions
|
@ -1,5 +1,30 @@
|
|||
2011-06-17 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/43912
|
||||
Generate proxy VAR_DECLs for better lambda debug info.
|
||||
* cp-tree.h (FUNCTION_NEEDS_BODY_BLOCK): Add lambda operator().
|
||||
(LAMBDA_EXPR_PENDING_PROXIES): New.
|
||||
(struct tree_lambda_expr): Add pending_proxies.
|
||||
* name-lookup.c (pushdecl_maybe_friend_1): Handle capture shadowing.
|
||||
(qualify_lookup): Use is_lambda_ignored_entity.
|
||||
* parser.c (cp_parser_lambda_expression): Don't adjust field names.
|
||||
Call insert_pending_capture_proxies.
|
||||
(cp_parser_lambda_introducer): Use this_identifier.
|
||||
(cp_parser_lambda_declarator_opt): Call the object parameter
|
||||
of the op() "__closure" instead of "this".
|
||||
(cp_parser_lambda_body): Call build_capture_proxy.
|
||||
* semantics.c (build_capture_proxy, is_lambda_ignored_entity): New.
|
||||
(insert_pending_capture_proxies, insert_capture_proxy): New.
|
||||
(is_normal_capture_proxy, is_capture_proxy): New.
|
||||
(add_capture): Add __ to field names here, return capture proxy.
|
||||
(add_default_capture): Use this_identifier, adjust to expect
|
||||
add_capture to return a capture proxy.
|
||||
(outer_lambda_capture_p, thisify_lambda_field): Remove.
|
||||
(finish_id_expression, lambda_expr_this_capture): Adjust.
|
||||
(build_lambda_expr): Initialize LAMBDA_EXPR_PENDING_PROXIES.
|
||||
* pt.c (tsubst_copy_and_build): Check that LAMBDA_EXPR_PENDING_PROXIES
|
||||
is null.
|
||||
|
||||
* name-lookup.c (pushdecl_maybe_friend_1): Do check for shadowing
|
||||
of artificial locals.
|
||||
|
||||
|
|
|
@ -442,6 +442,8 @@ DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0)
|
|||
none.
|
||||
LAMBDA_EXPR_CAPTURE_LIST holds the capture-list, including `this'.
|
||||
LAMBDA_EXPR_THIS_CAPTURE goes straight to the capture of `this', if it exists.
|
||||
LAMBDA_EXPR_PENDING_PROXIES is a vector of capture proxies which need to
|
||||
be pushed once scope returns to the lambda.
|
||||
LAMBDA_EXPR_MUTABLE_P signals whether this lambda was declared mutable.
|
||||
LAMBDA_EXPR_RETURN_TYPE holds the return type, if it was specified. */
|
||||
DEFTREECODE (LAMBDA_EXPR, "lambda_expr", tcc_exceptional, 0)
|
||||
|
|
|
@ -268,7 +268,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
|
|||
#define BIND_EXPR_BODY_BLOCK(NODE) \
|
||||
TREE_LANG_FLAG_3 (BIND_EXPR_CHECK (NODE))
|
||||
#define FUNCTION_NEEDS_BODY_BLOCK(NODE) \
|
||||
(DECL_CONSTRUCTOR_P (NODE) || DECL_DESTRUCTOR_P (NODE))
|
||||
(DECL_CONSTRUCTOR_P (NODE) || DECL_DESTRUCTOR_P (NODE) \
|
||||
|| LAMBDA_FUNCTION_P (NODE))
|
||||
|
||||
#define STATEMENT_LIST_NO_SCOPE(NODE) \
|
||||
TREE_LANG_FLAG_0 (STATEMENT_LIST_CHECK (NODE))
|
||||
|
@ -661,6 +662,11 @@ enum cp_lambda_default_capture_mode_type {
|
|||
#define LAMBDA_EXPR_DISCRIMINATOR(NODE) \
|
||||
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->discriminator)
|
||||
|
||||
/* During parsing of the lambda, a vector of capture proxies which need
|
||||
to be pushed once we're done processing a nested lambda. */
|
||||
#define LAMBDA_EXPR_PENDING_PROXIES(NODE) \
|
||||
(((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->pending_proxies)
|
||||
|
||||
struct GTY (()) tree_lambda_expr
|
||||
{
|
||||
struct tree_typed typed;
|
||||
|
@ -668,6 +674,7 @@ struct GTY (()) tree_lambda_expr
|
|||
tree this_capture;
|
||||
tree return_type;
|
||||
tree extra_scope;
|
||||
VEC(tree,gc)* pending_proxies;
|
||||
location_t locus;
|
||||
enum cp_lambda_default_capture_mode_type default_capture_mode;
|
||||
int discriminator;
|
||||
|
@ -5450,10 +5457,15 @@ extern tree lambda_function (tree);
|
|||
extern void apply_lambda_return_type (tree, tree);
|
||||
extern tree add_capture (tree, tree, tree, bool, bool);
|
||||
extern tree add_default_capture (tree, tree, tree);
|
||||
extern tree build_capture_proxy (tree);
|
||||
extern void insert_pending_capture_proxies (void);
|
||||
extern bool is_capture_proxy (tree);
|
||||
extern bool is_normal_capture_proxy (tree);
|
||||
extern void register_capture_members (tree);
|
||||
extern tree lambda_expr_this_capture (tree);
|
||||
extern tree nonlambda_method_basetype (void);
|
||||
extern void maybe_add_lambda_conv_op (tree);
|
||||
extern bool is_lambda_ignored_entity (tree);
|
||||
|
||||
/* in tree.c */
|
||||
extern int cp_tree_operand_length (const_tree);
|
||||
|
|
|
@ -13060,7 +13060,8 @@ finish_destructor_body (void)
|
|||
/* Do the necessary processing for the beginning of a function body, which
|
||||
in this case includes member-initializers, but not the catch clauses of
|
||||
a function-try-block. Currently, this means opening a binding level
|
||||
for the member-initializers (in a ctor) and member cleanups (in a dtor). */
|
||||
for the member-initializers (in a ctor), member cleanups (in a dtor),
|
||||
and capture proxies (in a lambda operator()). */
|
||||
|
||||
tree
|
||||
begin_function_body (void)
|
||||
|
|
|
@ -1089,6 +1089,10 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
|
|||
if (TREE_CODE (oldlocal) == PARM_DECL)
|
||||
warning_at (input_location, OPT_Wshadow,
|
||||
"declaration of %q#D shadows a parameter", x);
|
||||
else if (is_capture_proxy (oldlocal))
|
||||
warning_at (input_location, OPT_Wshadow,
|
||||
"declaration of %qD shadows a lambda capture",
|
||||
x);
|
||||
else
|
||||
warning_at (input_location, OPT_Wshadow,
|
||||
"declaration of %qD shadows a previous local",
|
||||
|
@ -4002,13 +4006,8 @@ qualify_lookup (tree val, int flags)
|
|||
return true;
|
||||
if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
|
||||
return false;
|
||||
/* In unevaluated context, look past normal capture fields. */
|
||||
if (cp_unevaluated_operand && TREE_CODE (val) == FIELD_DECL
|
||||
&& DECL_NORMAL_CAPTURE_P (val))
|
||||
return false;
|
||||
/* None of the lookups that use qualify_lookup want the op() from the
|
||||
lambda; they want the one from the enclosing class. */
|
||||
if (TREE_CODE (val) == FUNCTION_DECL && LAMBDA_FUNCTION_P (val))
|
||||
/* Look through lambda things that we shouldn't be able to see. */
|
||||
if (is_lambda_ignored_entity (val))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7396,26 +7396,9 @@ cp_parser_lambda_expression (cp_parser* parser)
|
|||
for (elt = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr);
|
||||
elt; elt = next)
|
||||
{
|
||||
tree field = TREE_PURPOSE (elt);
|
||||
char *buf;
|
||||
|
||||
next = TREE_CHAIN (elt);
|
||||
TREE_CHAIN (elt) = newlist;
|
||||
newlist = elt;
|
||||
|
||||
/* Also add __ to the beginning of the field name so that code
|
||||
outside the lambda body can't see the captured name. We could
|
||||
just remove the name entirely, but this is more useful for
|
||||
debugging. */
|
||||
if (field == LAMBDA_EXPR_THIS_CAPTURE (lambda_expr))
|
||||
/* The 'this' capture already starts with __. */
|
||||
continue;
|
||||
|
||||
buf = (char *) alloca (IDENTIFIER_LENGTH (DECL_NAME (field)) + 3);
|
||||
buf[1] = buf[0] = '_';
|
||||
memcpy (buf + 2, IDENTIFIER_POINTER (DECL_NAME (field)),
|
||||
IDENTIFIER_LENGTH (DECL_NAME (field)) + 1);
|
||||
DECL_NAME (field) = get_identifier (buf);
|
||||
}
|
||||
LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) = newlist;
|
||||
}
|
||||
|
@ -7433,6 +7416,11 @@ cp_parser_lambda_expression (cp_parser* parser)
|
|||
/* This field is only used during parsing of the lambda. */
|
||||
LAMBDA_EXPR_THIS_CAPTURE (lambda_expr) = NULL_TREE;
|
||||
|
||||
/* This lambda shouldn't have any proxies left at this point. */
|
||||
gcc_assert (LAMBDA_EXPR_PENDING_PROXIES (lambda_expr) == NULL);
|
||||
/* And now that we're done, push proxies for an enclosing lambda. */
|
||||
insert_pending_capture_proxies ();
|
||||
|
||||
if (ok)
|
||||
return build_lambda_object (lambda_expr);
|
||||
else
|
||||
|
@ -7499,7 +7487,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
|
|||
{
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
add_capture (lambda_expr,
|
||||
/*id=*/get_identifier ("__this"),
|
||||
/*id=*/this_identifier,
|
||||
/*initializer=*/finish_this_expr(),
|
||||
/*by_reference_p=*/false,
|
||||
explicit_init_p);
|
||||
|
@ -7701,6 +7689,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
|
|||
{
|
||||
DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
|
||||
DECL_ARTIFICIAL (fco) = 1;
|
||||
/* Give the object parameter a different name. */
|
||||
DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure");
|
||||
}
|
||||
|
||||
finish_member_declaration (fco);
|
||||
|
@ -7735,6 +7725,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
|
|||
tree body;
|
||||
bool done = false;
|
||||
tree compound_stmt;
|
||||
tree cap;
|
||||
|
||||
/* Let the front end know that we are going to be defining this
|
||||
function. */
|
||||
|
@ -7748,6 +7739,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
|
|||
if (!cp_parser_require (parser, CPP_OPEN_BRACE, RT_OPEN_BRACE))
|
||||
goto out;
|
||||
|
||||
/* Push the proxies for any explicit captures. */
|
||||
for (cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
|
||||
cap = TREE_CHAIN (cap))
|
||||
build_capture_proxy (TREE_PURPOSE (cap));
|
||||
|
||||
compound_stmt = begin_compound_stmt (0);
|
||||
|
||||
/* 5.1.1.4 of the standard says:
|
||||
|
|
|
@ -13500,7 +13500,8 @@ tsubst_copy_and_build (tree t,
|
|||
= RECUR (LAMBDA_EXPR_CAPTURE_LIST (t));
|
||||
LAMBDA_EXPR_EXTRA_SCOPE (r)
|
||||
= RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t));
|
||||
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE);
|
||||
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
|
||||
&& LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
|
||||
|
||||
/* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
|
||||
determine_visibility (TYPE_NAME (type));
|
||||
|
|
|
@ -54,7 +54,6 @@ 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
|
||||
|
@ -2830,18 +2829,6 @@ 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
|
||||
|
@ -2946,8 +2933,7 @@ finish_id_expression (tree id_expression,
|
|||
|
||||
/* Disallow uses of local variables from containing functions, except
|
||||
within lambda-expressions. */
|
||||
if ((outer_automatic_var_p (decl)
|
||||
|| outer_lambda_capture_p (decl))
|
||||
if (outer_automatic_var_p (decl)
|
||||
/* It's not a use (3.2) if we're in an unevaluated context. */
|
||||
&& !cp_unevaluated_operand)
|
||||
{
|
||||
|
@ -2967,13 +2953,6 @@ finish_id_expression (tree id_expression,
|
|||
if (decl_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
|
||||
|
@ -8122,6 +8101,7 @@ build_lambda_expr (void)
|
|||
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE;
|
||||
LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE;
|
||||
LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE;
|
||||
LAMBDA_EXPR_PENDING_PROXIES (lambda) = NULL;
|
||||
LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE;
|
||||
LAMBDA_EXPR_MUTABLE_P (lambda) = false;
|
||||
return lambda;
|
||||
|
@ -8399,6 +8379,135 @@ capture_decltype (tree decl)
|
|||
return type;
|
||||
}
|
||||
|
||||
/* Returns true iff DECL is a lambda capture proxy variable created by
|
||||
build_capture_proxy. */
|
||||
|
||||
bool
|
||||
is_capture_proxy (tree decl)
|
||||
{
|
||||
return (TREE_CODE (decl) == VAR_DECL
|
||||
&& DECL_HAS_VALUE_EXPR_P (decl)
|
||||
&& !DECL_ANON_UNION_VAR_P (decl)
|
||||
&& LAMBDA_FUNCTION_P (DECL_CONTEXT (decl)));
|
||||
}
|
||||
|
||||
/* Returns true iff DECL is a capture proxy for a normal capture
|
||||
(i.e. without explicit initializer). */
|
||||
|
||||
bool
|
||||
is_normal_capture_proxy (tree decl)
|
||||
{
|
||||
tree val;
|
||||
|
||||
if (!is_capture_proxy (decl))
|
||||
/* It's not a capture proxy. */
|
||||
return false;
|
||||
|
||||
/* It is a capture proxy, is it a normal capture? */
|
||||
val = DECL_VALUE_EXPR (decl);
|
||||
gcc_assert (TREE_CODE (val) == COMPONENT_REF);
|
||||
val = TREE_OPERAND (val, 1);
|
||||
return DECL_NORMAL_CAPTURE_P (val);
|
||||
}
|
||||
|
||||
/* VAR is a capture proxy created by build_capture_proxy; add it to the
|
||||
current function, which is the operator() for the appropriate lambda. */
|
||||
|
||||
static inline void
|
||||
insert_capture_proxy (tree var)
|
||||
{
|
||||
cxx_scope *b;
|
||||
int skip;
|
||||
tree stmt_list;
|
||||
|
||||
/* Put the capture proxy in the extra body block so that it won't clash
|
||||
with a later local variable. */
|
||||
b = current_binding_level;
|
||||
for (skip = 0; ; ++skip)
|
||||
{
|
||||
cxx_scope *n = b->level_chain;
|
||||
if (n->kind == sk_function_parms)
|
||||
break;
|
||||
b = n;
|
||||
}
|
||||
pushdecl_with_scope (var, b, false);
|
||||
|
||||
/* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */
|
||||
var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
|
||||
stmt_list = VEC_index (tree, stmt_list_stack,
|
||||
VEC_length (tree, stmt_list_stack) - 1 - skip);
|
||||
gcc_assert (stmt_list);
|
||||
append_to_statement_list_force (var, &stmt_list);
|
||||
}
|
||||
|
||||
/* We've just finished processing a lambda; if the containing scope is also
|
||||
a lambda, insert any capture proxies that were created while processing
|
||||
the nested lambda. */
|
||||
|
||||
void
|
||||
insert_pending_capture_proxies (void)
|
||||
{
|
||||
tree lam;
|
||||
VEC(tree,gc) *proxies;
|
||||
unsigned i;
|
||||
|
||||
if (!current_function_decl || !LAMBDA_FUNCTION_P (current_function_decl))
|
||||
return;
|
||||
|
||||
lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
|
||||
proxies = LAMBDA_EXPR_PENDING_PROXIES (lam);
|
||||
for (i = 0; i < VEC_length (tree, proxies); ++i)
|
||||
{
|
||||
tree var = VEC_index (tree, proxies, i);
|
||||
insert_capture_proxy (var);
|
||||
}
|
||||
release_tree_vector (LAMBDA_EXPR_PENDING_PROXIES (lam));
|
||||
LAMBDA_EXPR_PENDING_PROXIES (lam) = NULL;
|
||||
}
|
||||
|
||||
/* MEMBER is a capture field in a lambda closure class. Now that we're
|
||||
inside the operator(), build a placeholder var for future lookups and
|
||||
debugging. */
|
||||
|
||||
tree
|
||||
build_capture_proxy (tree member)
|
||||
{
|
||||
tree var, object, fn, closure, name, lam;
|
||||
|
||||
closure = DECL_CONTEXT (member);
|
||||
fn = lambda_function (closure);
|
||||
lam = CLASSTYPE_LAMBDA_EXPR (closure);
|
||||
|
||||
/* The proxy variable forwards to the capture field. */
|
||||
object = build_fold_indirect_ref (DECL_ARGUMENTS (fn));
|
||||
object = finish_non_static_data_member (member, object, NULL_TREE);
|
||||
if (REFERENCE_REF_P (object))
|
||||
object = TREE_OPERAND (object, 0);
|
||||
|
||||
/* Remove the __ inserted by add_capture. */
|
||||
name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
|
||||
|
||||
var = build_decl (input_location, VAR_DECL, name, TREE_TYPE (object));
|
||||
SET_DECL_VALUE_EXPR (var, object);
|
||||
DECL_HAS_VALUE_EXPR_P (var) = 1;
|
||||
DECL_ARTIFICIAL (var) = 1;
|
||||
TREE_USED (var) = 1;
|
||||
DECL_CONTEXT (var) = fn;
|
||||
|
||||
if (name == this_identifier)
|
||||
{
|
||||
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member);
|
||||
LAMBDA_EXPR_THIS_CAPTURE (lam) = var;
|
||||
}
|
||||
|
||||
if (fn == current_function_decl)
|
||||
insert_capture_proxy (var);
|
||||
else
|
||||
VEC_safe_push (tree, gc, LAMBDA_EXPR_PENDING_PROXIES (lam), var);
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/* From an ID and INITIALIZER, create a capture (by reference if
|
||||
BY_REFERENCE_P is true), add it to the capture-list for LAMBDA,
|
||||
and return it. */
|
||||
|
@ -8419,7 +8528,18 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
|
|||
}
|
||||
|
||||
/* Make member variable. */
|
||||
member = build_lang_decl (FIELD_DECL, id, type);
|
||||
{
|
||||
/* Add __ to the beginning of the field name so that user code
|
||||
won't find the field with name lookup. We can't just leave the name
|
||||
unset because template instantiation uses the name to find
|
||||
instantiated fields. */
|
||||
char *buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
|
||||
buf[1] = buf[0] = '_';
|
||||
memcpy (buf + 2, IDENTIFIER_POINTER (id),
|
||||
IDENTIFIER_LENGTH (id) + 1);
|
||||
member = build_lang_decl (FIELD_DECL, get_identifier (buf), type);
|
||||
}
|
||||
|
||||
if (!explicit_init_p)
|
||||
/* Normal captures are invisible to name lookup but uses are replaced
|
||||
with references to the capture field; we implement this by only
|
||||
|
@ -8435,14 +8555,18 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
|
|||
LAMBDA_EXPR_CAPTURE_LIST (lambda)
|
||||
= tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
|
||||
|
||||
if (id == get_identifier ("__this"))
|
||||
if (id == this_identifier)
|
||||
{
|
||||
if (LAMBDA_EXPR_CAPTURES_THIS_P (lambda))
|
||||
error ("already captured %<this%> in lambda expression");
|
||||
LAMBDA_EXPR_THIS_CAPTURE (lambda) = member;
|
||||
}
|
||||
|
||||
return member;
|
||||
if (TREE_TYPE (lambda))
|
||||
return build_capture_proxy (member);
|
||||
/* For explicit captures we haven't started the function yet, so we wait
|
||||
and build the proxy from cp_parser_lambda_body. */
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Register all the capture members on the list CAPTURES, which is the
|
||||
|
@ -8457,21 +8581,6 @@ void register_capture_members (tree captures)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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),
|
||||
RO_NULL,
|
||||
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. */
|
||||
|
@ -8479,9 +8588,9 @@ thisify_lambda_field (tree decl)
|
|||
tree
|
||||
add_default_capture (tree lambda_stack, tree id, tree initializer)
|
||||
{
|
||||
bool this_capture_p = (id == get_identifier ("__this"));
|
||||
bool this_capture_p = (id == this_identifier);
|
||||
|
||||
tree member = NULL_TREE;
|
||||
tree var = NULL_TREE;
|
||||
|
||||
tree saved_class_type = current_class_type;
|
||||
|
||||
|
@ -8494,7 +8603,7 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
|
|||
tree lambda = TREE_VALUE (node);
|
||||
|
||||
current_class_type = TREE_TYPE (lambda);
|
||||
member = add_capture (lambda,
|
||||
var = add_capture (lambda,
|
||||
id,
|
||||
initializer,
|
||||
/*by_reference_p=*/
|
||||
|
@ -8502,12 +8611,12 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
|
|||
&& (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
|
||||
== CPLD_REFERENCE)),
|
||||
/*explicit_init_p=*/false);
|
||||
initializer = thisify_lambda_field (member);
|
||||
initializer = convert_from_reference (var);
|
||||
}
|
||||
|
||||
current_class_type = saved_class_type;
|
||||
|
||||
return member;
|
||||
return var;
|
||||
}
|
||||
|
||||
/* Return the capture pertaining to a use of 'this' in LAMBDA, in the form of an
|
||||
|
@ -8540,8 +8649,7 @@ lambda_expr_this_capture (tree lambda)
|
|||
if (LAMBDA_EXPR_THIS_CAPTURE (lambda))
|
||||
{
|
||||
/* An outer lambda has already captured 'this'. */
|
||||
tree cap = LAMBDA_EXPR_THIS_CAPTURE (lambda);
|
||||
init = thisify_lambda_field (cap);
|
||||
init = LAMBDA_EXPR_THIS_CAPTURE (lambda);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -8563,7 +8671,7 @@ lambda_expr_this_capture (tree lambda)
|
|||
|
||||
if (init)
|
||||
this_capture = add_default_capture (lambda_stack,
|
||||
/*id=*/get_identifier ("__this"),
|
||||
/*id=*/this_identifier,
|
||||
init);
|
||||
}
|
||||
|
||||
|
@ -8577,9 +8685,7 @@ lambda_expr_this_capture (tree lambda)
|
|||
/* To make sure that current_class_ref is for the lambda. */
|
||||
gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) == TREE_TYPE (lambda));
|
||||
|
||||
result = finish_non_static_data_member (this_capture,
|
||||
NULL_TREE,
|
||||
/*qualifying_scope=*/NULL_TREE);
|
||||
result = this_capture;
|
||||
|
||||
/* If 'this' is captured, each use of 'this' is transformed into an
|
||||
access to the corresponding unnamed data member of the closure
|
||||
|
@ -8752,4 +8858,28 @@ maybe_add_lambda_conv_op (tree type)
|
|||
if (nested)
|
||||
pop_function_context ();
|
||||
}
|
||||
|
||||
/* Returns true iff VAL is a lambda-related declaration which should
|
||||
be ignored by unqualified lookup. */
|
||||
|
||||
bool
|
||||
is_lambda_ignored_entity (tree val)
|
||||
{
|
||||
/* In unevaluated context, look past normal capture proxies. */
|
||||
if (cp_unevaluated_operand && is_normal_capture_proxy (val))
|
||||
return true;
|
||||
|
||||
/* Always ignore lambda fields, their names are only for debugging. */
|
||||
if (TREE_CODE (val) == FIELD_DECL
|
||||
&& CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (val)))
|
||||
return true;
|
||||
|
||||
/* None of the lookups that use qualify_lookup want the op() from the
|
||||
lambda; they want the one from the enclosing class. */
|
||||
if (TREE_CODE (val) == FUNCTION_DECL && LAMBDA_FUNCTION_P (val))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "gt-cp-semantics.h"
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2011-06-17 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* g++.dg/debug/dwarf2/lambda1.C: New.
|
||||
* g++.dg/warn/Wshadow-6.C: Adjust.
|
||||
|
||||
2011-06-17 Janus Weil <janus@gcc.gnu.org>
|
||||
|
||||
PR fortran/48699
|
||||
|
|
35
gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C
Normal file
35
gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C
Normal file
|
@ -0,0 +1,35 @@
|
|||
// PR c++/43912
|
||||
// { dg-options "-g -std=c++0x -dA -fno-merge-debug-strings -gno-strict-dwarf" }
|
||||
|
||||
// Check for the local alias variables that point to the members of the closure.
|
||||
// { dg-final { scan-assembler-times "DW_TAG_variable\[^.\]*\.ascii \"j.0\"" 4 } }
|
||||
// { dg-final { scan-assembler-times "DW_TAG_variable\[^.\]*\.ascii \"this.0\"" 2 } }
|
||||
|
||||
struct A
|
||||
{
|
||||
int i;
|
||||
int f()
|
||||
{
|
||||
int j;
|
||||
[&]() { j = i; }();
|
||||
return j;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct B
|
||||
{
|
||||
int i;
|
||||
int f()
|
||||
{
|
||||
int j;
|
||||
[&]() { j = i; }();
|
||||
return j;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
A().f();
|
||||
B<int>().f();
|
||||
}
|
|
@ -33,7 +33,19 @@ void f2(struct S i, int j) {
|
|||
|
||||
void f3(int i) {
|
||||
[=]{
|
||||
int j = i;
|
||||
int i; // { dg-warning "shadows a member of" }
|
||||
int j = i; // { dg-warning "shadowed declaration" }
|
||||
int i; // { dg-warning "shadows a lambda capture" }
|
||||
i = 1;
|
||||
};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void f4(int i) {
|
||||
[=]{
|
||||
int j = i; // { dg-warning "shadowed declaration" }
|
||||
int i; // { dg-warning "shadows a lambda capture" }
|
||||
i = 1;
|
||||
};
|
||||
}
|
||||
|
||||
template void f4<int>(int);
|
||||
|
|
Loading…
Add table
Reference in a new issue