aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2017-05-17 15:41:23 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2017-05-17 15:41:23 +0000
commit539f481a292d606bd7cf092880c51412e95d92b6 (patch)
tree53aba9673ac838d39acb0850e6b131d32bdb8607 /gcc/cp
parente5b1f5a1d11f73ff289ffebfeccbc0650531367b (diff)
downloadgcc-539f481a292d606bd7cf092880c51412e95d92b6.zip
gcc-539f481a292d606bd7cf092880c51412e95d92b6.tar.gz
gcc-539f481a292d606bd7cf092880c51412e95d92b6.tar.bz2
cp-tree.h (default_hash_traits <lang_identifier *>): New specialization.
* 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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog10
-rw-r--r--gcc/cp/cp-tree.h20
-rw-r--r--gcc/cp/name-lookup.c198
3 files changed, 102 insertions, 126 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index f657194..c404ced 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9211186..25b05ef 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index acd8b14..83ef7c7 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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