On 01/31/2017 10:04 AM, Jason Merrill wrote:

Agreed.  As I was suggesting in response to one of Adam's patches, I
think we need to defer creating the closure until f is instantiated;
at that point we can resolve all names from f and so we should be able
to always push to top when instantiating the lambda.

Yup.

Perhaps

if (!fn_context || fn_context != current_function_decl)

That works fine, thanks. It also makes it clearer that 'nested' must be true if !push_to_top (but not vice-versa), which allowed a little more simplification.

Committed the attached to trunk.

nathan
--
Nathan Sidwell
2017-01-31  Nathan Sidwell  <nat...@acm.org>

	PR c++/67273
	PR c++/79253
	* pt.c: (instantiate_decl): Push to top level when current
	function scope doesn't match.  Only push lmabda scope stack when
	pushing to top.

	PR c++/67273
	PR c++/79253
	* g++.dg/cpp1y/pr67273.C: New.
	* g++.dg/cpp1y/pr79253.C: New.

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 245066)
+++ cp/pt.c	(working copy)
@@ -22666,20 +22666,21 @@ instantiate_decl (tree d, bool defer_ok,
 	goto out;
     }
 
-  bool nested;
+  bool push_to_top, nested;
   tree fn_context;
   fn_context = decl_function_context (d);
-  nested = (current_function_decl != NULL_TREE);
+  nested = current_function_decl != NULL_TREE;
+  push_to_top = !(nested && fn_context == current_function_decl);
+
   vec<tree> omp_privatization_save;
   if (nested)
     save_omp_privatization_clauses (omp_privatization_save);
 
-  if (!fn_context)
+  if (push_to_top)
     push_to_top_level ();
   else
     {
-      if (nested)
-	push_function_context ();
+      push_function_context ();
       cp_unevaluated_operand = 0;
       c_inhibit_evaluation_warnings = 0;
     }
@@ -22756,7 +22757,7 @@ instantiate_decl (tree d, bool defer_ok,
 	block = push_stmt_list ();
       else
 	{
-	  if (LAMBDA_FUNCTION_P (d))
+	  if (push_to_top && LAMBDA_FUNCTION_P (d))
 	    {
 	      /* When instantiating a lambda's templated function
 		 operator, we need to push the non-lambda class scope
@@ -22849,9 +22850,9 @@ instantiate_decl (tree d, bool defer_ok,
   /* We're not deferring instantiation any more.  */
   TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (d)) = 0;
 
-  if (!fn_context)
+  if (push_to_top)
     pop_from_top_level ();
-  else if (nested)
+  else
     pop_function_context ();
 
   if (nested)
Index: testsuite/g++.dg/cpp1y/pr67273.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr67273.C	(revision 0)
+++ testsuite/g++.dg/cpp1y/pr67273.C	(working copy)
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++14 } }
+// { dg-additional-options "-Wshadow" }
+
+// pr67273 bogus warning about shadowing.
+
+
+template <typename T> void Foo (T &&lambda)
+{
+  int ARG = 2;
+  lambda (1);
+}
+
+void Baz ()
+{
+  Foo ([] (auto &&ARG) {});
+}
Index: testsuite/g++.dg/cpp1y/pr79253.C
===================================================================
--- testsuite/g++.dg/cpp1y/pr79253.C	(revision 0)
+++ testsuite/g++.dg/cpp1y/pr79253.C	(working copy)
@@ -0,0 +1,33 @@
+// { dg-do compile { target c++14 } }
+// PR 79253 ICE instantiating lambda body.
+
+template <typename> struct A;
+template <typename = A<int>> class B {};
+template <class T, class U, class V> void foo (U, V) { T (0, 0); }
+struct C {};
+template <template <bool, bool, bool> class F, class>
+void
+bar ()
+{
+  F<0, 0, 0>::baz;
+}
+struct G { int l; };
+template <int, int, int> struct E : C
+{
+  E (int, int) : e (0)
+  {
+    auto &m = this->m ();
+    auto c = [&] { m.l; };
+  }
+  G &m ();
+  int e;
+};
+struct D
+{
+  void
+  baz () { bar<F, B<>>; }
+  template <bool, bool, bool> struct F
+  {
+    static B<> baz () { foo<E<0, 0, 0>> (0, 0); }
+  };
+};

Reply via email to