commit 8456c74aa1edfd0c2d65d8892273e125e672c993
Author: Jason Merrill <jason@redhat.com>
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.
@@ -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"
new file mode 100644
@@ -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);
commit 5fef9545d98be9d4f4a035a5086000ab3cd70ba0
Author: Jason Merrill <jason@redhat.com>
Date: Fri Jun 17 13:32:07 2011 -0400
* name-lookup.c (pushdecl_maybe_friend_1): Do check for shadowing
of artificial locals.
@@ -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 <jason@redhat.com>
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.
@@ -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)
@@ -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
@@ -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 <jason@redhat.com>
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.
@@ -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 <jason@redhat.com>
Date: Thu Jun 16 12:18:46 2011 -0400
pushdecl_with_scope comment
@@ -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 <jason@redhat.com>
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.
@@ -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;
@@ -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 <jason@redhat.com>
Date: Wed Jun 15 20:47:29 2011 -0400
* semantics.c (finish_non_static_data_member): Preserve dereference
in template.
@@ -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