[PR,c++/84804] ICE with default arg, template friend & lambda

Message ID 1e982dd5-0741-1de1-18a0-019258e19710@acm.org
State New
Headers show
Series
  • [PR,c++/84804] ICE with default arg, template friend & lambda
Related show

Commit Message

Nathan Sidwell March 21, 2018, 3:55 p.m.
When instantiating a template we end up with a rather strange binding 
hierarchy -- the innermost binding is the template and the next one is 
the instantiation.  Anyway, the upshot is we end up trying to push a 
tsubst'd lambda into the template itself and die because that's marked 
as a complete type.  All somewhat suspicious.

However, there as a 'scope == ts_lambda' escape on that check, and I'd 
removed it because it seemed unneeded.  Sadly not.  As we now never pass 
ts_lambda into do_pushtag, we have to inspect the type being pushed to 
determine this check.  This gets us back to the older behaviour, but at 
least we push into the instantiation, not the template because of 
changes I made earlier.

nathan
-- 
Nathan Sidwell

Patch

2018-03-21  Nathan Sidwell  <nathan@acm.org>

	PR c++/84804
	* name-lookup.c (do_pushtag): Permit lambdas to be pushed into
	complete classes.


	PR c++/84804
	* g++.dg/lookup/pr84804.C: New.

Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c	(revision 258716)
+++ cp/name-lookup.c	(working copy)
@@ -6436,7 +6436,8 @@  do_pushtag (tree name, tree type, tag_sc
 
       if (b->kind == sk_class)
 	{
-	  if (!TYPE_BEING_DEFINED (current_class_type))
+	  if (!TYPE_BEING_DEFINED (current_class_type)
+	      && !LAMBDA_TYPE_P (type))
 	    return error_mark_node;
 
 	  if (!PROCESSING_REAL_TEMPLATE_DECL_P ())
Index: testsuite/g++.dg/lookup/pr84804.C
===================================================================
--- testsuite/g++.dg/lookup/pr84804.C	(revision 0)
+++ testsuite/g++.dg/lookup/pr84804.C	(working copy)
@@ -0,0 +1,12 @@ 
+// { dg-do compile { target c++11 } }
+// PR c++/84804 ICE instantiating friend with default arg containing a lambda
+template<int> struct A
+{
+  // Note, instantiation injects this into ::, so there can only be one!
+  friend void foo(int i = []{ return 0;}()) {}
+};
+
+void bar()
+{
+  A<0> x;
+}