re PR c++/56464 ([C++11] Crashes when using implicit this in a lambda capture in...
authorJason Merrill <jason@redhat.com>
Mon, 4 Mar 2013 17:12:32 +0000 (12:12 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 4 Mar 2013 17:12:32 +0000 (12:12 -0500)
PR c++/56464
PR c++/54383
* semantics.c (lambda_expr_this_capture): Handle NSDMI
and non-class scopes.

From-SVN: r196437

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

index eb030f117e25f4dc6b8637f5d077b63c87f09ec5..8243e67b30d00d5473cf30e0cef2da83bb97ac90 100644 (file)
@@ -1,3 +1,10 @@
+2013-03-04  Jason Merrill  <jason@redhat.com>
+
+       PR c++/56464
+       PR c++/54383
+       * semantics.c (lambda_expr_this_capture): Handle NSDMI
+       and non-class scopes.
+
 2013-03-01  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * decl.c (grokdeclarator): Remove dead code.
index 8038aa26e4800ea99de241f28b40e7d4261db701..ab3d16ea3b805e677c1c75d55130a2f9d4fa71ed 100644 (file)
@@ -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
-            = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (containing_function));
+      for (tree tlambda = lambda; ;)
+       {
+          lambda_stack = tree_cons (NULL_TREE,
+                                    tlambda,
+                                    lambda_stack);
 
-          if (LAMBDA_EXPR_THIS_CAPTURE (lambda))
+         if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)
+             && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL)
            {
-             /* An outer lambda has already captured 'this'.  */
-             init = LAMBDA_EXPR_THIS_CAPTURE (lambda);
+             /* 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;
            }
 
-         if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_NONE)
-           /* An outer lambda won't let us capture 'this'.  */
+         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;
 
-          lambda_stack = tree_cons (NULL_TREE,
-                                    lambda,
-                                    lambda_stack);
+         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;
+           }
 
-          containing_function = decl_function_context (containing_function);
-        }
+         tlambda
+            = CLASSTYPE_LAMBDA_EXPR (DECL_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 (LAMBDA_EXPR_THIS_CAPTURE (tlambda))
+           {
+             /* An outer lambda has already captured 'this'.  */
+             init = LAMBDA_EXPR_THIS_CAPTURE (tlambda);
+             break;
+           }
+
+         if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE)
+           /* An outer lambda won't let us capture 'this'.  */
+           break;
+       }
 
       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 (file)
index 0000000..94dc254
--- /dev/null
@@ -0,0 +1,10 @@
+// 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 (file)
index 0000000..b4b8e72
--- /dev/null
@@ -0,0 +1,4 @@
+// PR c++/54383
+// { dg-do compile { target c++11 } }
+
+auto foo = [&](int a) { return a > this->b; }; // { dg-error "this" }