diff mbox

[C++] OVERLOAD iterators #5

Message ID f31df86c-d516-ae41-7af5-c4fdc34f8161@acm.org
State New
Headers show

Commit Message

Nathan Sidwell May 17, 2017, 12:44 p.m. UTC
This patch fixes up add_method.  There are two things going on here

1) a new ovl_insert worker to add a new decl to an existing overload 
set.  This is no longer simply prepending the new decl, as we keep the 
set ordered.  The eventual ordering will be 
hidden->using->regular->exported.  But at this point we just keep the 
using decls before the regular ones.  Hidden handling will be later and 
of course exports is a modules thing. (hidden fns are both friend 
injections and anticipated builtins)

2) a remove_node worker, rather than have users directly stitch out the 
node.

Both these behaviours mean that there's an issue with overload lookups 
that are stashed in uninstantiated templates.  If we can subsequently go 
modifying that lookup, a later instantiation may see different functions 
than it should do.  We already have this problem because of #2 (users 
directly stitching out), and #1 now introduces another way it can 
happen.  This patch does not address that problem.  I have further 
patches to rectify this.  There are no new testcase failures because of 
this problem (I have new testcases too).

nathan
diff mbox

Patch

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

	* cp-tree.h (ovl_iterator::using_p): New predicate.
	(ovl_iterator::remove_node): New worker.
	(ovl_insert): Declare.
	* tree.c (ovl_insert): New.
	(ovl_iterator::remove_node): New.
	* class.c (add_method): Use ovl_iterator, ovl_insert.
	(clone_function_decl): Fix description.
	(clone_constructors_and_destructors): Use ovl_iterator.

Index: class.c
===================================================================
--- class.c	(revision 248144)
+++ class.c	(working copy)
@@ -1010,7 +1010,6 @@  bool
 add_method (tree type, tree method, bool via_using)
 {
   unsigned slot;
-  tree overload;
   bool template_conv_p = false;
   bool conv_p;
   vec<tree, va_gc> *method_vec;
@@ -1059,7 +1058,7 @@  add_method (tree type, tree method, bool
 	   vec_safe_iterate (method_vec, slot, &m);
 	   ++slot)
 	{
-	  m = OVL_CURRENT (m);
+	  m = OVL_FIRST (m);
 	  if (template_conv_p)
 	    {
 	      if (TREE_CODE (m) == TEMPLATE_DECL
@@ -1083,24 +1082,23 @@  add_method (tree type, tree method, bool
   current_fns = insert_p ? NULL_TREE : (*method_vec)[slot];
 
   /* Check to see if we've already got this method.  */
-  for (tree *p = &current_fns; *p; )
+  for (ovl_iterator iter (current_fns); iter; ++iter)
     {
-      tree fns = *p;
-      tree fn = OVL_CURRENT (fns);
+      tree fn = *iter;
       tree fn_type;
       tree method_type;
       tree parms1;
       tree parms2;
 
       if (TREE_CODE (fn) != TREE_CODE (method))
-	goto cont;
+	continue;
 
       /* Two using-declarations can coexist, we'll complain about ambiguity in
 	 overload resolution.  */
-      if (via_using && TREE_CODE (fns) == OVERLOAD && OVL_USED (fns)
+      if (via_using && iter.using_p ()
 	  /* Except handle inherited constructors specially.  */
 	  && ! DECL_CONSTRUCTOR_P (fn))
-	goto cont;
+	continue;
 
       /* [over.load] Member function declarations with the
 	 same name and the same parameter types cannot be
@@ -1134,7 +1132,7 @@  add_method (tree type, tree method, bool
 	      == FUNCTION_REF_QUALIFIED (method_type))
 	  && (type_memfn_quals (fn_type) != type_memfn_quals (method_type)
 	      || type_memfn_rqual (fn_type) != type_memfn_rqual (method_type)))
-	  goto cont;
+	  continue;
 
       /* For templates, the return type and template parameters
 	 must be identical.  */
@@ -1143,7 +1141,7 @@  add_method (tree type, tree method, bool
 			    TREE_TYPE (method_type))
 	      || !comp_template_parms (DECL_TEMPLATE_PARMS (fn),
 				       DECL_TEMPLATE_PARMS (method))))
-	goto cont;
+	continue;
 
       if (! DECL_STATIC_FUNCTION_P (fn))
 	parms1 = TREE_CHAIN (parms1);
@@ -1187,8 +1185,9 @@  add_method (tree type, tree method, bool
 		    mangle_decl (method);
 		}
 	      cgraph_node::record_function_versions (fn, method);
-	      goto cont;
+	      continue;
 	    }
+
 	  if (DECL_INHERITED_CTOR (method))
 	    {
 	      if (DECL_INHERITED_CTOR (fn))
@@ -1202,7 +1201,7 @@  add_method (tree type, tree method, bool
 			  /* Inheriting the same constructor along different
 			     paths, combine them.  */
 			  SET_DECL_INHERITED_CTOR
-			    (fn, ovl_cons (DECL_INHERITED_CTOR (method),
+			    (fn, ovl_make (DECL_INHERITED_CTOR (method),
 					   DECL_INHERITED_CTOR (fn)));
 			  /* And discard the new one.  */
 			  return false;
@@ -1210,7 +1209,7 @@  add_method (tree type, tree method, bool
 		      else
 			/* Inherited ctors can coexist until overload
 			   resolution.  */
-			goto cont;
+			continue;
 		    }
 		  error_at (DECL_SOURCE_LOCATION (method),
 			    "%q#D", method);
@@ -1228,8 +1227,8 @@  add_method (tree type, tree method, bool
 	  else if (flag_new_inheriting_ctors
 		   && DECL_INHERITED_CTOR (fn))
 	    {
-	      /* Hide the inherited constructor.  */
-	      *p = OVL_NEXT (fns);
+	      /* Remove the inherited constructor.  */
+	      current_fns = iter.remove_node (current_fns);
 	      continue;
 	    }
 	  else
@@ -1238,33 +1237,19 @@  add_method (tree type, tree method, bool
 	      error ("with %q+#D", fn);
 	      return false;
 	    }
-
 	}
-
-    cont:
-      if (TREE_CODE (fns) == OVERLOAD)
-	p = &OVL_CHAIN (fns);
-      else
-	break;
     }
 
   /* A class should never have more than one destructor.  */
   if (current_fns && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
     return false;
 
-  /* Add the new binding.  */
-  if (via_using)
-    {
-      overload = ovl_cons (method, current_fns);
-      OVL_USED (overload) = true;
-    }
-  else
-    overload = build_overload (method, current_fns);
+  current_fns = ovl_insert (method, current_fns, via_using);
 
   if (conv_p)
     TYPE_HAS_CONVERSION (type) = 1;
   else if (slot >= CLASSTYPE_FIRST_CONVERSION_SLOT && !complete_p)
-    push_class_level_binding (DECL_NAME (method), overload);
+    push_class_level_binding (DECL_NAME (method), current_fns);
 
   if (insert_p)
     {
@@ -1279,13 +1264,13 @@  add_method (tree type, tree method, bool
       if (reallocated)
 	CLASSTYPE_METHOD_VEC (type) = method_vec;
       if (slot == method_vec->length ())
-	method_vec->quick_push (overload);
+	method_vec->quick_push (current_fns);
       else
-	method_vec->quick_insert (slot, overload);
+	method_vec->quick_insert (slot, current_fns);
     }
   else
     /* Replace the current slot.  */
-    (*method_vec)[slot] = overload;
+    (*method_vec)[slot] = current_fns;
   return true;
 }
 
@@ -4873,8 +4858,7 @@  decl_cloned_function_p (const_tree decl,
 
 /* Produce declarations for all appropriate clones of FN.  If
    UPDATE_METHODS is true, the clones are added to the
-   CLASTYPE_METHOD_VEC.  VIA_USING indicates whether these are cloning
-   decls brought in via using declarations (i.e. inheriting ctors).  */
+   CLASSTYPE_METHOD_VEC.  */
 
 void
 clone_function_decl (tree fn, bool update_methods)
@@ -5017,8 +5001,6 @@  adjust_clone_args (tree decl)
 static void
 clone_constructors_and_destructors (tree t)
 {
-  tree fns;
-
   /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail
      out now.  */
   if (!CLASSTYPE_METHOD_VEC (t))
@@ -5026,10 +5008,10 @@  clone_constructors_and_destructors (tree
 
   /* While constructors can be via a using declaration, at this point
      we no longer need to know that.  */
-  for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
-    clone_function_decl (OVL_CURRENT (fns), /*update_methods=*/true);
-  for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
-    clone_function_decl (OVL_CURRENT (fns), /*update_methods=*/true);
+  for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+    clone_function_decl (*iter, /*update_methods=*/true);
+  for (ovl_iterator iter (CLASSTYPE_DESTRUCTORS (t)); iter; ++iter)
+    clone_function_decl (*iter, /*update_methods=*/true);
 }
 
 /* Deduce noexcept for a destructor DTOR.  */
Index: cp-tree.h
===================================================================
--- cp-tree.h	(revision 248144)
+++ cp-tree.h	(working copy)
@@ -680,6 +680,22 @@  class ovl_iterator
 
     return fn;
   }
+
+ public:
+  /* Whether this overload was introduced by a using decl.  */
+  bool using_p () const
+  {
+    return TREE_CODE (ovl) == OVERLOAD && OVL_USED (ovl);
+  }
+  tree remove_node (tree head)
+  {
+    return remove_node (head, ovl);
+  }
+
+ private:
+  /* We make this a static function to avoid the address of the
+     iterator escaping the local context.  */
+  static tree remove_node (tree head, tree node);
 };
 
 /* Iterator over a (potentially) 2 dimensional overload, which is
@@ -6768,6 +6784,8 @@  extern tree build_ref_qualified_type		(t
 inline tree ovl_first				(tree) ATTRIBUTE_PURE;
 extern tree ovl_make				(tree fn,
 						 tree next = NULL_TREE);
+extern tree ovl_insert				(tree fn, tree maybe_ovl,
+						 bool using_p = false);
 extern tree lookup_add				(tree lookup, tree ovl);
 extern int is_overloaded_fn			(tree);
 extern tree dependent_name			(tree);
Index: tree.c
===================================================================
--- tree.c	(revision 248144)
+++ tree.c	(working copy)
@@ -2124,6 +2124,65 @@  ovl_make (tree fn, tree next)
   return result;
 }
 
+/* Add FN to the (potentially NULL) overload set OVL.  USING_P is
+   true, if FN is via a using declaration.  Overloads are ordered as
+   using, regular.  */
+
+tree
+ovl_insert (tree fn, tree maybe_ovl, bool using_p)
+{
+  int weight = using_p;
+
+  tree result = NULL_TREE;
+  tree insert_after = NULL_TREE;
+
+  /* Find insertion point.  */
+  while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
+	 && (weight < OVL_USED (maybe_ovl)))
+    {
+      if (!result)
+	result = maybe_ovl;
+      insert_after = maybe_ovl;
+      maybe_ovl = OVL_CHAIN (maybe_ovl);
+    }
+
+  tree trail = fn;
+  if (maybe_ovl || using_p || TREE_CODE (fn) == TEMPLATE_DECL)
+    {
+      trail = ovl_make (fn, maybe_ovl);
+      if (using_p)
+	OVL_USED (trail) = true;
+    }
+
+  if (insert_after)
+    {
+      TREE_CHAIN (insert_after) = trail;
+      TREE_TYPE (insert_after) = unknown_type_node;
+    }
+  else
+    result = trail;
+
+  return result;
+}
+
+/* NODE is on the overloads of OVL.  Remove it.  */
+
+tree
+ovl_iterator::remove_node (tree overload, tree node)
+{
+  tree *slot = &overload;
+  while (*slot != node)
+    slot = &OVL_CHAIN (*slot);
+
+  /* Stitch out NODE.  We don't have to worry about now making a
+     singleton overload (and consequently maybe setting its type),
+     because all uses of this function will be followed by inserting a
+     new node that must follow the place we've cut this out from.  */
+  *slot = OVL_CHAIN (node);
+
+  return overload;
+}
+
 /* Add a potential overload into a lookup set.  */
 
 tree