re PR c++/43912 ([C++0x] lambda debug info does not describe captured variables)
authorJason Merrill <jason@redhat.com>
Fri, 17 Jun 2011 20:08:01 +0000 (16:08 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 17 Jun 2011 20:08:01 +0000 (16:08 -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.

From-SVN: r175158

gcc/cp/ChangeLog
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wshadow-6.C

index f84bc45a38cc0281204ef849b475507e5ffc96bf..f3fca847a082b6585466f5a3dda8f8354991607e 100644 (file)
@@ -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.
 
index ce1141735a7ff25b8fe06584c8e9b7d12537e08b..12c01cb15f5069054bad65bdfc49b7763fa27046 100644 (file)
@@ -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)
index cf1c5927cb0b3aee29b5d1379ac7d5cf9d9e5767..2773e34de2314a9082f68eeb9c406bc4cfb9f986 100644 (file)
@@ -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);
index 9f62ea34e12bfcbcd034ff847da2d0d9f2f519c2..59c4a4c9d01665717a5e4347e6aa3bb5908a1af8 100644 (file)
@@ -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)
index 64a0f9ae4a0a990b856e24b1659b9845a043ab14..953edd57f221719ab0a141669c12f213e07116ef 100644 (file)
@@ -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;
 }
index a9cedcf38ab152afff791c31e179ded5e63c158e..49aa35e45b95eaec04ae66784272b6bbf67e9406 100644 (file)
@@ -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:
index ca4f955cc12c3a8542328180ab1235f3460f9a81..85f27497d9004d4d6f6f24269c14980c2d8a5bb3 100644 (file)
@@ -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));
index a43662381862b715540732d7c49c9d107fab30dd..76c186249208007bb2f88342213fcc90ac50add5 100644 (file)
@@ -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"
index 1adce47c6215a26686526f650790b9b9cf2a8883..805c5b178f1918406e8d3dead671eebdd87d6273 100644 (file)
@@ -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
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C b/gcc/testsuite/g++.dg/debug/dwarf2/lambda1.C
new file mode 100644 (file)
index 0000000..ee24eca
--- /dev/null
@@ -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();
+}
index 9b13e3ae79e211effb63c099eaec0c9e15c67afb..fdc37df31b4966242e351daa101f68bb249f13aa 100644 (file)
@@ -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);