diff mbox series

[C++] Simplify overloads

Message ID 374c8f9b-bc6b-299a-cc30-15d884d1d670@acm.org
State New
Headers show
Series [C++] Simplify overloads | expand

Commit Message

Nathan Sidwell Oct. 31, 2018, 12:40 p.m. UTC
When I redid namespace-scope name lookup I made overload sets ordered 
hidden, then using, then other.  This was with an eye to how modules 
would need to extend that to add 'exported' on the end.  Turns out 
that's not needed, so we can simplify a bit.  This patch changes things 
so that using and non-using decls are unordered, but still come after 
the hidden decls.  We have to add another flag into the overload though 
to say whether a set contains a using-decl.  That engages de-duplication 
machinery during the lookup.  Previously that machinery could just look 
at the first (non-hidden) decl to find out it was needed.

I've been using a variant of this on the modules branch for some time.

booted & tested on x86_64-linux, applying to trunk.

nathan
diff mbox series

Patch

2018-10-31  Nathan Sidwell  <nathan@acm.org>

	gcc/cp/
	* cp-tree.h (OVL_DEDUP_P): New.
	* name-lookup.c (name_lookup::add_overload): Check OVL_DEDUP_P.
	(get_class_binding_direct): Likwise.
	* tree.c (ovl_make): Propagate OVL_DEDUP_P.
	(ovl_copy): Copy it.
	(ovl_insert): Do not keep using-decls ordered.
	(lookup_maybe_add): Adjust comment.

	gcc/testsuite/
	* g++.dg/lookup/using60.C: New.

Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 265671)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -409,6 +409,7 @@  extern GTY(()) tree cp_global_trees[CPTI
       SWITCH_STMT_ALL_CASES_P (in SWITCH_STMT)
       REINTERPRET_CAST_P (in NOP_EXPR)
       ALIGNOF_EXPR_STD_P (in ALIGNOF_EXPR)
+      OVL_DEDUP_P (in OVERLOAD)
    1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -695,6 +696,8 @@  typedef struct ptrmem_cst * ptrmem_cst_t
 #define OVL_CHAIN(NODE) \
   (((struct tree_overload*)OVERLOAD_CHECK (NODE))->common.chain)
 
+/* If set, this or a subsequent overload contains decls that need deduping.  */
+#define OVL_DEDUP_P(NODE)	TREE_LANG_FLAG_0 (OVERLOAD_CHECK (NODE))
 /* If set, this was imported in a using declaration.   */
 #define OVL_USING_P(NODE)	TREE_LANG_FLAG_1 (OVERLOAD_CHECK (NODE))
 /* If set, this overload is a hidden decl.  */
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 265671)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -422,7 +422,8 @@  name_lookup::add_overload (tree fns)
       tree probe = fns;
       if (flags & LOOKUP_HIDDEN)
 	probe = ovl_skip_hidden (probe);
-      if (probe && TREE_CODE (probe) == OVERLOAD && OVL_USING_P (probe))
+      if (probe && TREE_CODE (probe) == OVERLOAD
+	  && OVL_DEDUP_P (probe))
 	{
 	  /* We're about to add something found by a using
 	     declaration, so need to engage deduping mode.  */
@@ -1260,7 +1261,8 @@  get_class_binding_direct (tree klass, tr
 
       if (type_or_fns < 0)
 	/* Don't bother looking for field.  We don't want it.  */;
-      else if (!val || (TREE_CODE (val) == OVERLOAD && OVL_USING_P (val)))
+      else if (!val || (TREE_CODE (val) == OVERLOAD
+			&& OVL_DEDUP_P (val)))
 	/* Dependent using declarations are a 'field', make sure we
 	   return that even if we saw an overload already.  */
 	if (tree field_val = fields_linear_search (klass, lookup,
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	(revision 265671)
+++ gcc/cp/tree.c	(working copy)
@@ -2153,6 +2153,8 @@  ovl_make (tree fn, tree next)
 
   TREE_TYPE (result) = (next || TREE_CODE (fn) == TEMPLATE_DECL
 			? unknown_type_node : TREE_TYPE (fn));
+  if (next && TREE_CODE (next) == OVERLOAD && OVL_DEDUP_P (next))
+    OVL_DEDUP_P (result) = true;
   OVL_FUNCTION (result) = fn;
   OVL_CHAIN (result) = next;
   return result;
@@ -2167,64 +2169,54 @@  ovl_copy (tree ovl)
   TREE_TYPE (result) = TREE_TYPE (ovl);
   OVL_FUNCTION (result) = OVL_FUNCTION (ovl);
   OVL_CHAIN (result) = OVL_CHAIN (ovl);
+  OVL_DEDUP_P (result) = OVL_DEDUP_P (ovl);
+  OVL_LOOKUP_P (result) = OVL_LOOKUP_P (ovl);
   OVL_HIDDEN_P (result) = OVL_HIDDEN_P (ovl);
   OVL_USING_P (result) = OVL_USING_P (ovl);
-  OVL_LOOKUP_P (result) = OVL_LOOKUP_P (ovl);
 
   return result;
 }
 
 /* Add FN to the (potentially NULL) overload set OVL.  USING_P is
    true, if FN is via a using declaration.  We also pay attention to
-   DECL_HIDDEN.  Overloads are ordered as hidden, using, regular.  */
+   DECL_HIDDEN.  We keep the hidden decls first, but remaining ones
+   are unordered.  */
 
 tree
 ovl_insert (tree fn, tree maybe_ovl, bool using_p)
 {
-  bool copying = false; /* Checking use only.  */
-  bool hidden_p = DECL_HIDDEN_P (fn);
-  int weight = (hidden_p << 1) | (using_p << 0);
-
-  tree result = NULL_TREE;
+  tree result = maybe_ovl;
   tree insert_after = NULL_TREE;
 
-  /* Find insertion point.  */
-  while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
-	 && (weight < ((OVL_HIDDEN_P (maybe_ovl) << 1)
-		       | (OVL_USING_P (maybe_ovl) << 0))))
+  /* Skip hidden.  */
+  for (; maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
+	 && OVL_HIDDEN_P (maybe_ovl);
+       maybe_ovl = OVL_CHAIN (maybe_ovl))
     {
       gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl)
-			   && (!copying || OVL_USED_P (maybe_ovl)));
-      if (OVL_USED_P (maybe_ovl))
-	{
-	  copying = true;
-	  maybe_ovl = ovl_copy (maybe_ovl);
-	  if (insert_after)
-	    OVL_CHAIN (insert_after) = maybe_ovl;
-	}
-      if (!result)
-	result = maybe_ovl;
+			   && !OVL_USED_P (maybe_ovl));
       insert_after = maybe_ovl;
-      maybe_ovl = OVL_CHAIN (maybe_ovl);
     }
 
-  tree trail = fn;
+  bool hidden_p = DECL_HIDDEN_P (fn);
   if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL)
     {
-      trail = ovl_make (fn, maybe_ovl);
+      maybe_ovl = ovl_make (fn, maybe_ovl);
       if (hidden_p)
-	OVL_HIDDEN_P (trail) = true;
+	OVL_HIDDEN_P (maybe_ovl) = true;
       if (using_p)
-	OVL_USING_P (trail) = true;
+	OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true;
     }
+  else
+    maybe_ovl = fn;
 
   if (insert_after)
     {
-      OVL_CHAIN (insert_after) = trail;
+      OVL_CHAIN (insert_after) = maybe_ovl;
       TREE_TYPE (insert_after) = unknown_type_node;
     }
   else
-    result = trail;
+    result = maybe_ovl;
 
   return result;
 }
@@ -2367,7 +2359,8 @@  lookup_maybe_add (tree fns, tree lookup,
 	    for (; fns != probe; fns = OVL_CHAIN (fns))
 	      {
 		lookup = lookup_add (OVL_FUNCTION (fns), lookup);
-		/* Propagate OVL_USING, but OVL_HIDDEN doesn't matter.  */
+		/* Propagate OVL_USING, but OVL_HIDDEN &
+		   OVL_DEDUP_P don't matter.  */
 		if (OVL_USING_P (fns))
 		  OVL_USING_P (lookup) = true;
 	      }
Index: gcc/testsuite/g++.dg/lookup/using60.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using60.C	(revision 0)
+++ gcc/testsuite/g++.dg/lookup/using60.C	(working copy)
@@ -0,0 +1,18 @@ 
+// ICE with overloads not ordering using decls.  Failed to invoke
+// deduping logic
+
+void remove (const char *);
+
+namespace std
+{
+  using ::remove;
+
+  void remove ();
+}
+
+using namespace std;
+
+void test01 ()
+{
+  remove (0);
+}