re PR c++/77585 (g++ incorrectly decides that member function is called without objec...
authorNathan Sidwell <nathan@acm.org>
Thu, 15 Dec 2016 19:50:25 +0000 (19:50 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Thu, 15 Dec 2016 19:50:25 +0000 (19:50 +0000)
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.

From-SVN: r243723

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/pr77585.C [new file with mode: 0644]

index d2e8d45..9c6ee48 100644 (file)
@@ -1,3 +1,9 @@
+2016-12-15  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.
+
 2016-12-14  Martin Sebor  <msebor@redhat.com>
 
        PR c++/78774
index a21be81..91178ea 100644 (file)
@@ -22484,6 +22484,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.  */
@@ -22497,7 +22498,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
@@ -22565,6 +22582,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);
index 535dc84..ac49d4d 100644 (file)
@@ -1,3 +1,8 @@
+2016-12-15  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/77585
+       * g++.dg/cpp1y/pr77585.C: New.
+
 2016-12-15  David Edelsohn  <dje.gcc@gmail.com>
 
        * gcc.dg/tree-ssa/ssa-fre-55.c: Add -Wno-psabi.
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr77585.C b/gcc/testsuite/g++.dg/cpp1y/pr77585.C
new file mode 100644 (file)
index 0000000..aff7a61
--- /dev/null
@@ -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;
+}