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.
commit 73e140fd81aa10994184bb8edfe9cfafdc1499a9
Author: Jason Merrill <ja...@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);
+}