cp-tree.h (OVL_HIDDEN_P): New.
authorNathan Sidwell <nathan@acm.org>
Wed, 24 May 2017 11:28:54 +0000 (11:28 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 24 May 2017 11:28:54 +0000 (11:28 +0000)
gcc/cp/
* cp-tree.h (OVL_HIDDEN_P): New.
(ovl_iterator::hidden_p, ovl_iterator::reveal_node): New.
(ovl_iterator::reveal_node): Declare.
* tree.c (ovl_copy): Copy OVL_HIDDEN_P.
(ovl_insert): Order on hiddenness.
(ovl_iterator::reveal_node): New.
* name-lookup.c (anticipated_builtin_p): New.
(supplement_binding_1): Use it.
(set_local_extern_decl_linkage): Use hidden_p.
(do_pushdecl): Deal with unhiding a hidden decl, use
anticipated_builtin_p.
(do_nonmember_using_decl): Use anticipated_decl_p.
(lookup_name_real_1): Use DECL_HIDDEN_P.

gcc/testsuite/
* g++.dg/lookup/extern-c-hidden.C: New.
* g++.dg/lookup/extern-redecl1.C: New.

From-SVN: r248406

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/name-lookup.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/extern-c-hidden.C [new file with mode: 0644]
gcc/testsuite/g++.dg/lookup/extern-redecl1.C [new file with mode: 0644]

index 785dfc56fc073a8c6002cbc45fdd056cd1b84e45..16e30fa43d796bd3565415fea1468a8f23a8f6c9 100644 (file)
@@ -1,3 +1,19 @@
+2017-05-24  Nathan Sidwell  <nathan@acm.org>
+
+       * cp-tree.h (OVL_HIDDEN_P): New.
+       (ovl_iterator::hidden_p, ovl_iterator::reveal_node): New.
+       (ovl_iterator::reveal_node): Declare.
+       * tree.c (ovl_copy): Copy OVL_HIDDEN_P.
+       (ovl_insert): Order on hiddenness.
+       (ovl_iterator::reveal_node): New.
+       * name-lookup.c (anticipated_builtin_p): New.
+       (supplement_binding_1): Use it.
+       (set_local_extern_decl_linkage): Use hidden_p.
+       (do_pushdecl): Deal with unhiding a hidden decl, use
+       anticipated_builtin_p.
+       (do_nonmember_using_decl): Use anticipated_decl_p.
+       (lookup_name_real_1): Use DECL_HIDDEN_P.
+
 2017-05-23  Jason Merrill  <jason@redhat.com>
 
        -Wunused and C++17 structured bindings
index 2ed9e5aa4738174768318a4628949a0c9eccef19..7f1c632da1d0077c706b710340ed1494633de377 100644 (file)
@@ -378,6 +378,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF)
       AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR)
       CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR)
+      OVL_HIDDEN_P (in OVERLOAD)
    3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
       ICS_BAD_FLAG (in _CONV)
       FN_TRY_BLOCK_P (in TRY_BLOCK)
@@ -659,6 +660,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
 
 /* If set, this was imported in a using declaration.   */
 #define OVL_USING_P(NODE)      TREE_LANG_FLAG_1 (OVERLOAD_CHECK (NODE))
+/* If set, this overload is a hidden decl.  */
+#define OVL_HIDDEN_P(NODE)     TREE_LANG_FLAG_2 (OVERLOAD_CHECK (NODE))
 /* If set, this overload contains a nested overload.  */
 #define OVL_NESTED_P(NODE)     TREE_LANG_FLAG_3 (OVERLOAD_CHECK (NODE))
 /* If set, this overload was constructed during lookup.  */
@@ -729,15 +732,26 @@ class ovl_iterator
   {
     return TREE_CODE (ovl) == OVERLOAD && OVL_USING_P (ovl);
   }
+  bool hidden_p () const
+  {
+    return TREE_CODE (ovl) == OVERLOAD && OVL_HIDDEN_P (ovl);
+  }
+
+ public:
   tree remove_node (tree head)
   {
     return remove_node (head, ovl);
   }
+  tree reveal_node (tree head)
+  {
+    return reveal_node (head, ovl);
+  }
 
  private:
-  /* We make this a static function to avoid the address of the
+  /* We make these static functions to avoid the address of the
      iterator escaping the local context.  */
   static tree remove_node (tree head, tree node);
+  static tree reveal_node (tree ovl, tree node);
 };
 
 /* Iterator over a (potentially) 2 dimensional overload, which is
index 89d4e2ad1dbea229294cbbc6ba0a85babff30c43..57d85a5a017f7cca3b8489224c559088c3ddb9ec 100644 (file)
@@ -1077,6 +1077,26 @@ strip_using_decl (tree decl)
   return decl;
 }
 
+/* Return true if OVL is an overload for an anticipated builtin.  */
+
+static bool
+anticipated_builtin_p (tree ovl)
+{
+  if (TREE_CODE (ovl) != OVERLOAD)
+    return false;
+
+  if (!OVL_HIDDEN_P (ovl))
+    return false;
+
+  tree fn = OVL_FUNCTION (ovl);
+  gcc_checking_assert (DECL_ANTICIPATED (fn));
+
+  if (DECL_HIDDEN_FRIEND_P (fn))
+    return false;
+
+  return true;
+}
+
 /* BINDING records an existing declaration for a name in the current scope.
    But, DECL is another declaration for that same identifier in the
    same scope.  This is the `struct stat' hack whereby a non-typedef
@@ -1131,9 +1151,7 @@ supplement_binding_1 (cxx_binding *binding, tree decl)
           || target_bval == error_mark_node
           /* If TARGET_BVAL is anticipated but has not yet been
              declared, pretend it is not there at all.  */
-          || (TREE_CODE (target_bval) == FUNCTION_DECL
-              && DECL_ANTICIPATED (target_bval)
-              && !DECL_HIDDEN_FRIEND_P (target_bval)))
+          || anticipated_builtin_p (target_bval))
     binding->value = decl;
   else if (TREE_CODE (target_bval) == TYPE_DECL
           && DECL_ARTIFICIAL (target_bval)
@@ -1803,7 +1821,7 @@ set_local_extern_decl_linkage (tree decl, bool shadowed)
        loc_value = NULL_TREE;
 
       for (ovl_iterator iter (loc_value); iter; ++iter)
-       if (!DECL_HIDDEN_P (*iter)
+       if (!iter.hidden_p ()
            && (TREE_STATIC (*iter) || DECL_EXTERNAL (*iter))
            && decls_match (*iter, decl))
          {
@@ -1931,15 +1949,34 @@ do_pushdecl (tree decl, bool is_friend)
        if (iter.using_p ())
          ; /* Ignore using decls here.  */
        else if (tree match = duplicate_decls (decl, *iter, is_friend))
-         return match;
+         {
+           if (iter.hidden_p ()
+               && match != error_mark_node
+               && !DECL_HIDDEN_P (match))
+             {
+               /* Unhiding a previously hidden decl.  */
+               tree head = iter.reveal_node (old);
+               if (head != old)
+                 {
+                   if (!ns)
+                     update_local_overload (binding, head);
+                   binding->value = head;
+                 }
+
+               if (TREE_CODE (match) == FUNCTION_DECL
+                   && DECL_EXTERN_C_P (match))
+                 /* We need to check and register the fn now.  */
+                 check_extern_c_conflict (match);
+             }
+           return match;
+         }
 
       /* We are pushing a new decl.  */
 
-      /* Skip a hidden builtin we failed to match already.  */
-      if (old && TREE_CODE (old) == FUNCTION_DECL
-         && DECL_ANTICIPATED (old)
-         && !DECL_HIDDEN_FRIEND_P (old))
-       old = NULL_TREE;
+      /* Skip a hidden builtin we failed to match already.  There can
+        only be one.  */
+      if (old && anticipated_builtin_p (old))
+       old = OVL_CHAIN (old);
 
       check_template_shadow (decl);
 
@@ -3045,8 +3082,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
                    found = true;
                  else if (old.using_p ())
                    continue; /* This is a using decl. */
-                 else if (DECL_ANTICIPATED (old_fn)
-                          && !DECL_HIDDEN_FRIEND_P (old_fn))
+                 else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn))
                    continue; /* This is an anticipated builtin.  */
                  else if (!matching_fn_p (new_fn, old_fn))
                    continue; /* Parameters do not match.  */
@@ -3069,9 +3105,7 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
        }
       else if (value
               /* Ignore anticipated builtins.  */
-              && !(TREE_CODE (value) == FUNCTION_DECL
-                   && DECL_ANTICIPATED (value)
-                   && !DECL_HIDDEN_FRIEND_P (value))
+              && !anticipated_builtin_p (value)
               && !decls_match (lookup.value, value))
        diagnose_name_conflict (lookup.value, value);
       else
@@ -5244,7 +5278,7 @@ lookup_name_real_1 (tree name, int prefer_type, int nonclass, bool block_p,
 
        if (binding)
          {
-           if (hidden_name_p (binding))
+           if (TREE_CODE (binding) == TYPE_DECL && DECL_HIDDEN_P (binding))
              {
                /* A non namespace-scope binding can only be hidden in the
                   presence of a local class, due to friend declarations.
index 8490c817f81c2736d03410ecc2114169dde3ceb9..5ae9601aaef784b2205c423be146dd32bded1e5d 100644 (file)
@@ -2143,7 +2143,8 @@ ovl_copy (tree ovl)
   TREE_TYPE (result) = TREE_TYPE (ovl);
   OVL_FUNCTION (result) = OVL_FUNCTION (ovl);
   OVL_CHAIN (result) = OVL_CHAIN (ovl);
-  OVL_USING_P (ovl) = OVL_USING_P (ovl);
+  OVL_HIDDEN_P (result) = OVL_HIDDEN_P (ovl);
+  OVL_USING_P (result) = OVL_USING_P (ovl);
 
   return result;
 }
@@ -2156,14 +2157,16 @@ tree
 ovl_insert (tree fn, tree maybe_ovl, bool using_p)
 {
   bool copying = false; /* Checking use only.  */
-  int weight = using_p;
+  bool hidden_p = DECL_HIDDEN_P (fn);
+  int weight = (hidden_p << 1) | (using_p << 0);
 
   tree result = NULL_TREE;
   tree insert_after = NULL_TREE;
 
   /* Find insertion point.  */
   while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
-        && (weight < OVL_USING_P (maybe_ovl)))
+        && (weight < ((OVL_HIDDEN_P (maybe_ovl) << 1)
+                      | (OVL_USING_P (maybe_ovl) << 0))))
     {
       gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl)
                           && (!OVL_USED_P (maybe_ovl) || !copying));
@@ -2181,9 +2184,11 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p)
     }
 
   tree trail = fn;
-  if (maybe_ovl || using_p || TREE_CODE (fn) == TEMPLATE_DECL)
+  if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL)
     {
       trail = ovl_make (fn, maybe_ovl);
+      if (hidden_p)
+       OVL_HIDDEN_P (trail) = true;
       if (using_p)
        OVL_USING_P (trail) = true;
     }
@@ -2199,6 +2204,28 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p)
   return result;
 }
 
+/* NODE is an OVL_HIDDEN_P node which is now revealed.  */
+
+tree
+ovl_iterator::reveal_node (tree overload, tree node)
+{
+  /* We cannot have returned NODE as part of a lookup overload, so it
+     cannot be USED.  */
+  gcc_checking_assert (!OVL_USED_P (node));
+
+  OVL_HIDDEN_P (node) = false;
+  if (tree chain = OVL_CHAIN (node))
+    if (TREE_CODE (chain) == OVERLOAD
+       && (OVL_USING_P (chain) || OVL_HIDDEN_P (chain)))
+      {
+       /* The node needs moving, and the simplest way is to remove it
+          and reinsert.  */
+       overload = remove_node (overload, node);
+       overload = ovl_insert (OVL_FUNCTION (node), overload);
+      }
+  return overload;
+}
+
 /* NODE is on the overloads of OVL.  Remove it.  If a predecessor is
    OVL_USED_P we must copy OVL nodes, because those are immutable.
    The removed node is unaltered and may continue to be iterated
index f536dda0fda70884fb2bd13d6727a2e8f55f2f3b..d8d16eebb8bf9f83c81a0732dc74083faf2ea666 100644 (file)
@@ -1,5 +1,8 @@
 2017-05-23  Nathan Sidwell  <nathan@acm.org>
 
+       * g++.dg/lookup/extern-c-hidden.C: New.
+       * g++.dg/lookup/extern-redecl1.C: New.
+
        PR c++/80866
        * g++.dg/parse/pr80866.C: New.
 
diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C b/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C
new file mode 100644 (file)
index 0000000..a03dea0
--- /dev/null
@@ -0,0 +1,11 @@
+// Make sure unhidding an extern-c still checks it is compatible
+
+extern "C" float fabsf (float);  // { dg-error "conflicts with previous declaration" }
+
+namespace Bob 
+{
+  extern "C" float fabsf (float, float); // { dg-error "C language" }
+  extern "C" double fabs (double, double); // { dg-error "conflicts with previous declaration" }
+}
+
+extern "C" double fabs (double); // { dg-error "C language" }
diff --git a/gcc/testsuite/g++.dg/lookup/extern-redecl1.C b/gcc/testsuite/g++.dg/lookup/extern-redecl1.C
new file mode 100644 (file)
index 0000000..18e675b
--- /dev/null
@@ -0,0 +1,18 @@
+extern int X; // { dg-message "previous declaration" }
+extern int Y (int);  // { dg-message "previous declaration" }
+extern int Y (float);
+
+static int Z (int s)
+{
+  return s;
+}
+
+void Foo ()
+{
+  extern char X; // { dg-error "local external declaration" }
+  extern char Y (int); // { dg-error "local external declaration" }
+  extern int Y (float);
+  extern void Y (double);
+  extern char Z (int);
+}
+