c++: Name lookup simplifications

Here are a few cleanups, prior to landing the hidden decl changes.

1) Clear cxx_binding flags in the allocator, not at each user of the allocator.

2) Refactor update_binding.  The logic was getting too convoluted.

3) Set friendliness and anticipatedness before pushing a template decl (not after).

	gcc/cp/
	* name-lookup.c (create_local_binding): Do not clear
	INHERITED_VALUE_BINDING_P here.
	(name_lookup::process_binding): Move done hidden-decl triage to ...
	(name_lookup::search_namespace_only): ... here, its only caller.
	(cxx_binding_make): Clear flags here.
	(push_binding): Not here.
	(pop_local_binding): RAII.
	(update_binding): Refactor.
	(do_pushdecl): Assert we're never revealing a local binding.
	(do_pushdecl_with_scope): Directly call do_pushdecl.
	(get_class_binding): Do not clear LOCAL_BINDING_P here.
	* pt.c (push_template_decl): Set friend & anticipated before
	pushing.
This commit is contained in:
Nathan Sidwell 2020-09-29 09:38:34 -07:00
parent 74b5b8dec4
commit adcf8a11c7
2 changed files with 97 additions and 76 deletions

View File

@ -77,7 +77,6 @@ create_local_binding (cp_binding_level *level, tree name)
{
cxx_binding *binding = cxx_binding_make (NULL, NULL);
INHERITED_VALUE_BINDING_P (binding) = false;
LOCAL_BINDING_P (binding) = true;
binding->scope = level;
binding->previous = IDENTIFIER_BINDING (name);
@ -480,22 +479,17 @@ name_lookup::add_type (tree new_type)
}
/* Process a found binding containing NEW_VAL and NEW_TYPE. Returns
true if we actually found something noteworthy. */
true if we actually found something noteworthy. Hiddenness has
already been handled in the caller. */
bool
name_lookup::process_binding (tree new_val, tree new_type)
{
/* Did we really see a type? */
if (new_type
&& ((want & LOOK_want::TYPE_NAMESPACE) == LOOK_want::NAMESPACE
|| (!bool (want & LOOK_want::HIDDEN_FRIEND)
&& DECL_LANG_SPECIFIC (new_type)
&& DECL_ANTICIPATED (new_type))))
&& (want & LOOK_want::TYPE_NAMESPACE) == LOOK_want::NAMESPACE)
new_type = NULL_TREE;
if (new_val && !bool (want & LOOK_want::HIDDEN_FRIEND))
new_val = ovl_skip_hidden (new_val);
/* Do we really see a value? */
if (new_val)
switch (TREE_CODE (new_val))
@ -544,8 +538,25 @@ name_lookup::search_namespace_only (tree scope)
bool found = false;
if (tree *binding = find_namespace_slot (scope, name))
found |= process_binding (MAYBE_STAT_DECL (*binding),
MAYBE_STAT_TYPE (*binding));
{
tree value = *binding, type = NULL_TREE;
if (STAT_HACK_P (value))
{
type = STAT_TYPE (value);
value = STAT_DECL (value);
if (!bool (want & LOOK_want::HIDDEN_FRIEND)
&& DECL_LANG_SPECIFIC (type)
&& DECL_ANTICIPATED (type))
type = NULL_TREE;
}
if (!bool (want & LOOK_want::HIDDEN_FRIEND))
value = ovl_skip_hidden (value);
found |= process_binding (value, type);
}
return found;
}
@ -1954,15 +1965,17 @@ cxx_binding_init (cxx_binding *binding, tree value, tree type)
static cxx_binding *
cxx_binding_make (tree value, tree type)
{
cxx_binding *binding;
if (free_bindings)
{
binding = free_bindings;
free_bindings = binding->previous;
}
cxx_binding *binding = free_bindings;
if (binding)
free_bindings = binding->previous;
else
binding = ggc_alloc<cxx_binding> ();
/* Clear flags by default. */
LOCAL_BINDING_P (binding) = false;
INHERITED_VALUE_BINDING_P (binding) = false;
cxx_binding_init (binding, value, type);
return binding;
@ -2009,7 +2022,6 @@ push_binding (tree id, tree decl, cp_binding_level* level)
/* Now, fill in the binding information. */
binding->previous = IDENTIFIER_BINDING (id);
INHERITED_VALUE_BINDING_P (binding) = 0;
LOCAL_BINDING_P (binding) = (level != class_binding_level);
/* And put it on the front of the list of bindings for ID. */
@ -2022,8 +2034,6 @@ push_binding (tree id, tree decl, cp_binding_level* level)
void
pop_local_binding (tree id, tree decl)
{
cxx_binding *binding;
if (id == NULL_TREE)
/* It's easiest to write the loops that call this function without
checking whether or not the entities involved have names. We
@ -2031,7 +2041,7 @@ pop_local_binding (tree id, tree decl)
return;
/* Get the innermost binding for ID. */
binding = IDENTIFIER_BINDING (id);
cxx_binding *binding = IDENTIFIER_BINDING (id);
/* The name should be bound. */
gcc_assert (binding != NULL);
@ -2356,9 +2366,16 @@ static tree
update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
tree old, tree decl, bool hiding = false)
{
tree old_type = NULL_TREE;
if (!slot)
old_type = binding->type;
else if (STAT_HACK_P (*slot))
old_type = STAT_TYPE (*slot);
tree to_val = decl;
tree old_type = slot ? MAYBE_STAT_TYPE (*slot) : binding->type;
tree to_type = old_type;
bool local_overload = false;
gcc_assert (level->kind == sk_namespace ? !binding
: level->kind != sk_class && !slot);
@ -2375,16 +2392,20 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
if (old)
{
/* Slide decl into the type slot, keep old unaltered */
/* Put DECL into the type slot. */
gcc_checking_assert (!to_type);
to_type = decl;
to_val = old;
}
goto done;
}
if (old && DECL_IMPLICIT_TYPEDEF_P (old))
{
/* Slide old into the type slot. */
/* OLD is an implicit typedef. Move it to to_type. */
gcc_checking_assert (!to_type);
to_type = old;
old = NULL_TREE;
}
@ -2428,60 +2449,66 @@ 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;
to_val = ovl_insert (decl, old);
}
else if (!old)
;
else if (TREE_CODE (old) != TREE_CODE (decl))
/* Different kinds of decls conflict. */
goto conflict;
else if (TREE_CODE (old) == TYPE_DECL)
else if (old)
{
if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl)))
/* Two type decls to the same type. Do nothing. */
return old;
else
goto conflict;
}
else if (TREE_CODE (old) == NAMESPACE_DECL)
{
/* Two maybe-aliased namespaces. If they're to the same target
namespace, that's ok. */
if (ORIGINAL_NAMESPACE (old) != ORIGINAL_NAMESPACE (decl))
if (TREE_CODE (old) != TREE_CODE (decl))
/* Different kinds of decls conflict. */
goto conflict;
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;
}
else
goto conflict;
}
else if (TREE_CODE (old) == NAMESPACE_DECL)
{
/* Two maybe-aliased namespaces. If they're to the same target
namespace, that's ok. */
if (ORIGINAL_NAMESPACE (old) != ORIGINAL_NAMESPACE (decl))
goto conflict;
/* The new one must be an alias at this point. */
gcc_assert (DECL_NAMESPACE_ALIAS (decl));
return old;
}
else if (TREE_CODE (old) == VAR_DECL)
{
/* There can be two block-scope declarations of the same
variable, so long as they are `extern' declarations. */
if (!DECL_EXTERNAL (old) || !DECL_EXTERNAL (decl))
goto conflict;
else if (tree match = duplicate_decls (decl, old))
return match;
/* The new one must be an alias at this point. */
gcc_assert (DECL_NAMESPACE_ALIAS (decl) && !hiding);
return old;
}
else if (TREE_CODE (old) == VAR_DECL)
{
/* There can be two block-scope declarations of the same
variable, so long as they are `extern' declarations. */
// FIXME: This is DECL_LOCAL_DECL_P type stuff.
if (!DECL_EXTERNAL (old) || !DECL_EXTERNAL (decl))
goto conflict;
else if (tree match = duplicate_decls (decl, old))
return match;
else
goto conflict;
}
else
goto conflict;
}
else
{
conflict:
diagnose_name_conflict (decl, old);
to_val = NULL_TREE;
{
conflict:
diagnose_name_conflict (decl, old);
to_val = NULL_TREE;
}
}
done:
if (to_val)
{
if (level->kind == sk_namespace || to_type == decl || to_val == decl)
add_decl_to_level (level, decl);
else
if (local_overload)
{
gcc_checking_assert (binding->value && OVL_P (binding->value));
update_local_overload (binding, to_val);
}
else
add_decl_to_level (level, decl);
if (slot)
{
@ -3059,12 +3086,8 @@ do_pushdecl (tree decl, bool hiding)
tree head = iter.reveal_node (old);
if (head != old)
{
if (!ns)
{
update_local_overload (binding, head);
binding->value = head;
}
else if (STAT_HACK_P (*slot))
gcc_checking_assert (ns);
if (STAT_HACK_P (*slot))
STAT_DECL (*slot) = head;
else
*slot = head;
@ -3859,7 +3882,7 @@ do_pushdecl_with_scope (tree x, cp_binding_level *level, bool hiding = false)
current_function_decl = NULL_TREE;
b = current_binding_level;
current_binding_level = level;
x = pushdecl (x, hiding);
x = do_pushdecl (x, hiding);
current_binding_level = b;
current_function_decl = function_decl;
}
@ -4398,8 +4421,6 @@ get_class_binding (tree name, cp_binding_level *scope)
value_binding,
type_binding,
scope);
/* This is a class-scope binding, not a block-scope binding. */
LOCAL_BINDING_P (binding) = 0;
set_inherited_value_binding_p (binding, value_binding, class_type);
}
else

View File

@ -6018,16 +6018,16 @@ push_template_decl (tree decl, bool is_friend)
if (!ctx
&& !(is_friend && template_class_depth (current_class_type) > 0))
{
tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/is_friend);
if (tmpl == error_mark_node)
return error_mark_node;
/* Hide template friend classes that haven't been declared yet. */
if (is_friend && TREE_CODE (decl) == TYPE_DECL)
{
DECL_ANTICIPATED (tmpl) = 1;
DECL_FRIEND_P (tmpl) = 1;
}
tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/is_friend);
if (tmpl == error_mark_node)
return error_mark_node;
}
}
else