2016-12-14 Nathan Sidwell <nathan@acm.org>
PR c++/77585
* pt.c (instantiate_decl): Push to class scope lambda resides
within when instantiating a generic lambda function.
PR c++/77585
* g++.dg/cpp1y/pr77585.C: New.
===================================================================
@@ -22483,6 +22483,7 @@ instantiate_decl (tree d, int defer_ok,
tree tmpl_parm;
tree spec_parm;
tree block = NULL_TREE;
+ tree lambda_ctx = NULL_TREE;
/* Save away the current list, in case we are instantiating one
template from within the body of another. */
@@ -22496,7 +22497,23 @@ instantiate_decl (tree d, int defer_ok,
&& TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
block = push_stmt_list ();
else
- start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
+ {
+ if (LAMBDA_FUNCTION_P (d))
+ {
+ /* When instantiating a lambda's templated function
+ operator, we need to push the non-lambda class scope
+ of the lambda itself so that the nested function
+ stack is sufficiently correct to deal with this
+ capture. */
+ lambda_ctx = DECL_CONTEXT (d);
+ do
+ lambda_ctx = decl_type_context (TYPE_NAME (lambda_ctx));
+ while (lambda_ctx && LAMBDA_TYPE_P (lambda_ctx));
+ if (lambda_ctx)
+ push_nested_class (lambda_ctx);
+ }
+ start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
+ }
/* Some typedefs referenced from within the template code need to be
access checked at template instantiation time, i.e now. These
@@ -22564,6 +22581,8 @@ instantiate_decl (tree d, int defer_ok,
d = finish_function (0);
expand_or_defer_fn (d);
}
+ if (lambda_ctx)
+ pop_nested_class ();
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
cp_check_omp_declare_reduction (d);
===================================================================
@@ -0,0 +1,41 @@
+// PR c++/77585
+// { dg-do run { target c++14 } }
+
+// Confusion about this capture when instantiating generic lambda's
+// function operator
+
+template <typename F> int Eat (F &&f) { return f (1); }
+
+struct Foo {
+ int x = 1;
+ int Share () { return x++; }
+ int Frob (int);
+};
+
+int Foo::Frob (int r)
+{
+ auto lam = [&](auto) { return Share (); };
+ r += Eat (lam);
+
+ auto lam0 = [&](auto) {
+ auto lam1 = [&](auto) { return Share (); };
+ return Eat (lam1); };
+ r += Eat (lam0);
+
+ return r;
+}
+
+int Frob (int r)
+{
+ auto lam = [&](auto) { return 1; };
+ r += Eat (lam);
+ return r;
+}
+
+
+int main ()
+{
+ Foo f;
+
+ return Frob (f.Frob (0)) == 4 ? 0 : 1;
+}