diff mbox series

C++ PATCH for c++/84708, ICE with lambda in local class NSDMI

Message ID CADzB+2kUNjCSmQOFJ29eYCnPbLtRgpA1cpHYB8f137bjmvYLVg@mail.gmail.com
State New
Headers show
Series C++ PATCH for c++/84708, ICE with lambda in local class NSDMI | expand

Commit Message

Jason Merrill March 5, 2018, 10:12 p.m. UTC
Looking for fake NSDMI 'this' in scope_chain only works for non-local
classes.  But if we can't find it, we can make our own fake.

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

Patch

commit 8fd062c984befc3419f8a0a61224d0f4ecf02495
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Mar 5 16:45:36 2018 -0500

            PR c++/84708 - ICE with lambda in local class NSDMI.
    
            * lambda.c (lambda_expr_this_capture): Handle local class NSDMI
            context.

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 3f77df037a2..345b210e89c 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -757,25 +757,31 @@  lambda_expr_this_capture (tree lambda, bool add_capture_p)
                                     tlambda,
                                     lambda_stack);
 
-	  if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)
-	      && !COMPLETE_TYPE_P (LAMBDA_EXPR_CLOSURE (tlambda))
-	      && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL)
+	  tree closure = LAMBDA_EXPR_CLOSURE (tlambda);
+	  tree containing_function
+	    = decl_function_context (TYPE_NAME (closure));
+
+	  tree ex = LAMBDA_EXPR_EXTRA_SCOPE (tlambda);
+	  if (ex && TREE_CODE (ex) == 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.  But if the closure is already complete, we're
-	         in an instantiation of a generic lambda, and the fake 'this'
-	         is gone.  */
-	      init = scope_chain->x_current_class_ptr;
+	      /* Lambda in an NSDMI.  We don't have a function to look up
+		 'this' in, but we can find (or rebuild) the fake one from
+		 inject_this_parameter.  */
+	      if (!containing_function && !COMPLETE_TYPE_P (closure))
+		/* If we're parsing a lambda in a non-local class,
+		   we can find the fake 'this' in scope_chain.  */
+		init = scope_chain->x_current_class_ptr;
+	      else
+		/* Otherwise it's either gone or buried in
+		   function_context_stack, so make another.  */
+		init = build_this_parm (NULL_TREE, DECL_CONTEXT (ex),
+					TYPE_UNQUALIFIED);
 	      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;
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi9.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi9.C
new file mode 100644
index 00000000000..fe64f459479
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi9.C
@@ -0,0 +1,15 @@ 
+// PR c++/84708
+// { dg-do run { target c++14 } }
+
+int main()
+{
+  struct Z
+  {
+    int i;
+    int b = ([&] { return i; }());
+    Z(int i): i(i) {}
+  } z (42);
+
+  if (z.b != 42)
+    __builtin_abort ();
+}