diff mbox series

[C++] hash-table for extern-c fns.

Message ID 8423b154-14ac-0263-aa18-01752c6894ef@acm.org
State New
Headers show
Series [C++] hash-table for extern-c fns. | expand

Commit Message

Nathan Sidwell Oct. 6, 2017, 2:18 p.m. UTC
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

Comments

Jason Merrill Oct. 9, 2017, 3:57 p.m. UTC | #1
On Fri, Oct 6, 2017 at 10:18 AM, Nathan Sidwell <nathan@acm.org> wrote:
> 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.

Hmm, why do we only check extern "C" conflicts for functions?

Jason
Nathan Sidwell Oct. 9, 2017, 10:15 p.m. UTC | #2
On 10/09/2017 11:57 AM, Jason Merrill wrote:
> On Fri, Oct 6, 2017 at 10:18 AM, Nathan Sidwell <nathan@acm.org> wrote:
>> This patch converts the extern "C" function map to use a hash table, in the
>> same way as I've just changed namespace bindings.

> Hmm, why do we only check extern "C" conflicts for functions?

I suspect a bug.  I noticed it as existing behaviour and was puzzled the first 
time around rearranging this code, but didn't want to get distracted from the 
big picture.

nathan
Nathan Sidwell Oct. 10, 2017, 7:11 p.m. UTC | #3
On 10/09/2017 06:15 PM, Nathan Sidwell wrote:
> On 10/09/2017 11:57 AM, Jason Merrill wrote:

>> Hmm, why do we only check extern "C" conflicts for functions?
> 
> I suspect a bug.  I noticed it as existing behaviour and was puzzled the 
> first time around rearranging this code, but didn't want to get 
> distracted from the big picture.

This patch checks both vars and fns (as typedefs don't have linkage, I 
don't think they can be extern C, but ICBW).

I also tweaked the diagnostics, so that the first one is a pedwarn and 
the later ones are notes. (so we won't arbitrarily truncate the series 
of diagnostics.

Look good to you?

nathan
Jason Merrill Oct. 10, 2017, 7:49 p.m. UTC | #4
On Tue, Oct 10, 2017 at 3:11 PM, Nathan Sidwell <nathan@acm.org> wrote:
> On 10/09/2017 06:15 PM, Nathan Sidwell wrote:
>>
>> On 10/09/2017 11:57 AM, Jason Merrill wrote:
>
>
>>> Hmm, why do we only check extern "C" conflicts for functions?
>>
>>
>> I suspect a bug.  I noticed it as existing behaviour and was puzzled the
>> first time around rearranging this code, but didn't want to get distracted
>> from the big picture.
>
>
> This patch checks both vars and fns (as typedefs don't have linkage, I don't
> think they can be extern C, but ICBW).
>
> I also tweaked the diagnostics, so that the first one is a pedwarn and the
> later ones are notes. (so we won't arbitrarily truncate the series of
> diagnostics.
>
> Look good to you?

Yes, thanks.
diff mbox series

Patch

2017-10-06  Nathan Sidwell  <nathan@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;
 }