diff mbox

[C++] Overload iterators #3

Message ID 3836fca5-70ad-332a-395d-e8aa8a08f27e@acm.org
State New
Headers show

Commit Message

Nathan Sidwell May 16, 2017, 6:33 p.m. UTC
This patch to do_class_deduction notices that we currently add some 
candidates and them immediately elide them from the set.  Why not just 
not add them?

Adding to the overload set uses a new lookup_add function, which in turn 
uses a new ovl_make.  A couple of new OVL_foo flags appear, which will 
be used more in subsequent patches.

Also, you may notice that nothing currently adds to the ovl_cache of 
reuseable overload nodes.  That'll be rectified shortly.

(I'll be killing the current ovl_cons and build_overload later.  One 
reason for the name changing is that it ensures I converted all the uses.)

nathan
diff mbox

Patch

2017-05-16  Nathan Sidwell  <nathan@acm.org>

	* cp-tree.h (OVL_NESTED_P, OVL_LOOKUP_P): New.
	(ovl_first): Move inline definition to end of file.
	(ovl_make, lookup_add): Declare.
	(get_fns, get_first_fn): Make pure.
	* tree.c (ovl_cache): New.
	(ovl_make, lookup_add): New.
	* pt.c (do_class_deduction): Don't add candidates that will be
	elided.

Index: cp-tree.h
===================================================================
--- cp-tree.h	(revision 248120)
+++ cp-tree.h	(working copy)
@@ -371,11 +371,13 @@  extern GTY(()) tree cp_global_trees[CPTI
       CALL_EXPR_ORDERED_ARGS (in CALL_EXPR, AGGR_INIT_EXPR)
       DECLTYPE_FOR_REF_CAPTURE (in DECLTYPE_TYPE)
       CONSTUCTOR_C99_COMPOUND_LITERAL (in CONSTRUCTOR)
+      OVL_NESTED_P (in OVERLOAD)
    4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
 	  CALL_EXPR, or FIELD_DECL).
       IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
       DECL_TINFO_P (in VAR_DECL)
       FUNCTION_REF_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
+      OVL_LOOKUP_P (in OVERLOAD)
    5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
       DECL_VTABLE_OR_VTT_P (in VAR_DECL)
       FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE)
@@ -626,6 +628,11 @@  typedef struct ptrmem_cst * ptrmem_cst_t
    and can be freed afterward.  */
 #define OVL_ARG_DEPENDENT(NODE) TREE_LANG_FLAG_0 (OVERLOAD_CHECK (NODE))
 
+/* If set, this overload contains a nested overload.  */
+#define OVL_NESTED_P(NODE)	TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE))
+/* If set, this overload was constructed during lookup.  */
+#define OVL_LOOKUP_P(NODE)	TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE))
+
 /* The first decl of an overload.  */
 #define OVL_FIRST(NODE)	ovl_first (NODE)
 /* The name of the overload set.  */
@@ -6733,17 +6740,14 @@  extern tree hash_tree_cons			(tree, tree
 extern tree hash_tree_chain			(tree, tree);
 extern tree build_qualified_name		(tree, tree, tree, bool);
 extern tree build_ref_qualified_type		(tree, cp_ref_qualifier);
-inline tree
-ovl_first (tree node)
-{
-  while (TREE_CODE (node) == OVERLOAD)
-    node = OVL_FUNCTION (node);
-  return node;
-}
+inline tree ovl_first				(tree) ATTRIBUTE_PURE;
+extern tree ovl_make				(tree fn,
+						 tree next = NULL_TREE);
+extern tree lookup_add				(tree lookup, tree ovl);
 extern int is_overloaded_fn			(tree);
 extern tree dependent_name			(tree);
-extern tree get_fns				(tree);
-extern tree get_first_fn			(tree);
+extern tree get_fns				(tree) ATTRIBUTE_PURE;
+extern tree get_first_fn			(tree) ATTRIBUTE_PURE;
 extern tree ovl_cons				(tree, tree);
 extern tree build_overload			(tree, tree);
 extern tree ovl_scope				(tree);
@@ -7188,6 +7192,16 @@  extern tree cp_ubsan_maybe_instrument_do
 extern tree cp_ubsan_maybe_instrument_cast_to_vbase (location_t, tree, tree);
 extern void cp_ubsan_maybe_initialize_vtbl_ptrs (tree);
 
+/* Inline bodies.  */
+
+inline tree
+ovl_first (tree node)
+{
+  while (TREE_CODE (node) == OVERLOAD)
+    node = OVL_FUNCTION (node);
+  return node;
+}
+
 /* -- end of C++ */
 
 #endif /* ! GCC_CP_TREE_H */
Index: pt.c
===================================================================
--- pt.c	(revision 248120)
+++ pt.c	(working copy)
@@ -25157,9 +25157,29 @@  do_class_deduction (tree ptype, tree tmp
   tree cands = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dname,
 				      /*type*/false, /*complain*/false,
 				      /*hidden*/false);
+  bool elided = false;
   if (cands == error_mark_node)
     cands = NULL_TREE;
 
+  /* Prune explicit deduction guides in copy-initialization context.  */
+  if (flags & LOOKUP_ONLYCONVERTING)
+    {
+      for (lkp_iterator iter (cands); !elided && iter; ++iter)
+	if (DECL_NONCONVERTING_P (STRIP_TEMPLATE (*iter)))
+	  elided = true;
+
+      if (elided)
+	{
+	  /* Found a nonconverting guide, prune the candidates.  */
+	  tree pruned = NULL_TREE;
+	  for (lkp_iterator iter (cands); iter; ++iter)
+	    if (!DECL_NONCONVERTING_P (STRIP_TEMPLATE (*iter)))
+	      pruned = lookup_add (pruned, *iter);
+
+	  cands = pruned;
+	}
+    }
+
   tree outer_args = NULL_TREE;
   if (DECL_CLASS_SCOPE_P (tmpl)
       && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (tmpl)))
@@ -25171,11 +25191,15 @@  do_class_deduction (tree ptype, tree tmp
   bool saw_ctor = false;
   if (CLASSTYPE_METHOD_VEC (type))
     // FIXME cache artificial deduction guides
-    for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
+    for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (type));
+	 iter; ++iter)
       {
-	tree fn = OVL_CURRENT (fns);
-	tree guide = build_deduction_guide (fn, outer_args, complain);
-	cands = ovl_cons (guide, cands);
+	tree guide = build_deduction_guide (*iter, outer_args, complain);
+	if ((flags & LOOKUP_ONLYCONVERTING)
+	    && DECL_NONCONVERTING_P (STRIP_TEMPLATE (guide)))
+	  elided = true;
+	else
+	  cands = lookup_add (cands, guide);
 
 	saw_ctor = true;
       }
@@ -25183,41 +25207,29 @@  do_class_deduction (tree ptype, tree tmp
   if (!saw_ctor && args->length() == 0)
     {
       tree guide = build_deduction_guide (type, outer_args, complain);
-      cands = ovl_cons (guide, cands);
+      if ((flags & LOOKUP_ONLYCONVERTING)
+	  && DECL_NONCONVERTING_P (STRIP_TEMPLATE (guide)))
+	elided = true;
+      else
+	cands = lookup_add (cands, guide);
     }
   if (args->length() == 1)
     {
       tree guide = build_deduction_guide (build_reference_type (type),
 					  outer_args, complain);
-      cands = ovl_cons (guide, cands);
+      if ((flags & LOOKUP_ONLYCONVERTING)
+	  && DECL_NONCONVERTING_P (STRIP_TEMPLATE (guide)))
+	elided = true;
+      else
+	cands = lookup_add (cands, guide);
     }
 
-  /* Prune explicit deduction guides in copy-initialization context.  */
-  tree old_cands = cands;
-  if (flags & LOOKUP_ONLYCONVERTING)
+  if (elided && !cands)
     {
-      tree t = cands;
-      for (; t; t = OVL_NEXT (t))
-	if (DECL_NONCONVERTING_P (STRIP_TEMPLATE (OVL_CURRENT (t))))
-	  break;
-      if (t)
-	{
-	  tree pruned = NULL_TREE;
-	  for (t = cands; t; t = OVL_NEXT (t))
-	    {
-	      tree f = OVL_CURRENT (t);
-	      if (!DECL_NONCONVERTING_P (STRIP_TEMPLATE (f)))
-		pruned = build_overload (f, pruned);
-	    }
-	  cands = pruned;
-	  if (cands == NULL_TREE)
-	    {
-	      error ("cannot deduce template arguments for copy-initialization"
-		     " of %qT, as it has no non-explicit deduction guides or "
-		     "user-declared constructors", type);
-	      return error_mark_node;
-	    }
-	}
+      error ("cannot deduce template arguments for copy-initialization"
+	     " of %qT, as it has no non-explicit deduction guides or "
+	     "user-declared constructors", type);
+      return error_mark_node;
     }
 
   ++cp_unevaluated_operand;
@@ -25227,7 +25239,7 @@  do_class_deduction (tree ptype, tree tmp
     {
       error ("class template argument deduction failed:");
       t = build_new_function_call (cands, &args, complain | tf_decltype);
-      if (old_cands != cands)
+      if (elided)
 	inform (input_location, "explicit deduction guides not considered "
 		"for copy-initialization");
     }
Index: tree.c
===================================================================
--- tree.c	(revision 248120)
+++ tree.c	(working copy)
@@ -2094,6 +2094,52 @@  build_ref_qualified_type (tree type, cp_
   return t;
 }
 
+/* Cache of free ovl nodes.  Uses OVL_FUNCTION for chaining.  */
+static GTY((deletable)) tree ovl_cache;
+
+/* Make a raw overload node containing FN.  */
+
+tree
+ovl_make (tree fn, tree next)
+{
+  tree result = ovl_cache;
+
+  if (result)
+    {
+      ovl_cache = OVL_FUNCTION (result);
+      /* Zap the flags.  */
+      memset (result, 0, sizeof (tree_base));
+      TREE_SET_CODE (result, OVERLOAD);
+    }
+  else
+    result = make_node (OVERLOAD);
+
+  if (TREE_CODE (fn) == OVERLOAD)
+    OVL_NESTED_P (result) = true;
+
+  TREE_TYPE (result) = (next || TREE_CODE (fn) == TEMPLATE_DECL
+			? unknown_type_node : TREE_TYPE (fn));
+  OVL_FUNCTION (result) = fn;
+  OVL_CHAIN (result) = next;
+  return result;
+}
+
+/* Add a potential overload into a lookup set.  */
+
+tree
+lookup_add (tree lookup, tree ovl)
+{
+  if (lookup || TREE_CODE (ovl) == TEMPLATE_DECL)
+    {
+      lookup = ovl_make (ovl, lookup);
+      OVL_LOOKUP_P (lookup) = true;
+    }
+  else
+    lookup = ovl;
+
+  return lookup;
+}
+
 /* 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