extern int decls_match (tree, tree, bool = true);
extern bool maybe_version_functions (tree, tree, bool);
extern tree duplicate_decls (tree, tree,
- bool is_friend = false);
+ bool hiding = false,
+ bool was_hidden = false);
extern tree declare_local_label (tree);
extern tree define_label (location_t, tree);
extern void check_goto (tree);
static void
check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl,
- bool olddecl_hidden_friend_p)
+ bool olddecl_hidden_p)
{
- if (!olddecl_hidden_friend_p && !DECL_FRIEND_P (newdecl))
+ if (!olddecl_hidden_p && !DECL_FRIEND_P (newdecl))
return;
- tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl);
- tree t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl);
-
- for (; t1 && t1 != void_list_node;
+ for (tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl),
+ t2 = FUNCTION_FIRST_USER_PARMTYPE (newdecl);
+ t1 && t1 != void_list_node;
t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
- if ((olddecl_hidden_friend_p && TREE_PURPOSE (t1))
+ if ((olddecl_hidden_p && TREE_PURPOSE (t1))
|| (DECL_FRIEND_P (newdecl) && TREE_PURPOSE (t2)))
{
auto_diagnostic_group d;
If NEWDECL is not a redeclaration of OLDDECL, NULL_TREE is
returned.
- NEWDECL_IS_FRIEND is true if NEWDECL was declared as a friend. */
+ HIDING is true if the new decl is being hidden. WAS_HIDDEN is true
+ if the old decl was hidden.
+
+ Hidden decls can be anticipated builtins, injected friends, or
+ (coming soon) injected from a local-extern decl. */
tree
-duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
+duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
{
unsigned olddecl_uid = DECL_UID (olddecl);
int olddecl_friend = 0, types_match = 0, hidden_friend = 0;
{
/* Avoid warnings redeclaring built-ins which have not been
explicitly declared. */
- if (DECL_ANTICIPATED (olddecl))
+ if (was_hidden)
{
tree t1, t2;
types_match = decls_match (newdecl, olddecl);
if (types_match)
return duplicate_decls (newdecl, olddecl,
- newdecl_is_friend);
+ hiding, was_hidden);
TYPE_ARG_TYPES (TREE_TYPE (olddecl)) = oldargs;
}
goto next_arg;
declaration of the function or function template in the
translation unit." */
check_no_redeclaration_friend_default_args
- (olddecl, newdecl, DECL_HIDDEN_FRIEND_P (olddecl));
+ (olddecl, newdecl, was_hidden);
}
}
}
&& !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE)
/* Don't warn about extern decl followed by definition. */
&& !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))
- /* Don't warn about friends, let add_friend take care of it. */
- && ! (newdecl_is_friend || DECL_FRIEND_P (olddecl))
+ /* Don't warn if at least one is/was hidden. */
+ && !(hiding || was_hidden)
/* Don't warn about declaration followed by specialization. */
&& (! DECL_TEMPLATE_SPECIALIZATION (newdecl)
|| DECL_TEMPLATE_SPECIALIZATION (olddecl)))
if (DECL_DECLARES_FUNCTION_P (olddecl))
{
- olddecl_friend = DECL_FRIEND_P (olddecl);
- olddecl_hidden_friend = DECL_HIDDEN_FRIEND_P (olddecl);
- hidden_friend = (DECL_ANTICIPATED (olddecl)
- && DECL_HIDDEN_FRIEND_P (olddecl)
- && newdecl_is_friend);
+ olddecl_friend = DECL_FRIEND_P (STRIP_TEMPLATE (olddecl));
+ olddecl_hidden_friend = olddecl_friend && was_hidden;
+ hidden_friend = olddecl_hidden_friend && hiding;
if (!hidden_friend)
{
DECL_ANTICIPATED (olddecl) = 0;
tree id = DECL_NAME (decl);
const char *name = IDENTIFIER_POINTER (id);
+ bool hiding = false;
if (name[0] != '_' || name[1] != '_')
- /* In the user's namespace, it must be declared before use. */
- DECL_ANTICIPATED (decl) = 1;
+ {
+ /* In the user's namespace, it must be declared before use. */
+ DECL_ANTICIPATED (decl) = 1;
+ hiding = true;
+ }
else if (IDENTIFIER_LENGTH (id) > strlen ("___chk")
&& 0 != strncmp (name + 2, "builtin_", strlen ("builtin_"))
&& 0 == memcmp (name + IDENTIFIER_LENGTH (id) - strlen ("_chk"),
"_chk", strlen ("_chk") + 1))
- /* Treat __*_chk fortification functions as anticipated as well,
- unless they are __builtin_*_chk. */
- DECL_ANTICIPATED (decl) = 1;
+ {
+ /* Treat __*_chk fortification functions as anticipated as well,
+ unless they are __builtin_*_chk. */
+ DECL_ANTICIPATED (decl) = 1;
+ hiding = true;
+ }
/* All builtins that don't begin with an '_' should additionally
go in the 'std' namespace. */
push_nested_namespace (std_node);
DECL_CONTEXT (std_decl) = FROB_CONTEXT (std_node);
- pushdecl (std_decl);
+ pushdecl (std_decl, hiding);
pop_nested_namespace (std_node);
}
DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
- decl = pushdecl (decl);
+ decl = pushdecl (decl, hiding);
return decl;
}
/* Attempt to merge the declarations. This can fail, in
the case of some invalid specialization declarations. */
pushed_scope = push_scope (ctype);
- ok = duplicate_decls (decl, old_decl, friendp);
+ ok = duplicate_decls (decl, old_decl);
if (pushed_scope)
pop_scope (pushed_scope);
if (!ok)
if (! DECL_USE_TEMPLATE (decl))
{
/* We must check whether the decl refers to template
- arguments before push_template_decl_real adds a
- reference to the containing template class. */
+ arguments before push_template_decl adds a reference to
+ the containing template class. */
int warn = (warn_nontemplate_friend
&& ! funcdef_flag && ! is_friend_template
&& current_template_parms
decl = push_template_decl (decl, /*is_friend=*/true);
else if (current_function_decl)
/* pushdecl will check there's a local decl already. */
- decl = pushdecl (decl, /*is_friend=*/true);
+ decl = pushdecl (decl, /*hiding=*/true);
else
{
/* We can't use pushdecl, as we might be in a template
tree ns = decl_namespace_context (decl);
push_nested_namespace (ns);
- decl = pushdecl_namespace_level (decl, /*is_friend=*/true);
+ decl = pushdecl_namespace_level (decl, /*hiding=*/true);
pop_nested_namespace (ns);
}
&& DECL_EXTERNAL (target_decl) && DECL_EXTERNAL (target_bval)
&& !DECL_CLASS_SCOPE_P (target_decl))
{
- duplicate_decls (decl, binding->value, /*newdecl_is_friend=*/false);
+ duplicate_decls (decl, binding->value);
ok = false;
}
else if (TREE_CODE (decl) == NAMESPACE_DECL
static tree
update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
- tree old, tree decl, bool is_friend)
+ tree old, tree decl, bool hiding = false)
{
tree to_val = decl;
tree old_type = slot ? MAYBE_STAT_TYPE (*slot) : binding->type;
if (iter.using_p () && matching_fn_p (fn, decl))
{
+ gcc_checking_assert (!iter.hidden_p ());
/* If a function declaration in namespace scope or
block scope has the same name and the same
parameter-type- list (8.3.5) as a function
introduced by a using-declaration, and the
declarations do not declare the same function,
the program is ill-formed. [namespace.udecl]/14 */
- if (tree match = duplicate_decls (decl, fn, is_friend))
+ if (tree match = duplicate_decls (decl, fn, hiding))
return match;
else
/* FIXME: To preserve existing error behavior, we
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, false))
+ else if (tree match = duplicate_decls (decl, old))
return match;
else
goto conflict;
says. */
static tree
-do_pushdecl (tree decl, bool is_friend)
+do_pushdecl (tree decl, bool hiding)
{
if (decl == error_mark_node)
return error_mark_node;
- if (!DECL_TEMPLATE_PARM_P (decl) && current_function_decl && !is_friend)
+ if (!DECL_TEMPLATE_PARM_P (decl) && current_function_decl && !hiding)
set_decl_context_in_fn (current_function_decl, decl);
/* The binding level we will be pushing into. During local class
tree *slot = NULL; /* Binding slot in namespace. */
tree old = NULL_TREE;
+ if (!hiding)
+ /* We should never unknownly push an anticipated decl. */
+ gcc_checking_assert (!((TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == TEMPLATE_DECL)
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_ANTICIPATED (decl)));
+
if (level->kind == sk_namespace)
{
/* We look in the decl's namespace for an existing
for (ovl_iterator iter (old); iter; ++iter)
if (iter.using_p ())
; /* Ignore using decls here. */
- else if (tree match = duplicate_decls (decl, *iter, is_friend))
+ else if (tree match
+ = duplicate_decls (decl, *iter, hiding, iter.hidden_p ()))
{
if (match == error_mark_node)
;
/* The IDENTIFIER will have the type referring to the
now-smashed TYPE_DECL, because ...? Reset it. */
SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (match));
- else if (iter.hidden_p () && !DECL_HIDDEN_P (match))
+ else if (iter.hidden_p () && !hiding)
{
/* Unhiding a previously hidden decl. */
tree head = iter.reveal_node (old);
{
check_default_args (decl);
- if (is_friend)
+ if (hiding)
{
if (level->kind != sk_namespace)
{
old = MAYBE_STAT_DECL (*slot);
}
- old = update_binding (level, binding, slot, old, decl, is_friend);
+ old = update_binding (level, binding, slot, old, decl, hiding);
if (old != decl)
/* An existing decl matched, use it. */
we push it. */
tree
-pushdecl (tree x, bool is_friend)
+pushdecl (tree x, bool hiding)
{
bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
- tree ret = do_pushdecl (x, is_friend);
+ tree ret = do_pushdecl (x, hiding);
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
return ret;
}
{
tree *slot = find_namespace_slot (current_namespace, id, true);
gcc_assert (decl);
- update_binding (b, NULL, slot, MAYBE_STAT_DECL (*slot), decl, false);
+ update_binding (b, NULL, slot, MAYBE_STAT_DECL (*slot), decl);
/* Store marker instead of real type. */
type = global_type_node;
closer binding level than LEVEL. */
static tree
-do_pushdecl_with_scope (tree x, cp_binding_level *level, bool is_friend)
+do_pushdecl_with_scope (tree x, cp_binding_level *level, bool hiding = false)
{
cp_binding_level *b;
if (level->kind == sk_class)
{
+ gcc_checking_assert (!hiding);
b = class_binding_level;
class_binding_level = level;
pushdecl_class_level (x);
current_function_decl = NULL_TREE;
b = current_binding_level;
current_binding_level = level;
- x = pushdecl (x, is_friend);
+ x = pushdecl (x, hiding);
current_binding_level = b;
current_function_decl = function_decl;
}
n->kind != sk_function_parms; n = b->level_chain)
b = n;
- tree ret = b ? do_pushdecl_with_scope (x, b, false) : error_mark_node;
+ tree ret = b ? do_pushdecl_with_scope (x, b) : error_mark_node;
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
return ret;
if appropriate. */
tree
-pushdecl_namespace_level (tree x, bool is_friend)
+pushdecl_namespace_level (tree x, bool hiding)
{
cp_binding_level *b = current_binding_level;
tree t;
bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
- t = do_pushdecl_with_scope
- (x, NAMESPACE_LEVEL (current_namespace), is_friend);
+ t = do_pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace), hiding);
/* Now, the type_shadowed stack may screw us. Munge it so it does
what we want. */
/* Pushes X into the global namespace. */
tree
-pushdecl_top_level (tree x, bool is_friend)
+pushdecl_top_level (tree x)
{
bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
do_push_to_top_level ();
- x = pushdecl_namespace_level (x, is_friend);
+ x = pushdecl_namespace_level (x);
do_pop_from_top_level ();
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
return x;
bool = true);
extern bool is_local_extern (tree);
extern bool pushdecl_class_level (tree);
-extern tree pushdecl_namespace_level (tree, bool is_friend = false);
+extern tree pushdecl_namespace_level (tree, bool hiding = false);
extern bool push_class_level_binding (tree, tree);
extern tree get_local_decls ();
extern int function_parm_depth (void);
extern void finish_nonmember_using_decl (tree scope, tree name);
extern void finish_using_directive (tree target, tree attribs);
-extern tree pushdecl (tree, bool is_friend = false);
+extern tree pushdecl (tree, bool hiding = false);
extern tree pushdecl_outermost_localscope (tree);
-extern tree pushdecl_top_level (tree, bool is_friend = false);
+extern tree pushdecl_top_level (tree);
extern tree pushdecl_top_level_and_finish (tree, tree);
extern tree pushtag (tree, tree, TAG_how = TAG_how::CURRENT_ONLY);
extern int push_namespace (tree, bool make_inline = false);
for the specialization, we want this to look as if
there were no definition, and vice versa. */
DECL_INITIAL (fn) = NULL_TREE;
- duplicate_decls (spec, fn, is_friend);
+ duplicate_decls (spec, fn, /*hiding=*/is_friend);
/* The call to duplicate_decls will have applied
[temp.expl.spec]:
}
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
{
- tree dd = duplicate_decls (spec, fn, is_friend);
+ tree dd = duplicate_decls (spec, fn, /*hiding=*/is_friend);
if (dd == error_mark_node)
/* We've already complained in duplicate_decls. */
return error_mark_node;
}
}
else if (fn)
- return duplicate_decls (spec, fn, is_friend);
+ return duplicate_decls (spec, fn, /*hiding=*/is_friend);
/* A specialization must be declared in the same namespace as the
template it is specializing. */
if (!ctx
&& !(is_friend && template_class_depth (current_class_type) > 0))
{
- tmpl = pushdecl_namespace_level (tmpl, is_friend);
+ tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/is_friend);
if (tmpl == error_mark_node)
return error_mark_node;
into the namespace of the template. */
ns = decl_namespace_context (new_friend);
push_nested_namespace (ns);
- old_decl = pushdecl_namespace_level (new_friend, /*is_friend=*/true);
+ old_decl = pushdecl_namespace_level (new_friend, /*hiding=*/true);
pop_nested_namespace (ns);
if (old_decl == error_mark_node)
}
/* Inject this template into the enclosing namspace scope. */
- tmpl = pushdecl_namespace_level (tmpl, true);
+ tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/true);
}
}