This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] c++/pr77585 bogus this error with generic lambda


77585 concerns the instantiation of a generic lambda that contains a call to a non-dependent non-static member function.

  auto lam = [&](auto) { return Share (); };
  r += Eat (lam);  // instantation of lambda::operator() here

During instantiation of the call to Share, maybe_resolve_dummy gets called and uses current_nonlambda_class_type, which peeks up the current_current_class stack.

That peeking presupposes we're actually pushing and popping class scopes as we enter them all the way from the global scope. But that doesn't always happen in instantiation. push_nested_class pushes the immediately enclosing scopes, but stops at function scope. So we don't get the class scope of that function pushed. Thus stack peeking fails.

This hasn't previously been an instantiation problem, because templates couldn't be defined at local scope. But generic lambdas now have that property (wrt this capture at least).

This patch amends instantiate_decl to first push the containing non-lambda class scope before start_preparsed_function does its stack pushing.

ok?

nathan
--
Nathan Sidwell
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.

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 243661)
+++ cp/pt.c	(working copy)
@@ -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);
Index: testsuite/g++.dg/cpp1y/pr77585.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr77585.C	(revision 0)
+++ testsuite/g++.dg/cpp1y/pr77585.C	(working copy)
@@ -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;
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]