c++: Adjust pushdecl/duplicate_decls API
authorNathan Sidwell <nathan@acm.org>
Fri, 25 Sep 2020 18:58:26 +0000 (11:58 -0700)
committerNathan Sidwell <nathan@acm.org>
Fri, 25 Sep 2020 19:03:54 +0000 (12:03 -0700)
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
gcc/cp/decl.c
gcc/cp/friend.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/pt.c

index 321bb95..b7f5b6b 100644 (file)
@@ -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);
index b481bbd..c00b996 100644 (file)
@@ -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)
index e484134..6a783a9 100644 (file)
@@ -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);
            }
 
index 0115a4b..184e9c8 100644 (file)
@@ -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;
index 82f4d51..7b46338 100644 (file)
@@ -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);
index a4530db..199fe65 100644 (file)
@@ -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);
        }
     }