public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH to nested lambda capture
@ 2009-10-23 18:15 Jason Merrill
  2009-10-23 21:23 ` Jason Merrill
  0 siblings, 1 reply; 2+ messages in thread
From: Jason Merrill @ 2009-10-23 18:15 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 275 bytes --]

The paper proposing to extend C++ lambdas to allow nested captures (as 
our implementation does) has a testcase that found a bug in the current 
implementation; implicit capture of an explicit capture was failing. 
Fixed thus.

Tested x86_64-pc-linux-gnu, applied to trunk.


[-- Attachment #2: lambda-nest2.patch --]
[-- Type: text/x-patch, Size: 6635 bytes --]

commit 178c24b826f685493bb5b4a76d7b9d8d51e8d76e
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Oct 22 18:08:47 2009 -0700

    	* semantics.c (outer_lambda_capture_p): New fn.
    	(thisify_lambda_field): Factor out...
    	(add_default_capture): ...from here.
    	(finish_id_expression): Use them.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 6cf2220..3e39f37 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -56,6 +56,7 @@ 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
@@ -1447,14 +1448,13 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
       return error_mark_node;
     }
 
-  /* If decl is a field, object has a lambda type, and decl is not a member
-     of that type, then we have a reference to a member of 'this' from a
+  /* If decl is a non-capture field and object has a lambda type,
+     then we have a reference to a member of 'this' from a
      lambda inside a non-static member function, and we must get to decl
      through the 'this' capture.  If decl is not a member of that object,
      either, then its access will still fail later.  */
   if (LAMBDA_TYPE_P (TREE_TYPE (object))
-      && !same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (decl),
-                                                     TREE_TYPE (object)))
+      && !LAMBDA_TYPE_P (DECL_CONTEXT (decl)))
     object = cp_build_indirect_ref (lambda_expr_this_capture
 				    (CLASSTYPE_LAMBDA_EXPR
 				     (TREE_TYPE (object))),
@@ -2648,6 +2648,18 @@ 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
@@ -2751,7 +2763,8 @@ finish_id_expression (tree id_expression,
 
       /* Disallow uses of local variables from containing functions, except
 	 within lambda-expressions.  */
-      if (outer_automatic_var_p (decl)
+      if ((outer_automatic_var_p (decl)
+	   || outer_lambda_capture_p (decl))
 	  /* It's not a use (3.2) if we're in an unevaluated context.  */
 	  && !cp_unevaluated_operand)
 	{
@@ -2759,6 +2772,7 @@ finish_id_expression (tree id_expression,
 	  tree containing_function = current_function_decl;
 	  tree lambda_stack = NULL_TREE;
 	  tree lambda_expr = NULL_TREE;
+	  tree initializer = decl;
 
 	  /* Core issue 696: "[At the July 2009 meeting] the CWG expressed
 	     support for an approach in which a reference to a local
@@ -2770,6 +2784,13 @@ finish_id_expression (tree id_expression,
 	  if (DECL_INTEGRAL_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
@@ -2796,7 +2817,7 @@ finish_id_expression (tree id_expression,
 	    {
 	      decl = add_default_capture (lambda_stack,
 					  /*id=*/DECL_NAME (decl),
-					  /*initializer=*/decl);
+					  initializer);
 	    }
 	  else if (lambda_expr)
 	    {
@@ -5604,6 +5625,21 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
   return member;
 }
 
+/* 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),
+				       /*errorstring*/"",
+				       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.  */
@@ -5634,16 +5670,7 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
 			     && (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
 				 == CPLD_REFERENCE)),
 			    /*explicit_init_p=*/false);
-
-      {
-        /* Have to get the old value of current_class_ref.  */
-        tree object = cp_build_indirect_ref (DECL_ARGUMENTS
-                                               (lambda_function (lambda)),
-                                             /*errorstring=*/"",
-                                             /*complain=*/tf_warning_or_error);
-        initializer = finish_non_static_data_member
-                        (member, object, /*qualifying_scope=*/NULL_TREE);
-      }
+      initializer = thisify_lambda_field (member);
     }
 
   current_class_type = saved_class_type;
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C
new file mode 100644
index 0000000..b788748
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C
@@ -0,0 +1,31 @@
+// Testcase from N2998
+// { dg-options -std=c++0x }
+
+void f1(int i) {
+  int const N = 20;
+  auto m1 = [=]{
+     int const M = 30;
+     auto m2 = [i]{
+        int x[N][M]; // OK: N and M are not "used"
+        x[0][0] = i; // OK: i is explicitly captured by m2
+                     // and implicitly captured by m1
+     };
+  };
+  struct s1 {
+    int f;
+    int work(int n) {
+      int m = n*n;
+      int j = 40;
+      auto m3 = [this,m]{
+        /*auto m4=*/[&,j]{      // { dg-error "j. is not captured" }
+          int x = n;	        // { dg-error "n. is not captured" }
+          x += m;	        // OK: m implicitly captured by m4
+				// and explicitly captured by m3
+          x += i;		// { dg-error "i. is not captured" }
+          x += f;		// OK: this captured implicitly by m4
+				// and explicitly by m3
+        };
+      };
+    }
+  };
+}


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: C++ PATCH to nested lambda capture
  2009-10-23 18:15 C++ PATCH to nested lambda capture Jason Merrill
@ 2009-10-23 21:23 ` Jason Merrill
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2009-10-23 21:23 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 81 bytes --]

One more small code reuse change:

Tested x86_64-pc-linux-gnu, applied to trunk.

[-- Attachment #2: lambda-nest3.patch --]
[-- Type: text/x-patch, Size: 777 bytes --]

commit 42952e08d6d6bd932b7c9bfd62a9e6131fa95ac9
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Oct 23 12:03:22 2009 -0700

    	* semantics.c (lambda_expr_this_capture): Use thisify_lambda_field.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 3e39f37..417c15f 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5709,10 +5709,7 @@ lambda_expr_this_capture (tree lambda)
 	    {
 	      /* An outer lambda has already captured 'this'.  */
 	      tree cap = LAMBDA_EXPR_THIS_CAPTURE (lambda);
-	      tree lthis
-		= cp_build_indirect_ref (DECL_ARGUMENTS (containing_function),
-					 "", tf_warning_or_error);
-	      init = finish_non_static_data_member (cap, lthis, NULL_TREE);
+	      init = thisify_lambda_field (cap);
 	      break;
 	    }
 


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-10-23 20:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-10-23 18:15 C++ PATCH to nested lambda capture Jason Merrill
2009-10-23 21:23 ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).