cp-tree.h (default_hash_traits <lang_identifier *>): New specialization.
authorNathan Sidwell <nathan@acm.org>
Wed, 17 May 2017 15:41:23 +0000 (15:41 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 17 May 2017 15:41:23 +0000 (15:41 +0000)
* cp-tree.h (default_hash_traits <lang_identifier *>): New
specialization.
* name-lookup.c (lookup_extern_c_fun_in_all_ns): Delete.
(extern_c_fns): New hash table.
(check_extern_c_conflict): New, broken out of ...
(pushdecl_maybe_friend_1): ... here.  Call it.
(c_linkage_bindings): Just look in hash table.

From-SVN: r248159

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/name-lookup.c

index f657194..c404ced 100644 (file)
@@ -1,3 +1,13 @@
+2017-05-17  Nathan Sidwell  <nathan@acm.org>
+
+       * cp-tree.h (default_hash_traits <lang_identifier *>): New
+       specialization.
+       * name-lookup.c (lookup_extern_c_fun_in_all_ns): Delete.
+       (extern_c_fns): New hash table.
+       (check_extern_c_conflict): New, broken out of ...
+       (pushdecl_maybe_friend_1): ... here.  Call it.
+       (c_linkage_bindings): Just look in hash table.
+
 2017-05-17  Ville Voutilainen  <ville.voutilainen@gmail.com>
 
        PR c++/80654
index 9211186..25b05ef 100644 (file)
@@ -535,6 +535,26 @@ identifier_p (tree t)
   return NULL;
 }
 
+/* Hash trait specialization for lang_identifiers.  This allows
+   PCH-safe maps keyed by DECL_NAME.  If it wasn't for PCH, we could
+   just use a regular tree key.  */
+
+template <>
+struct default_hash_traits <lang_identifier *>
+  : pointer_hash <tree_node>, ggc_remove <tree>
+{
+  /* Use a regular tree as the type, to make using the hash table
+     simpler.  We'll get dynamic type checking with the hash function
+     itself.  */
+  GTY((skip)) typedef tree value_type;
+  GTY((skip)) typedef tree compare_type;
+
+  static hashval_t hash (const value_type &id)
+  {
+    return IDENTIFIER_HASH_VALUE (id);
+  }
+};
+
 /* In an IDENTIFIER_NODE, nonzero if this identifier is actually a
    keyword.  C_RID_CODE (node) is then the RID_* value of the keyword.  */
 
index acd8b14..83ef7c7 100644 (file)
@@ -60,7 +60,6 @@ static void consider_binding_level (tree name,
                                    enum lookup_name_fuzzy_kind kind);
 static tree lookup_type_current_level (tree);
 static tree push_using_directive (tree);
-static tree lookup_extern_c_fun_in_all_ns (tree);
 static void diagnose_name_conflict (tree, tree);
 
 /* Add DECL to the list of things declared in B.  */
@@ -1184,6 +1183,75 @@ supplement_binding (cxx_binding *binding, tree decl)
   return ret;
 }
 
+/* Map of identifiers to extern C functions (or LISTS thereof).  */
+
+static GTY(()) hash_map<lang_identifier *, tree> *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
+   instance, add DECL to the map.  */
+
+static void
+check_extern_c_conflict (tree decl)
+{
+  /* Ignore artificial or system header decls.  */
+  if (DECL_ARTIFICIAL (decl) || DECL_IN_SYSTEM_HEADER (decl))
+    return;
+
+  if (!extern_c_fns)
+    extern_c_fns = hash_map<lang_identifier *,tree>::create_ggc (127);
+
+  bool existed;
+  tree *slot = &extern_c_fns->get_or_insert (DECL_NAME (decl), &existed);
+  if (!existed)
+    *slot = decl;
+  else
+    {
+      tree old = *slot;
+      if (TREE_CODE (old) == TREE_LIST)
+       old = TREE_VALUE (old);
+
+      int mismatch = 0;
+      if (DECL_CONTEXT (old) == DECL_CONTEXT (decl))
+       ; /* If they're in the same context, we'll have already complained
+            about a (possible) mismatch, when inserting the decl.  */
+      else if (!decls_match (decl, old))
+       mismatch = 1;
+      else if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old)),
+                                  TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)),
+                                  ce_normal))
+       mismatch = -1;
+      else if (DECL_ASSEMBLER_NAME_SET_P (old))
+       SET_DECL_ASSEMBLER_NAME (decl, DECL_ASSEMBLER_NAME (old));
+
+      if (mismatch)
+       {
+         pedwarn (input_location, 0,
+                  "declaration of %q#D with C language linkage", decl);
+         pedwarn (DECL_SOURCE_LOCATION (old), 0,
+                  "conflicts with previous declaration %q#D", old);
+         if (mismatch < 0)
+           pedwarn (input_location, 0,
+                    "due to different exception specifications");
+       }
+      else
+       /* Chain it on for c_linkage_binding's use.  */
+       *slot = tree_cons (NULL_TREE, decl, *slot);
+    }
+}
+
+/* Returns a list of C-linkage decls with the name NAME.  Used in
+   c-family/c-pragma.c to implement redefine_extname pragma.  */
+
+tree
+c_linkage_bindings (tree name)
+{
+  if (extern_c_fns)
+    if (tree *slot = extern_c_fns->get (name))
+      return *slot;
+  return NULL_TREE;
+}
+
 /* DECL is being declared at a local scope.  Emit suitable shadow
    warnings.  */
 
@@ -1591,63 +1659,6 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
            }
        }
 
-      /* If x has C linkage-specification, (extern "C"),
-        lookup its binding, in case it's already bound to an object.
-        The lookup is done in all namespaces.
-        If we find an existing binding, make sure it has the same
-        exception specification as x, otherwise, bail in error [7.5, 7.6].  */
-      if ((TREE_CODE (x) == FUNCTION_DECL)
-         && DECL_EXTERN_C_P (x)
-          /* We should ignore declarations happening in system headers.  */
-         && !DECL_ARTIFICIAL (x)
-         && !DECL_IN_SYSTEM_HEADER (x))
-       {
-         tree previous = lookup_extern_c_fun_in_all_ns (x);
-         if (previous
-             && !DECL_ARTIFICIAL (previous)
-              && !DECL_IN_SYSTEM_HEADER (previous)
-             && DECL_CONTEXT (previous) != DECL_CONTEXT (x))
-           {
-             /* In case either x or previous is declared to throw an exception,
-                make sure both exception specifications are equal.  */
-             if (decls_match (x, previous))
-               {
-                 tree x_exception_spec = NULL_TREE;
-                 tree previous_exception_spec = NULL_TREE;
-
-                 x_exception_spec =
-                               TYPE_RAISES_EXCEPTIONS (TREE_TYPE (x));
-                 previous_exception_spec =
-                               TYPE_RAISES_EXCEPTIONS (TREE_TYPE (previous));
-                 if (!comp_except_specs (previous_exception_spec,
-                                         x_exception_spec,
-                                         ce_normal))
-                   {
-                     pedwarn (input_location, 0,
-                               "declaration of %q#D with C language linkage",
-                              x);
-                     pedwarn (DECL_SOURCE_LOCATION (previous), 0,
-                               "conflicts with previous declaration %q#D",
-                              previous);
-                     pedwarn (input_location, 0,
-                               "due to different exception specifications");
-                     return error_mark_node;
-                   }
-                 if (DECL_ASSEMBLER_NAME_SET_P (previous))
-                   SET_DECL_ASSEMBLER_NAME (x,
-                                            DECL_ASSEMBLER_NAME (previous));
-               }
-             else
-               {
-                 pedwarn (input_location, 0,
-                          "declaration of %q#D with C language linkage", x);
-                 pedwarn (DECL_SOURCE_LOCATION (previous), 0,
-                          "conflicts with previous declaration %q#D",
-                          previous);
-               }
-           }
-       }
-
       check_template_shadow (x);
 
       /* If this is a function conjured up by the back end, massage it
@@ -1848,6 +1859,9 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 
       if (VAR_P (x))
        maybe_register_incomplete_var (x);
+      if (TREE_CODE (x) == FUNCTION_DECL && DECL_EXTERN_C_P (x))
+       /* We need to check and register the fn now.  */
+       check_extern_c_conflict (x);
     }
 
   if (need_new_binding)
@@ -2722,74 +2736,6 @@ binding_for_name (cp_binding_level *scope, tree name)
   return result;
 }
 
-/* Walk through the bindings associated to the name of FUNCTION,
-   and return the first declaration of a function with a
-   "C" linkage specification, a.k.a 'extern "C"'.
-   This function looks for the binding, regardless of which scope it
-   has been defined in. It basically looks in all the known scopes.
-   Note that this function does not lookup for bindings of builtin functions
-   or for functions declared in system headers.  */
-static tree
-lookup_extern_c_fun_in_all_ns (tree function)
-{
-  tree name;
-  cxx_binding *iter;
-
-  gcc_assert (function && TREE_CODE (function) == FUNCTION_DECL);
-
-  name = DECL_NAME (function);
-  gcc_assert (name && identifier_p (name));
-
-  for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name);
-       iter;
-       iter = iter->previous)
-    {
-      tree ovl;
-      for (ovl = iter->value; ovl; ovl = OVL_NEXT (ovl))
-       {
-         tree decl = OVL_CURRENT (ovl);
-         if (decl
-             && TREE_CODE (decl) == FUNCTION_DECL
-             && DECL_EXTERN_C_P (decl)
-             && !DECL_ARTIFICIAL (decl))
-           {
-             return decl;
-           }
-       }
-    }
-  return NULL;
-}
-
-/* Returns a list of C-linkage decls with the name NAME.  */
-
-tree
-c_linkage_bindings (tree name)
-{
-  tree decls = NULL_TREE;
-  cxx_binding *iter;
-
-  for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name);
-       iter;
-       iter = iter->previous)
-    {
-      tree ovl;
-      for (ovl = iter->value; ovl; ovl = OVL_NEXT (ovl))
-       {
-         tree decl = OVL_CURRENT (ovl);
-         if (decl
-             && DECL_EXTERN_C_P (decl)
-             && !DECL_ARTIFICIAL (decl))
-           {
-             if (decls == NULL_TREE)
-               decls = decl;
-             else
-               decls = tree_cons (NULL_TREE, decl, decls);
-           }
-       }
-    }
-  return decls;
-}
-
 /* Insert another USING_DECL into the current binding level, returning
    this declaration. If this is a redeclaration, do nothing, and
    return NULL_TREE if this not in namespace scope (in namespace