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.
This commit is contained in:
Nathan Sidwell 2020-12-10 06:54:37 -08:00
parent 237a8e8d56
commit 36d0108adf

View File

@ -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);
newbinding_bookkeeping (name, decl, level);
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);
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<tree, va_gc> *&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<cp_binding_level> ();
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++;
}