From c74e6f7cfd7a741fc0477fe3660eec57581b22c5 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 25 Sep 2020 11:58:26 -0700 Subject: [PATCH] c++: Adjust pushdecl/duplicate_decls API The decl pushing APIs and duplicate_decls take an 'is_friend' parm, when what they actually mean is 'hide this from name lookup'. That conflation has gotten more anachronistic as time moved on. We now have anticipated builtins, and I plan to have injected extern decls soon. So this patch is mainly a renaming excercise. is_friend -> hiding. duplicate_decls gets an additional 'was_hidden' parm. As I've already said, hiddenness is a property of the symbol table, not the decl. Builtins are now pushed requesting hiding, and pushdecl asserts that we don't attempt to push a thing that should be hidden without asking for it to be hidden. This is the final piece of groundwork to get rid of a bunch of 'this is hidden' markers on decls and move the hiding management entirely into name lookup. gcc/cp/ * cp-tree.h (duplicate_decls): Replace 'is_friend' with 'hiding' and add 'was_hidden'. * name-lookup.h (pushdecl_namespace_level): Replace 'is_friend' with 'hiding'. (pushdecl): Likewise. (pushdecl_top_level): Drop is_friend parm. * decl.c (check_no_redeclaration_friend_default_args): Rename parm olddelc_hidden_p. (duplicate_decls): Replace 'is_friend' with 'hiding' and 'was_hidden'. Do minimal adjustments in body. (cxx_builtin_function): Pass 'hiding' to pushdecl. * friend.c (do_friend): Pass 'hiding' to pushdecl. * name-lookup.c (supplement_binding_1): Drop defaulted arg to duplicate_decls. (update_binding): Replace 'is_friend' with 'hiding'. Drop defaulted arg to duplicate_decls. (do_pushdecl): Replace 'is_friend' with 'hiding'. Assert no surprise hidhing. Adjust duplicate_decls calls to inform of old decl's hiddennes. (pushdecl): Replace 'is_friend' with 'hiding'. (set_identifier_type_value_with_scope): Adjust update_binding call. (do_pushdecl_with_scope): Replace 'is_friend' with 'hiding'. (pushdecl_outermost_localscope): Drop default arg to do_pushdecl_with_scope. (pushdecl_namespace_level): Replace 'is_friend' with 'hiding'. (pushdecl_top_level): Drop is_friend parm. * pt.c (register_specialization): Comment duplicate_decls call args. (push_template_decl): Commont pushdecl_namespace_level. (tsubst_friend_function, tsubst_friend_class): Likewise. --- gcc/cp/cp-tree.h | 3 ++- gcc/cp/decl.c | 62 +++++++++++++++++++++++++++++----------------------- gcc/cp/friend.c | 8 +++---- gcc/cp/name-lookup.c | 52 +++++++++++++++++++++++++------------------ gcc/cp/name-lookup.h | 6 ++--- gcc/cp/pt.c | 12 +++++----- 6 files changed, 81 insertions(+), 62 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 321bb95..b7f5b6b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6466,7 +6466,8 @@ extern void determine_local_discriminator (tree); 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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b481bbd..c00b996 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1341,17 +1341,16 @@ check_redeclaration_no_default_args (tree decl) 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; @@ -1435,10 +1434,14 @@ duplicate_function_template_decls (tree newdecl, tree olddecl) 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; @@ -1510,7 +1513,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) { /* Avoid warnings redeclaring built-ins which have not been explicitly declared. */ - if (DECL_ANTICIPATED (olddecl)) + if (was_hidden) { tree t1, t2; @@ -1550,7 +1553,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) 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; @@ -1985,7 +1988,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) 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); } } } @@ -2075,8 +2078,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && !(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))) @@ -2134,11 +2137,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) 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; @@ -4714,16 +4715,23 @@ cxx_builtin_function (tree decl) 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. */ @@ -4733,12 +4741,12 @@ cxx_builtin_function (tree decl) 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; } @@ -9925,7 +9933,7 @@ grokfndecl (tree ctype, /* 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) diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index e484134..6a783a9 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -598,8 +598,8 @@ do_friend (tree ctype, tree declarator, tree decl, 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 @@ -614,7 +614,7 @@ do_friend (tree ctype, tree declarator, tree decl, 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 @@ -624,7 +624,7 @@ do_friend (tree ctype, tree declarator, tree decl, 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); } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 0115a4b..184e9c8 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2232,7 +2232,7 @@ supplement_binding_1 (cxx_binding *binding, tree decl) && 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 @@ -2354,7 +2354,7 @@ matching_fn_p (tree one, tree two) 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; @@ -2410,13 +2410,14 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, 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 @@ -2468,7 +2469,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, 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; @@ -2989,12 +2990,12 @@ set_local_extern_decl_linkage (tree decl, bool shadowed) 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 @@ -3014,6 +3015,14 @@ do_pushdecl (tree decl, bool is_friend) 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 @@ -3044,7 +3053,8 @@ do_pushdecl (tree decl, bool is_friend) 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) ; @@ -3052,7 +3062,7 @@ do_pushdecl (tree decl, bool is_friend) /* 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); @@ -3088,7 +3098,7 @@ do_pushdecl (tree decl, bool is_friend) { check_default_args (decl); - if (is_friend) + if (hiding) { if (level->kind != sk_namespace) { @@ -3126,7 +3136,7 @@ do_pushdecl (tree decl, bool is_friend) 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. */ @@ -3170,10 +3180,10 @@ do_pushdecl (tree decl, bool is_friend) 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; } @@ -3780,7 +3790,7 @@ set_identifier_type_value_with_scope (tree id, tree decl, cp_binding_level *b) { 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; @@ -3836,12 +3846,13 @@ constructor_name_p (tree name, tree type) 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); @@ -3854,7 +3865,7 @@ do_pushdecl_with_scope (tree x, cp_binding_level *level, bool is_friend) 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; } @@ -3874,7 +3885,7 @@ pushdecl_outermost_localscope (tree x) 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; @@ -5072,14 +5083,13 @@ do_namespace_alias (tree alias, tree name_space) 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. */ @@ -7282,11 +7292,11 @@ finish_using_directive (tree target, tree attribs) /* 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; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 82f4d51..7b46338 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -337,7 +337,7 @@ extern tree lookup_qualified_name (tree scope, const char *name, 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); @@ -363,9 +363,9 @@ extern void cp_emit_debug_info_for_using (tree, tree); 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); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a4530db..199fe65 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1635,7 +1635,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, 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]: @@ -1662,7 +1662,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, } 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; @@ -1677,7 +1677,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, } } 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. */ @@ -6018,7 +6018,7 @@ push_template_decl (tree decl, bool is_friend) 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; @@ -11078,7 +11078,7 @@ tsubst_friend_function (tree decl, tree args) 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) @@ -11323,7 +11323,7 @@ tsubst_friend_class (tree friend_tmpl, tree args) } /* Inject this template into the enclosing namspace scope. */ - tmpl = pushdecl_namespace_level (tmpl, true); + tmpl = pushdecl_namespace_level (tmpl, /*hiding=*/true); } } -- 2.7.4