PR c++/84708 - ICE with lambda in local class NSDMI.
authorJason Merrill <jason@redhat.com>
Mon, 5 Mar 2018 22:14:38 +0000 (17:14 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 5 Mar 2018 22:14:38 +0000 (17:14 -0500)
* lambda.c (lambda_expr_this_capture): Handle local class NSDMI
context.

From-SVN: r258264

gcc/cp/ChangeLog
gcc/cp/lambda.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nsdmi9.C [new file with mode: 0644]

index 5e62b1ce06dce0586eb1d985e5870a2e9f6a863c..3523b7e09125da38f37f34f40320f63951380bc6 100644 (file)
@@ -1,3 +1,9 @@
+2018-03-05  Jason Merrill  <jason@redhat.com>
+
+       PR c++/84708 - ICE with lambda in local class NSDMI.
+       * lambda.c (lambda_expr_this_capture): Handle local class NSDMI
+       context.
+
 2018-03-05  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/84684
index 3f77df037a233f08ce66624a50352a9f1fb78af0..345b210e89c857ec606da0a0395b235f8b23421c 100644 (file)
@@ -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 (file)
index 0000000..8f41d4e
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/84708
+// { dg-do run { target c++11 } }
+
+int main()
+{
+  struct Z
+  {
+    int i;
+    int b = ([&] { return i; }());
+    Z(int i): i(i) {}
+  } z (42);
+
+  if (z.b != 42)
+    __builtin_abort ();
+}