diff mbox

C++ PATCH for c++/56464 (ICE with lambda capturing 'this' in NSDMI)

Message ID 5134D5EC.4060104@redhat.com
State New
Headers show

Commit Message

Jason Merrill March 4, 2013, 5:12 p.m. UTC
Within an non-static data member initializer, the 'this' declaration is 
just a placeholder to be replaced when the NSDMI is used in a 
constructor, there's no function to find it in.  So we need to handle it 
specially for implicit capture.

This patch also fixes 54383, the case where there is no 'this' at all to 
capture.

Tested x86_64-pc-linux-gnu, applying to trunk.
diff mbox

Patch

commit 92223a939da06304df678232b3f15051d750157a
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 15 23:09:57 2013 -0500

    	PR c++/56464
    	PR c++/54383
    	* semantics.c (lambda_expr_this_capture): Handle NSDMI
    	and non-class scopes.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 8038aa2..ab3d16e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -9442,41 +9442,62 @@  lambda_expr_this_capture (tree lambda)
   if (!this_capture
       && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)
     {
-      tree containing_function = TYPE_CONTEXT (LAMBDA_EXPR_CLOSURE (lambda));
-      tree lambda_stack = tree_cons (NULL_TREE, lambda, NULL_TREE);
+      tree lambda_stack = NULL_TREE;
       tree init = NULL_TREE;
 
       /* If we are in a lambda function, we can move out until we hit:
-           1. a non-lambda function,
+           1. a non-lambda function or NSDMI,
            2. a lambda function capturing 'this', or
            3. a non-default capturing lambda function.  */
-      while (LAMBDA_FUNCTION_P (containing_function))
-        {
-          tree lambda
+      for (tree tlambda = lambda; ;)
+	{
+          lambda_stack = tree_cons (NULL_TREE,
+                                    tlambda,
+                                    lambda_stack);
+
+	  if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)
+	      && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL)
+	    {
+	      /* In an NSDMI, we don't have a function to look up the decl in,
+		 but the fake 'this' pointer that we're using for parsing is
+		 in scope_chain.  */
+	      init = scope_chain->x_current_class_ptr;
+	      gcc_checking_assert
+		(init && (TREE_TYPE (TREE_TYPE (init))
+			  == current_nonlambda_class_type ()));
+	      break;
+	    }
+
+	  tree closure_decl = TYPE_NAME (LAMBDA_EXPR_CLOSURE (tlambda));
+	  tree containing_function = decl_function_context (closure_decl);
+
+	  if (containing_function == NULL_TREE)
+	    /* We ran out of scopes; there's no 'this' to capture.  */
+	    break;
+
+	  if (!LAMBDA_FUNCTION_P (containing_function))
+	    {
+	      /* We found a non-lambda function.  */
+	      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function))
+		/* First parameter is 'this'.  */
+		init = DECL_ARGUMENTS (containing_function);
+	      break;
+	    }
+
+	  tlambda
             = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (containing_function));
 
-          if (LAMBDA_EXPR_THIS_CAPTURE (lambda))
+          if (LAMBDA_EXPR_THIS_CAPTURE (tlambda))
 	    {
 	      /* An outer lambda has already captured 'this'.  */
-	      init = LAMBDA_EXPR_THIS_CAPTURE (lambda);
+	      init = LAMBDA_EXPR_THIS_CAPTURE (tlambda);
 	      break;
 	    }
 
-	  if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_NONE)
+	  if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE)
 	    /* An outer lambda won't let us capture 'this'.  */
 	    break;
-
-          lambda_stack = tree_cons (NULL_TREE,
-                                    lambda,
-                                    lambda_stack);
-
-          containing_function = decl_function_context (containing_function);
-        }
-
-      if (!init && DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function)
-	  && !LAMBDA_FUNCTION_P (containing_function))
-	/* First parameter is 'this'.  */
-	init = DECL_ARGUMENTS (containing_function);
+	}
 
       if (init)
 	this_capture = add_default_capture (lambda_stack,
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi1.C
new file mode 100644
index 0000000..4d16ea4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi1.C
@@ -0,0 +1,11 @@ 
+// PR c++/56464
+// { dg-do run { target c++11 } }
+
+struct bug { bug*a = [&]{ return [=]{return this;}(); }(); };
+int main()
+{
+  bug b;
+  if (b.a != &b)
+    __builtin_abort ();
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this10.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this10.C
new file mode 100644
index 0000000..b4b8e72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this10.C
@@ -0,0 +1,4 @@ 
+// PR c++/54383
+// { dg-do compile { target c++11 } }
+
+auto foo = [&](int a) { return a > this->b; }; // { dg-error "this" }