re PR c++/56447 ([C++11] Lambda in template has conversion op it shouldn't have)
authorJason Merrill <jason@redhat.com>
Sun, 17 Mar 2013 02:35:18 +0000 (22:35 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 17 Mar 2013 02:35:18 +0000 (22:35 -0400)
PR c++/56447
PR c++/55532
* pt.c (instantiate_class_template_1): Instantiate lambda capture
list here.
(tsubst_copy_and_build): Not here.

From-SVN: r196729

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

index 28b110c..59d6e8a 100644 (file)
@@ -1,5 +1,11 @@
 2013-03-16  Jason Merrill  <jason@redhat.com>
 
+       PR c++/56447
+       PR c++/55532
+       * pt.c (instantiate_class_template_1): Instantiate lambda capture
+       list here.
+       (tsubst_copy_and_build): Not here.
+
        PR c++/55017
        * method.c (walk_field_subobs): Disallow copy of rvalue ref.
 
index 6264add..126e110 100644 (file)
@@ -8991,12 +8991,26 @@ instantiate_class_template_1 (tree type)
        }
     }
 
-  if (CLASSTYPE_LAMBDA_EXPR (type))
+  if (tree expr = CLASSTYPE_LAMBDA_EXPR (type))
     {
       tree decl = lambda_function (type);
       if (decl)
        {
          instantiate_decl (decl, false, false);
+
+         /* We need to instantiate the capture list from the template
+            after we've instantiated the closure members, but before we
+            consider adding the conversion op.  Also keep any captures
+            that may have been added during instantiation of the op().  */
+         tree tmpl_expr = CLASSTYPE_LAMBDA_EXPR (pattern);
+         tree tmpl_cap
+           = tsubst_copy_and_build (LAMBDA_EXPR_CAPTURE_LIST (tmpl_expr),
+                                    args, tf_warning_or_error, NULL_TREE,
+                                    false, false);
+
+         LAMBDA_EXPR_CAPTURE_LIST (expr)
+           = chainon (tmpl_cap, nreverse (LAMBDA_EXPR_CAPTURE_LIST (expr)));
+
          maybe_add_lambda_conv_op (type);
        }
       else
@@ -14470,12 +14484,6 @@ tsubst_copy_and_build (tree t,
           declaration of the op() for later calls to lambda_function.  */
        complete_type (type);
 
-       /* The capture list refers to closure members, so this needs to
-          wait until after we finish instantiating the type.  Also keep
-          any captures that may have been added during instantiation.  */
-       LAMBDA_EXPR_CAPTURE_LIST (r)
-         = chainon (RECUR (LAMBDA_EXPR_CAPTURE_LIST (t)),
-                    LAMBDA_EXPR_CAPTURE_LIST (r));
        LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;
 
        RETURN (build_lambda_object (r));
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv8.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv8.C
new file mode 100644 (file)
index 0000000..abe272a
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/56447
+// { dg-do compile { target c++11 } }
+
+template <class T>
+void f()
+{
+  int i;
+  // This lambda should not have a conversion op, since it captures i
+  int (*p)() = [=]{ return i; }; // { dg-error "cannot convert" }
+}
+
+int main()
+{
+  f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable2.C
new file mode 100644 (file)
index 0000000..c54ff5c
--- /dev/null
@@ -0,0 +1,23 @@
+// PR c++/55532
+// { dg-do compile { target c++11 } }
+
+struct Foo {
+    void doit() {
+    }
+};
+
+template<typename T>
+void oops(Foo &foo, const T &) {
+    auto fun = [&] () mutable {
+        foo.doit();
+    };
+    auto fun2 = [=]() {
+        fun();                 // { dg-error "" }
+    };
+    fun2();
+}
+
+int main() {
+    Foo foo;
+    oops(foo, 1);
+}