From 539f481a292d606bd7cf092880c51412e95d92b6 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Wed, 17 May 2017 15:41:23 +0000 Subject: [PATCH] cp-tree.h (default_hash_traits ): New specialization. * cp-tree.h (default_hash_traits ): 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 | 10 +++ gcc/cp/cp-tree.h | 20 +++++ gcc/cp/name-lookup.c | 198 ++++++++++++++++--------------------------- 3 files changed, 102 insertions(+), 126 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f657194f419..c404cedc783 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2017-05-17 Nathan Sidwell + + * cp-tree.h (default_hash_traits ): 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 PR c++/80654 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 921118635a6..25b05ef6cd0 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 + : pointer_hash , ggc_remove +{ + /* 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 acd8b14c5b7..83ef7c74230 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 *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::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 -- 2.30.2