Patchwork C++ PATCH for c++/56447 (wrong lambda conversion op in templates)

login
register
mail settings
Submitter Jason Merrill
Date March 16, 2013, 6:58 p.m.
Message ID <5144C0EA.7030505@redhat.com>
Download mbox | patch
Permalink /patch/228241/
State New
Headers show

Comments

Jason Merrill - March 16, 2013, 6:58 p.m.
The code for adding a conversion op to a lambda closure was checking 
whether there were any captures before we had gotten around to setting 
up the capture list.  Fixed by instantiating it a bit sooner.

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

Patch

commit 75607bcd47d0be87cfaca0ebf625986ecde78a7d
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 15 12:04:34 2013 -0500

    	PR c++/56447
    	PR c++/55532
    	* pt.c (instantiate_class_template_1): Instantiate lambda capture
    	list here.
    	(tsubst_copy_and_build): Not here.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6264add..126e110 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
index 0000000..abe272a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv8.C
@@ -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
index 0000000..c54ff5c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mutable2.C
@@ -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);
+}