commit 8456c74aa1edfd0c2d65d8892273e125e672c993 Author: Jason Merrill Date: Thu Jun 16 20:17:48 2011 -0400 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. diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index ce11417..12c01cb 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -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) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cf1c592..2773e34 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9f62ea3..59c4a4c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 64a0f9a..953edd5 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index a9cedcf..49aa35e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ca4f955..85f2749 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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)); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a436623..76c1862 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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 % 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" diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C b/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C new file mode 100644 index 0000000..ee24eca --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C @@ -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 +struct B +{ + int i; + int f() + { + int j; + [&]() { j = i; }(); + return j; + } +}; + +int main() +{ + A().f(); + B().f(); +} diff --git a/gcc/testsuite/g++.dg/warn/Wshadow-6.C b/gcc/testsuite/g++.dg/warn/Wshadow-6.C index 9b13e3a..fdc37df 100644 --- a/gcc/testsuite/g++.dg/warn/Wshadow-6.C +++ b/gcc/testsuite/g++.dg/warn/Wshadow-6.C @@ -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 +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); commit 5fef9545d98be9d4f4a035a5086000ab3cd70ba0 Author: Jason Merrill Date: Fri Jun 17 13:32:07 2011 -0400 * name-lookup.c (pushdecl_maybe_friend_1): Do check for shadowing of artificial locals. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 16b991d..64a0f9a 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1022,11 +1022,6 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend) || (TREE_CODE (oldlocal) == TYPE_DECL && (!DECL_ARTIFICIAL (oldlocal) || TREE_CODE (x) == TYPE_DECL))) - /* Don't check the `this' parameter or internally generated - vars unless it's an implicit typedef (see - create_implicit_typedef in decl.c). */ - && (!DECL_ARTIFICIAL (oldlocal) - || DECL_IMPLICIT_TYPEDEF_P (oldlocal)) /* Don't check for internally generated vars unless it's an implicit typedef (see create_implicit_typedef in decl.c). */ commit c1bc237ee7559dda94a0a6e2bf73de1d36ca1a16 Author: Jason Merrill Date: Thu Jun 16 20:17:18 2011 -0400 * parser.c (cp_parser_lambda_expression): Clear LAMBDA_EXPR_THIS_CAPTURE after parsing. * pt.c (tsubst_copy_and_build): Make sure it isn't set. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ee303fe..cf1c592 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -625,7 +625,8 @@ enum cp_lambda_default_capture_mode_type { #define LAMBDA_EXPR_CAPTURE_LIST(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->capture_list) -/* The node in the capture-list that holds the 'this' capture. */ +/* During parsing of the lambda, the node in the capture-list that holds + the 'this' capture. */ #define LAMBDA_EXPR_THIS_CAPTURE(NODE) \ (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->this_capture) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 5ea04b5..a9cedcf 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7430,6 +7430,9 @@ cp_parser_lambda_expression (cp_parser* parser) pop_deferring_access_checks (); + /* This field is only used during parsing of the lambda. */ + LAMBDA_EXPR_THIS_CAPTURE (lambda_expr) = NULL_TREE; + if (ok) return build_lambda_object (lambda_expr); else diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 308aff7..ca4f955 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13498,10 +13498,9 @@ tsubst_copy_and_build (tree t, = (LAMBDA_EXPR_DISCRIMINATOR (t)); LAMBDA_EXPR_CAPTURE_LIST (r) = RECUR (LAMBDA_EXPR_CAPTURE_LIST (t)); - LAMBDA_EXPR_THIS_CAPTURE (r) - = RECUR (LAMBDA_EXPR_THIS_CAPTURE (t)); LAMBDA_EXPR_EXTRA_SCOPE (r) = RECUR (LAMBDA_EXPR_EXTRA_SCOPE (t)); + gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE); /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */ determine_visibility (TYPE_NAME (type)); commit 57e2d45f96fc4c7a18450f8557e80be9035672b3 Author: Jason Merrill Date: Thu Jun 16 14:09:44 2011 -0400 * cp-tree.h (struct tree_lambda_expr): Change common to typed. Move non-pointers to end of struct. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ff8b2dc..ee303fe 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -662,13 +662,13 @@ enum cp_lambda_default_capture_mode_type { struct GTY (()) tree_lambda_expr { - struct tree_common common; - location_t locus; - enum cp_lambda_default_capture_mode_type default_capture_mode; + struct tree_typed typed; tree capture_list; tree this_capture; tree return_type; tree extra_scope; + location_t locus; + enum cp_lambda_default_capture_mode_type default_capture_mode; int discriminator; }; commit 6523f3884893fa8492c6fc740edacafaa2e86039 Author: Jason Merrill Date: Thu Jun 16 12:18:46 2011 -0400 pushdecl_with_scope comment diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 7f0f615..16b991d 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2066,7 +2066,12 @@ push_using_decl (tree scope, tree name) } /* Same as pushdecl, but define X in binding-level LEVEL. We rely on the - caller to set DECL_CONTEXT properly. */ + caller to set DECL_CONTEXT properly. + + Note that this must only be used when X will be the new innermost + binding for its name, as we tack it onto the front of IDENTIFIER_BINDING + without checking to see if the current IDENTIFIER_BINDING comes from a + closer binding level than LEVEL. */ static tree pushdecl_with_scope_1 (tree x, cxx_scope *level, bool is_friend) commit a14ec74f2a875ea3de670faf532912c21bec5a7e Author: Jason Merrill Date: Wed Jun 15 20:54:10 2011 -0400 * pt.c (tsubst_decl): Handle DECL_VALUE_EXPR on reference. * decl.c (check_initializer): Handle DECL_VALUE_EXPR_P. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0584cd8..9f62ea3 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5387,6 +5387,14 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup) type. */ TREE_TYPE (decl) = type = complete_type (TREE_TYPE (decl)); + if (DECL_HAS_VALUE_EXPR_P (decl)) + { + /* A variable with DECL_HAS_VALUE_EXPR_P set is just a placeholder, + it doesn't have storage to be initialized. */ + gcc_assert (init == NULL_TREE); + return NULL_TREE; + } + if (type == error_mark_node) /* We will have already complained. */ return NULL_TREE; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1008b3b..308aff7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -10061,6 +10061,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) tree ve = DECL_VALUE_EXPR (t); ve = tsubst_expr (ve, args, complain, in_decl, /*constant_expression_p=*/false); + if (REFERENCE_REF_P (ve)) + { + gcc_assert (TREE_CODE (type) == REFERENCE_TYPE); + ve = TREE_OPERAND (ve, 0); + } SET_DECL_VALUE_EXPR (r, ve); } } commit 3194462e1e7be304451699ee8368431b153099fd Author: Jason Merrill Date: Wed Jun 15 20:47:29 2011 -0400 * semantics.c (finish_non_static_data_member): Preserve dereference in template. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index bad7acb..a436623 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1557,7 +1557,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) tree type = TREE_TYPE (decl); if (TREE_CODE (type) == REFERENCE_TYPE) - type = TREE_TYPE (type); + /* Quals on the object don't matter. */; else { /* Set the cv qualifiers. */ @@ -1572,7 +1572,8 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) type = cp_build_qualified_type (type, quals); } - return build_min (COMPONENT_REF, type, object, decl, NULL_TREE); + return (convert_from_reference + (build_min (COMPONENT_REF, type, object, decl, NULL_TREE))); } /* If PROCESSING_TEMPLATE_DECL is nonzero here, then QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF