From 36d0108adfdd7d1123ac1a972ef04910af13137e Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 10 Dec 2020 06:54:37 -0800 Subject: [PATCH] c++: name-lookup refactoring Here are some refactorings to the name-lookup machinery. Primarily breakout out worker functions that the modules patch will also use. Fixing a couple of comments on the way. gcc/cp/ * name-lookup.c (pop_local_binding): Check for IDENTIFIER_ANON_P. (update_binding): Level may be null, don't add namespaces to level. (newbinding_bookkeeping): New, broken out of ... (do_pushdecl): ... here, call it. Don't push anonymous decls. (pushdecl, add_using_namespace): Correct comments. (do_push_nested_namespace): Remove assert. (make_namespace, make_namespace_finish): New, broken out of ... (push_namespace): ... here. Call them. Add namespace to level here. --- gcc/cp/name-lookup.c | 216 +++++++++++++++++++++++++++---------------- 1 file changed, 135 insertions(+), 81 deletions(-) diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index fa372810349..051ef0b36b1 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1916,7 +1916,7 @@ push_binding (tree id, tree decl, cp_binding_level* level) void pop_local_binding (tree id, tree decl) { - if (id == NULL_TREE) + if (!id || IDENTIFIER_ANON_P (id)) /* It's easiest to write the loops that call this function without checking whether or not the entities involved have names. We get here for such an entity. */ @@ -2266,8 +2266,9 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, tree to_type = old_type; bool local_overload = false; - gcc_assert (level->kind == sk_namespace ? !binding + gcc_assert (!level || level->kind == sk_namespace ? !binding : level->kind != sk_class && !slot); + if (old == error_mark_node) old = NULL_TREE; @@ -2343,7 +2344,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, warning (OPT_Wshadow, "%q#D hides constructor for %q#D", decl, to_type); - local_overload = old && level->kind != sk_namespace; + local_overload = old && level && level->kind != sk_namespace; to_val = ovl_insert (decl, old, -int (hiding)); } else if (old) @@ -2354,11 +2355,8 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, else if (TREE_CODE (old) == TYPE_DECL) { if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl))) - { - /* Two type decls to the same type. Do nothing. */ - gcc_checking_assert (!hiding); - return old; - } + /* Two type decls to the same type. Do nothing. */ + return old; else goto conflict; } @@ -2370,7 +2368,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, goto conflict; /* The new one must be an alias at this point. */ - gcc_assert (DECL_NAMESPACE_ALIAS (decl) && !hiding); + gcc_assert (DECL_NAMESPACE_ALIAS (decl)); return old; } else if (TREE_CODE (old) == VAR_DECL) @@ -2405,7 +2403,11 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, gcc_checking_assert (binding->value && OVL_P (binding->value)); update_local_overload (binding, to_val); } - else + else if (level + && !(TREE_CODE (decl) == NAMESPACE_DECL + && !DECL_NAMESPACE_ALIAS (decl))) + /* Don't add namespaces here. They're done in + push_namespace. */ add_decl_to_level (level, decl); if (slot) @@ -2911,6 +2913,41 @@ push_local_extern_decl_alias (tree decl) DECL_LOCAL_DECL_ALIAS (decl) = alias; } +/* DECL has just been bound at LEVEL. finish up the bookkeeping. */ + +static void +newbinding_bookkeeping (tree name, tree decl, cp_binding_level *level) +{ + if (TREE_CODE (decl) == TYPE_DECL) + { + tree type = TREE_TYPE (decl); + + if (type != error_mark_node) + { + if (TYPE_NAME (type) != decl) + set_underlying_type (decl); + + set_identifier_type_value_with_scope (name, decl, level); + + if (level->kind != sk_namespace + && !instantiating_current_function_p ()) + /* This is a locally defined typedef in a function that + is not a template instantation, record it to implement + -Wunused-local-typedefs. */ + record_locally_defined_typedef (decl); + } + } + else + { + if (VAR_P (decl) && !DECL_LOCAL_DECL_P (decl)) + maybe_register_incomplete_var (decl); + + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_EXTERN_C_P (decl)) + check_extern_c_conflict (decl); + } +} + /* Record DECL as belonging to the current lexical scope. Check for errors (such as an incompatible declaration for the same name already seen in the same scope). IS_FRIEND is true if DECL is @@ -2939,7 +2976,7 @@ do_pushdecl (tree decl, bool hiding) /* An anonymous namespace has a NULL DECL_NAME, but we still want to insert it. Other NULL-named decls, not so much. */ tree name = DECL_NAME (decl); - if (name || TREE_CODE (decl) == NAMESPACE_DECL) + if (name ? !IDENTIFIER_ANON_P (name) : TREE_CODE (decl) == NAMESPACE_DECL) { cxx_binding *binding = NULL; /* Local scope binding. */ tree ns = NULL_TREE; /* Searched namespace. */ @@ -3064,38 +3101,15 @@ do_pushdecl (tree decl, bool hiding) if (old != decl) /* An existing decl matched, use it. */ decl = old; - else if (TREE_CODE (decl) == TYPE_DECL) - { - tree type = TREE_TYPE (decl); - - if (type != error_mark_node) - { - if (TYPE_NAME (type) != decl) - set_underlying_type (decl); - - set_identifier_type_value_with_scope (name, decl, level); - } - - /* If this is a locally defined typedef in a function that - is not a template instantation, record it to implement - -Wunused-local-typedefs. */ - if (!instantiating_current_function_p ()) - record_locally_defined_typedef (decl); - } else { - if (VAR_P (decl) && !DECL_LOCAL_DECL_P (decl)) - maybe_register_incomplete_var (decl); - - if (VAR_OR_FUNCTION_DECL_P (decl)) - { - if (DECL_LOCAL_DECL_P (decl) - && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) - push_local_extern_decl_alias (decl); + newbinding_bookkeeping (name, decl, level); + - if (DECL_EXTERN_C_P (decl)) - check_extern_c_conflict (decl); - } + if (VAR_OR_FUNCTION_DECL_P (decl) + && DECL_LOCAL_DECL_P (decl) + && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) + push_local_extern_decl_alias (decl); } } else @@ -3105,8 +3119,8 @@ do_pushdecl (tree decl, bool hiding) } /* Record a decl-node X as belonging to the current lexical scope. - It's a friend if IS_FRIEND is true -- which affects exactly where - we push it. */ + The new binding is hidden if HIDING is true (an anticipated builtin + or hidden friend). */ tree pushdecl (tree x, bool hiding) @@ -7279,8 +7293,6 @@ do_push_nested_namespace (tree ns) else { do_push_nested_namespace (CP_DECL_CONTEXT (ns)); - gcc_checking_assert - (find_namespace_value (current_namespace, DECL_NAME (ns)) == ns); resume_scope (NAMESPACE_LEVEL (ns)); current_namespace = ns; } @@ -7302,10 +7314,10 @@ do_pop_nested_namespace (tree ns) do_pop_from_top_level (); } -/* Add TARGET to USINGS, if it does not already exist there. - We used to build the complete graph of usings at this point, from - the POV of the source namespaces. Now we build that as we perform - the unqualified search. */ +/* Add TARGET to USINGS, if it does not already exist there. We used + to build the complete graph of usings at this point, from the POV + of the source namespaces. Now we build that as we perform the + unqualified search. */ static void add_using_namespace (vec *&usings, tree target) @@ -7412,6 +7424,55 @@ push_inline_namespaces (tree ns) return count; } +/* Create a new namespace decl NAME in CTX. */ + +static tree +make_namespace (tree ctx, tree name, location_t loc, bool inline_p) +{ + /* Create the namespace. */ + tree ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node); + DECL_SOURCE_LOCATION (ns) = loc; + SCOPE_DEPTH (ns) = SCOPE_DEPTH (ctx) + 1; + if (!SCOPE_DEPTH (ns)) + /* We only allow depth 255. */ + sorry ("cannot nest more than %d namespaces", SCOPE_DEPTH (ctx)); + DECL_CONTEXT (ns) = FROB_CONTEXT (ctx); + + if (!name) + /* Anon-namespaces in different header-unit imports are distinct. + But that's ok as their contents all have internal linkage. + (This is different to how they'd behave as textual includes, + but doing this at all is really odd source.) */ + SET_DECL_ASSEMBLER_NAME (ns, anon_identifier); + else if (TREE_PUBLIC (ctx)) + TREE_PUBLIC (ns) = true; + + if (inline_p) + DECL_NAMESPACE_INLINE_P (ns) = true; + + return ns; +} + +/* NS was newly created, finish off making it. */ + +static void +make_namespace_finish (tree ns) +{ + tree ctx = CP_DECL_CONTEXT (ns); + cp_binding_level *scope = ggc_cleared_alloc (); + scope->this_entity = ns; + scope->more_cleanups_ok = true; + scope->kind = sk_namespace; + scope->level_chain = NAMESPACE_LEVEL (ctx); + NAMESPACE_LEVEL (ns) = scope; + + if (DECL_NAMESPACE_INLINE_P (ns)) + vec_safe_push (DECL_NAMESPACE_INLINEES (ctx), ns); + + if (DECL_NAMESPACE_INLINE_P (ns) || !DECL_NAME (ns)) + emit_debug_info_using_namespace (ctx, ns, true); +} + /* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we enter an anonymous namespace. If MAKE_INLINE is true, then we create an inline namespace (it is up to the caller to check upon @@ -7488,45 +7549,40 @@ push_namespace (tree name, bool make_inline) } } - bool new_ns = false; if (ns) - /* DR2061. NS might be a member of an inline namespace. We - need to push into those namespaces. */ - count += push_inline_namespaces (CP_DECL_CONTEXT (ns)); + { + /* DR2061. NS might be a member of an inline namespace. We + need to push into those namespaces. */ + count += push_inline_namespaces (CP_DECL_CONTEXT (ns)); + if (DECL_SOURCE_LOCATION (ns) == BUILTINS_LOCATION) + /* It's not builtin now. */ + DECL_SOURCE_LOCATION (ns) = input_location; + } else { - ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node); - SCOPE_DEPTH (ns) = SCOPE_DEPTH (current_namespace) + 1; - if (!SCOPE_DEPTH (ns)) - /* We only allow depth 255. */ - sorry ("cannot nest more than %d namespaces", - SCOPE_DEPTH (current_namespace)); - DECL_CONTEXT (ns) = FROB_CONTEXT (current_namespace); - new_ns = true; + /* Before making a new namespace, see if we already have one in + the existing partitions of the current namespace. */ + tree *slot = find_namespace_slot (current_namespace, name, false); + ns = make_namespace (current_namespace, name, input_location, make_inline); if (pushdecl (ns) == error_mark_node) ns = NULL_TREE; else { - if (!name) + /* Finish up making the namespace. */ + add_decl_to_level (NAMESPACE_LEVEL (current_namespace), ns); + if (!slot) { - SET_DECL_ASSEMBLER_NAME (ns, anon_identifier); - - if (!make_inline) - add_using_namespace (current_binding_level->using_directives, - ns); + slot = find_namespace_slot (current_namespace, name); + /* This should find the slot created by pushdecl. */ + gcc_checking_assert (slot && *slot == ns); } - else if (TREE_PUBLIC (current_namespace)) - TREE_PUBLIC (ns) = 1; + make_namespace_finish (ns); - if (make_inline) - { - DECL_NAMESPACE_INLINE_P (ns) = true; - vec_safe_push (DECL_NAMESPACE_INLINEES (current_namespace), ns); - } - - if (!name || make_inline) - emit_debug_info_using_namespace (current_namespace, ns, true); + /* Add the anon using-directive here, we don't do it in + make_namespace_finish. */ + if (!DECL_NAMESPACE_INLINE_P (ns) && !name) + add_using_namespace (current_binding_level->using_directives, ns); } } @@ -7534,13 +7590,11 @@ push_namespace (tree name, bool make_inline) { if (make_inline && !DECL_NAMESPACE_INLINE_P (ns)) { - error ("inline namespace must be specified at initial definition"); + error_at (input_location, + "inline namespace must be specified at initial definition"); inform (DECL_SOURCE_LOCATION (ns), "%qD defined here", ns); } - if (new_ns) - begin_scope (sk_namespace, ns); - else - resume_scope (NAMESPACE_LEVEL (ns)); + resume_scope (NAMESPACE_LEVEL (ns)); current_namespace = ns; count++; } -- 2.30.2