Patchwork C++ PATCH for c++/53137 ('this' capture in templates)

login
register
mail settings
Submitter Jason Merrill
Date Nov. 29, 2012, 8:12 p.m.
Message ID <50B7C1A3.8040204@redhat.com>
Download mbox | patch
Permalink /patch/202820/
State New
Headers show

Comments

Jason Merrill - Nov. 29, 2012, 8:12 p.m.
My earlier semi-fix for this issue failed to update 
LAMBDA_EXPR_THIS_CAPTURE to point to the proxy variable, so uses ended 
up with an unattached FIELD_DECL.  Fixed thus.

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

Patch

commit 73e140fd81aa10994184bb8edfe9cfafdc1499a9
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Nov 29 11:37:05 2012 -0500

    	PR c++/53137
    	* pt.c (tsubst_expr) [DECL_EXPR]: Set LAMBDA_EXPR_THIS_CAPTURE here.
    	(tsubst_copy_and_build) [LAMBDA_EXPR]: And clear it here.
    	(instantiate_class_template_1): Not here.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 85c8e7c..ceac093 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -659,8 +659,9 @@  enum cp_lambda_default_capture_mode_type {
 #define LAMBDA_EXPR_CAPTURE_LIST(NODE) \
   (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->capture_list)
 
-/* During parsing of the lambda, the node in the capture-list that holds
-   the 'this' capture.  */
+/* During parsing of the lambda-introducer, the node in the capture-list
+   that holds the 'this' capture.  During parsing of the body, the
+   capture proxy for that node.  */
 #define LAMBDA_EXPR_THIS_CAPTURE(NODE) \
   (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->this_capture)
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ecb013e..3bc0d64 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8956,14 +8956,8 @@  instantiate_class_template_1 (tree type)
       tree decl = lambda_function (type);
       if (decl)
 	{
-	  tree lam = CLASSTYPE_LAMBDA_EXPR (type);
-	  LAMBDA_EXPR_THIS_CAPTURE (lam)
-	    = lookup_field_1 (type, get_identifier ("__this"), false);
-
 	  instantiate_decl (decl, false, false);
 	  maybe_add_lambda_conv_op (type);
-
-	  LAMBDA_EXPR_THIS_CAPTURE (lam) = NULL_TREE;
 	}
       else
 	gcc_assert (errorcount);
@@ -12728,6 +12722,12 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 		else if (is_capture_proxy (DECL_EXPR_DECL (t)))
 		  {
 		    DECL_CONTEXT (decl) = current_function_decl;
+		    if (DECL_NAME (decl) == this_identifier)
+		      {
+			tree lam = DECL_CONTEXT (current_function_decl);
+			lam = CLASSTYPE_LAMBDA_EXPR (lam);
+			LAMBDA_EXPR_THIS_CAPTURE (lam) = decl;
+		      }
 		    insert_capture_proxy (decl);
 		  }
 		else if (DECL_IMPLICIT_TYPEDEF_P (t))
@@ -14313,6 +14313,7 @@  tsubst_copy_and_build (tree t,
 	   wait until after we finish instantiating the type.  */
 	LAMBDA_EXPR_CAPTURE_LIST (r)
 	  = RECUR (LAMBDA_EXPR_CAPTURE_LIST (t));
+	LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;
 
 	RETURN (build_lambda_object (r));
       }
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this6.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this6.C
new file mode 100644
index 0000000..acf4eaa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this6.C
@@ -0,0 +1,32 @@ 
+// PR c++/53137
+// { dg-options -std=c++11 }
+
+template <typename STORE>
+void getParent(STORE& tStore)
+{
+}
+
+struct  Store
+{
+    template <typename CheckParentFunc>
+    void updateChildCommon(CheckParentFunc c)
+    {
+        c();
+    }
+
+    template <typename T>
+    int& getStore();
+
+    template <typename T>
+    void updateChild(const T& obj)
+    {
+        updateChildCommon([this] () { getParent(getStore<T>()); });
+    }
+
+    void update(int obj);
+};
+
+void Store::update(int obj)
+{
+    updateChild(obj);
+}