This is another case of lookups escaping into template bodies, without being marked. In this case an initializer list.

in the non-template case, we try and recycle these lookup nodes immediately. But for templates we have to mark lookups, so we don't try and mutate them via the binding. When the lookup involved via a using directive we can detect the marking failure.

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

	PR c++/84970
	* cp-tree.h (lookup_list_keep): Declare.
	* tree.c (lookup_list_keep): New, broken out of ...
	(build_min): ... here.  Call it.
	* decl.c (cp_finish_decl): Call lookup_list_keep.

	PR c++/84970
	* g++.dg/lookup/pr84970.C: New.

Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 258676)
+++ cp/cp-tree.h	(working copy)
@@ -7012,6 +7012,7 @@ extern tree lookup_add				(tree fns, tre
 extern tree lookup_maybe_add			(tree fns, tree lookup,
 						 bool deduping);
 extern void lookup_keep				(tree lookup, bool keep);
+extern void lookup_list_keep			(tree list, bool keep);
 extern int is_overloaded_fn			(tree) ATTRIBUTE_PURE;
 extern bool really_overloaded_fn		(tree) ATTRIBUTE_PURE;
 extern tree dependent_name			(tree);
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 258676)
+++ cp/decl.c	(working copy)
@@ -7034,7 +7034,11 @@ cp_finish_decl (tree decl, tree init, bo
 	}
 
       if (init)
-	DECL_INITIAL (decl) = init;
+	{
+	  if (TREE_CODE (init) == TREE_LIST)
+	    lookup_list_keep (init, true);
+	  DECL_INITIAL (decl) = init;
+	}
       if (dep_init)
 	{
 	  retrofit_lang_decl (decl);
Index: cp/tree.c
===================================================================
--- cp/tree.c	(revision 258676)
+++ cp/tree.c	(working copy)
@@ -2436,6 +2436,20 @@ lookup_keep (tree lookup, bool keep)
     ovl_used (lookup);
 }
 
+/* LIST is a TREE_LIST whose TREE_VALUEs may be OVERLOADS that need
+   keeping, or may be ignored.  */
+
+void
+lookup_list_keep (tree list, bool keep)
+{
+  for (; list; list = TREE_CHAIN (list))
+    {
+      tree v = TREE_VALUE (list);
+      if (TREE_CODE (v) == OVERLOAD)
+	lookup_keep (v, keep);
+    }
+}
+
 /* Returns nonzero if X is an expression for a (possibly overloaded)
    function.  If "f" is a function or function template, "f", "c->f",
    "c.f", "C::f", and "f<int>" will all be considered possibly
@@ -3315,9 +3329,7 @@ build_min (enum tree_code code, tree tt,
 
   if (code == CAST_EXPR)
     /* The single operand is a TREE_LIST, which we have to check.  */
-    for (tree v = TREE_OPERAND (t, 0); v; v = TREE_CHAIN (v))
-      if (TREE_CODE (TREE_VALUE (v)) == OVERLOAD)
-	lookup_keep (TREE_VALUE (v), true);
+    lookup_list_keep (TREE_OPERAND (t, 0), true);
 
   return t;
 }
Index: testsuite/g++.dg/lookup/pr84970.C
===================================================================
--- testsuite/g++.dg/lookup/pr84970.C	(revision 0)
+++ testsuite/g++.dg/lookup/pr84970.C	(working copy)
@@ -0,0 +1,21 @@
+// PR c++/84970 ICE with deferred initializer
+
+namespace bob {
+  void a();
+}
+using namespace bob;
+
+void a (int);
+
+template <typename b>
+void *x (b)
+{
+  void (*c)(b) (a);
+
+  return (void *)c;
+}
+
+void d () {
+  x (1);
+}
+

Reply via email to