Commit 61ca4737 by Jason Merrill Committed by Jason Merrill

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
parent 7e7666ae
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));
......
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
......
// 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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment