This patch converts the extern "C" function map to use a hash table, in the same way as I've just changed namespace bindings.

There's a small wart, in that the c_linkage_bindings user (in c-common) expects either a single decl or a TREE_LIST. I.e. not an OVERLOAD. But the hasher expects either a DECL or an OVERLOAD. Rather than extend the hasher (and marginally pessimize it for this special case), I modify the extern-c table handling to insert an initial OVERLOAD node, when there are multiple functions. That can CHAIN directly to a TREE_LIST. Sure, we have a wasted OVERLOAD node in this case, but it's going to be rare -- programs don't usually declare extern "C" functions of the same name in different namespaces.

Changing the c-common function is harder, as OVERLOAD is a C++ FE local node.

Applying to trunk.

nathan
--
Nathan Sidwell
2017-10-06  Nathan Sidwell  <nat...@acm.org>

	Use hash_table for extern "C" names
	* name-lookup.c (extern_c_fns): Use hash_table.
	(check_extern_c_conflict): Adjust.
	(c_linkage_bindings): Adjust.

Index: name-lookup.c
===================================================================
--- name-lookup.c	(revision 253489)
+++ name-lookup.c	(working copy)
@@ -2511,9 +2511,9 @@ update_binding (cp_binding_level *level,
   return decl;
 }
 
-/* Map of identifiers to extern C functions (or LISTS thereof).  */
+/* Table of identifiers to extern C functions (or LISTS thereof).  */
 
-static GTY(()) hash_map<lang_identifier *, tree> *extern_c_fns;
+static GTY(()) hash_table<named_decl_hash> *extern_c_fns;
 
 /* DECL has C linkage. If we have an existing instance, make sure it
    has the same exception specification [7.5, 7.6].  If there's no
@@ -2527,17 +2527,15 @@ check_extern_c_conflict (tree decl)
     return;
 
   if (!extern_c_fns)
-    extern_c_fns = hash_map<lang_identifier *,tree>::create_ggc (127);
+    extern_c_fns = hash_table<named_decl_hash>::create_ggc (127);
 
-  bool existed;
-  tree *slot = &extern_c_fns->get_or_insert (DECL_NAME (decl), &existed);
-  if (!existed)
-    *slot = decl;
-  else
+  tree *slot = extern_c_fns
+    ->find_slot_with_hash (DECL_NAME (decl),
+			   IDENTIFIER_HASH_VALUE (DECL_NAME (decl)), INSERT);
+  if (tree old = *slot)
     {
-      tree old = *slot;
-      if (TREE_CODE (old) == TREE_LIST)
-	old = TREE_VALUE (old);
+      if (TREE_CODE (old) == OVERLOAD)
+	old = OVL_FUNCTION (old);
 
       int mismatch = 0;
       if (DECL_CONTEXT (old) == DECL_CONTEXT (decl))
@@ -2563,9 +2561,24 @@ check_extern_c_conflict (tree decl)
 		     "due to different exception specifications");
 	}
       else
-	/* Chain it on for c_linkage_binding's use.  */
-	*slot = tree_cons (NULL_TREE, decl, *slot);
+	{
+	  if (old == *slot)
+	    /* The hash table expects OVERLOADS, so construct one with
+	       OLD as both the function and the chain.  This allocate
+	       an excess OVERLOAD node, but it's rare to have multiple
+	       extern "C" decls of the same name.  And we save
+	       complicating the hash table logic (which is used
+	       elsewhere).  */
+	    *slot = ovl_make (old, old);
+
+	  slot = &OVL_CHAIN (*slot);
+
+	  /* Chain it on for c_linkage_binding's use.  */
+	  *slot = tree_cons (NULL_TREE, decl, *slot);
+	}
     }
+  else
+    *slot = decl;
 }
 
 /* Returns a list of C-linkage decls with the name NAME.  Used in
@@ -2575,8 +2588,15 @@ tree
 c_linkage_bindings (tree name)
 {
   if (extern_c_fns)
-    if (tree *slot = extern_c_fns->get (name))
-      return *slot;
+    if (tree *slot = extern_c_fns
+	->find_slot_with_hash (name, IDENTIFIER_HASH_VALUE (name), NO_INSERT))
+      {
+	tree result = *slot;
+	if (TREE_CODE (result) == OVERLOAD)
+	  result = OVL_CHAIN (result);
+	return result;
+      }
+
   return NULL_TREE;
 }
 

Reply via email to