diff --git i/gcc/cp/cp-tree.h w/gcc/cp/cp-tree.h
index b7f5b6b399f..a25934e3263 100644
--- i/gcc/cp/cp-tree.h
+++ w/gcc/cp/cp-tree.h
@@ -7371,7 +7371,7 @@ inline tree ovl_first				(tree) ATTRIBUTE_PURE;
 extern tree ovl_make				(tree fn,
 						 tree next = NULL_TREE);
 extern tree ovl_insert				(tree fn, tree maybe_ovl,
-						 bool using_p = false);
+						 int using_or_hidden = 0);
 extern tree ovl_skip_hidden			(tree) ATTRIBUTE_PURE;
 extern void lookup_mark				(tree lookup, bool val);
 extern tree lookup_add				(tree fns, tree lookup);
diff --git i/gcc/cp/decl.c w/gcc/cp/decl.c
index c00b996294e..617b96e02e4 100644
--- i/gcc/cp/decl.c
+++ w/gcc/cp/decl.c
@@ -15089,22 +15089,9 @@ xref_tag_1 (enum tag_types tag_code, tree name,
 	  return error_mark_node;
 	}
 
-      if (how != TAG_how::HIDDEN_FRIEND && TYPE_HIDDEN_P (t))
-	{
-	  /* This is no longer an invisible friend.  Make it
-	     visible.  */
-	  tree decl = TYPE_NAME (t);
-
-	  DECL_ANTICIPATED (decl) = false;
-	  DECL_FRIEND_P (decl) = false;
-
-	  if (TYPE_TEMPLATE_INFO (t))
-	    {
-	      tree tmpl = TYPE_TI_TEMPLATE (t);
-	      DECL_ANTICIPATED (tmpl) = false;
-	      DECL_FRIEND_P (tmpl) = false;
-	    }
-	}
+      gcc_checking_assert (how == TAG_how::HIDDEN_FRIEND
+			   || !(DECL_LANG_SPECIFIC (TYPE_NAME (t))
+				&& DECL_ANTICIPATED (TYPE_NAME (t))));
     }
 
   return t;
diff --git i/gcc/cp/name-lookup.c w/gcc/cp/name-lookup.c
index 89f1a4c5d64..bc60d343f7e 100644
--- i/gcc/cp/name-lookup.c
+++ w/gcc/cp/name-lookup.c
@@ -55,6 +55,15 @@ static name_hint suggest_alternatives_for_1 (location_t location, tree name,
 #define MAYBE_STAT_DECL(N) (STAT_HACK_P (N) ? STAT_DECL (N) : N)
 #define MAYBE_STAT_TYPE(N) (STAT_HACK_P (N) ? STAT_TYPE (N) : NULL_TREE)
 
+/* For regular (maybe) overloaded functions, we have OVL_HIDDEN_P.
+   But we also need to indicate hiddenness on implicit type decls
+   (injected friend classes), and (coming soon) decls injected from
+   block-scope externs.  It is too awkward to press the existing
+   overload marking for that.  If we have a hidden non-function, we
+   always create a STAT_HACK, and use these two markers as needed.  */
+#define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N)
+#define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N)
+
 /* Create a STAT_HACK node with DECL as the value binding and TYPE as
    the type binding.  */
 
@@ -545,14 +554,18 @@ name_lookup::search_namespace_only (tree scope)
 	{
 	  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))
+	    {
+	      if (STAT_TYPE_HIDDEN_P (*binding))
+		type = NULL_TREE;
+	      if (STAT_DECL_HIDDEN_P (*binding))
+		value = NULL_TREE;
+	      else
+		value = ovl_skip_hidden (value);
+	    }
 	}
-
-      if (!bool (want & LOOK_want::HIDDEN_FRIEND))
+      else if (!bool (want & LOOK_want::HIDDEN_FRIEND))
 	value = ovl_skip_hidden (value);
 
       found |= process_binding (value, type);
@@ -1975,6 +1988,7 @@ cxx_binding_make (tree value, tree type)
   /* Clear flags by default.  */
   LOCAL_BINDING_P (binding) = false;
   INHERITED_VALUE_BINDING_P (binding) = false;
+  HIDDEN_TYPE_BINDING_P (binding) = false;
 
   cxx_binding_init (binding, value, type);
 
@@ -2046,13 +2060,15 @@ pop_local_binding (tree id, tree decl)
   /* The name should be bound.  */
   gcc_assert (binding != NULL);
 
-  /* The DECL will be either the ordinary binding or the type
-     binding for this identifier.  Remove that binding.  */
+  /* The DECL will be either the ordinary binding or the type binding
+     for this identifier.  Remove that binding.  We don't have to
+     clear HIDDEN_TYPE_BINDING_P, as the whole binding will be going
+     away.  */
   if (binding->value == decl)
     binding->value = NULL_TREE;
   else
     {
-      gcc_assert (binding->type == decl);
+      gcc_checking_assert (binding->type == decl);
       binding->type = NULL_TREE;
     }
 
@@ -2367,11 +2383,22 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
 		tree old, tree decl, bool hiding = false)
 {
   tree old_type = NULL_TREE;
+  bool hide_type = false;
+  bool hide_value = false;
 
   if (!slot)
-    old_type = binding->type;
+    {
+      old_type = binding->type;
+      hide_type = HIDDEN_TYPE_BINDING_P (binding);
+      if (!old_type)
+	hide_value = hide_type, hide_type = false;
+    }
   else if (STAT_HACK_P (*slot))
+    {
       old_type = STAT_TYPE (*slot);
+      hide_type = STAT_TYPE_HIDDEN_P (*slot);
+      hide_value = STAT_DECL_HIDDEN_P (*slot);
+    }
 
   tree to_val = decl;
   tree to_type = old_type;
@@ -2394,9 +2421,12 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
 	{
 	  /* Put DECL into the type slot.  */
 	  gcc_checking_assert (!to_type);
+	  hide_type = hiding;
 	  to_type = decl;
 	  to_val = old;
 	}
+      else
+	hide_value = hiding;
 
       goto done;
     }
@@ -2407,7 +2437,9 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
       gcc_checking_assert (!to_type);
 
       to_type = old;
+      hide_type = hide_value;
       old = NULL_TREE;
+      hide_value = false;
     }
 
   if (DECL_DECLARES_FUNCTION_P (decl))
@@ -2450,7 +2482,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
 		 decl, to_type);
 
       local_overload = old && level->kind != sk_namespace;
-      to_val = ovl_insert (decl, old);
+      to_val = ovl_insert (decl, old, -int (hiding));
     }
   else if (old)
     {
@@ -2483,11 +2515,13 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
 	{
 	  /* 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;
+	    {
+	      gcc_checking_assert (!hide_value && !hiding);
+	      return match;
+	    }
 	  else
 	    goto conflict;
 	}
@@ -2498,6 +2532,8 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
 	  to_val = NULL_TREE;
 	}
     }
+  else if (hiding)
+    hide_value = true;
 
  done:
   if (to_val)
@@ -2516,16 +2552,26 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
 	    {
 	      STAT_TYPE (*slot) = to_type;
 	      STAT_DECL (*slot) = to_val;
+	      STAT_TYPE_HIDDEN_P (*slot) = hide_type;
+	      STAT_DECL_HIDDEN_P (*slot) = hide_value;
+	    }
+	  else if (to_type || hide_value)
+	    {
+	      *slot = stat_hack (to_val, to_type);
+	      STAT_TYPE_HIDDEN_P (*slot) = hide_type;
+	      STAT_DECL_HIDDEN_P (*slot) = hide_value;
 	    }
-	  else if (to_type)
-	    *slot = stat_hack (to_val, to_type);
 	  else
-	    *slot = to_val;
+	    {
+	      gcc_checking_assert (!hide_type);
+	      *slot = to_val;
+	    }
 	}
       else
 	{
 	  binding->type = to_type;
 	  binding->value = to_val;
+	  HIDDEN_TYPE_BINDING_P (binding) = hide_type || hide_value;
 	}
     }
 
@@ -6489,86 +6535,37 @@ lookup_name_1 (tree name, LOOK_where where, LOOK_want want)
     for (cxx_binding *iter = nullptr;
 	 (iter = outer_binding (name, iter, bool (where & LOOK_where::CLASS)));)
       {
-	tree binding;
-
 	/* Skip entities we don't want.  */
 	if (!bool (where & (LOCAL_BINDING_P (iter)
 			    ? LOOK_where::BLOCK : LOOK_where::CLASS)))
 	  continue;
 
 	/* If this is the kind of thing we're looking for, we're done.  */
-	if (iter->value
-	    && (bool (want & LOOK_want::HIDDEN_LAMBDA)
-		|| !is_lambda_ignored_entity (iter->value))
-	    && qualify_lookup (iter->value, want))
-	  binding = iter->value;
-	else if (bool (want & LOOK_want::TYPE)
-		 && qualify_lookup (iter->type, want))
-	  binding = iter->type;
-	else
-	  binding = NULL_TREE;
-
-	if (binding)
+	if (iter->value)
 	  {
-	    if (TREE_CODE (binding) == TYPE_DECL && DECL_HIDDEN_P (binding))
+	    tree binding = NULL_TREE;
+
+	    if (!(!iter->type && HIDDEN_TYPE_BINDING_P (iter))
+		&& (bool (want & LOOK_want::HIDDEN_LAMBDA)
+		    || !is_lambda_ignored_entity (iter->value))
+		&& qualify_lookup (iter->value, want))
+	      binding = iter->value;
+	    else if (bool (want & LOOK_want::TYPE)
+		     && !HIDDEN_TYPE_BINDING_P (iter)
+		     && iter->type)
+	      binding = iter->type;
+
+	    if (binding)
 	      {
-		/* A non namespace-scope binding can only be hidden in the
-		   presence of a local class, due to friend declarations.
-
-		   In particular, consider:
-
-		   struct C;
-		   void f() {
-		     struct A {
-		       friend struct B;
-		       friend struct C;
-		       void g() {
-		         B* b; // error: B is hidden
-			 C* c; // OK, finds ::C
-		       } 
-		     };
-		     B *b;  // error: B is hidden
-		     C *c;  // OK, finds ::C
-		     struct B {};
-		     B *bb; // OK
-		   }
-
-		   The standard says that "B" is a local class in "f"
-		   (but not nested within "A") -- but that name lookup
-		   for "B" does not find this declaration until it is
-		   declared directly with "f".
-
-		   In particular:
-
-		   [class.friend]
-
-		   If a friend declaration appears in a local class and
-		   the name specified is an unqualified name, a prior
-		   declaration is looked up without considering scopes
-		   that are outside the innermost enclosing non-class
-		   scope. For a friend function declaration, if there is
-		   no prior declaration, the program is ill-formed. For a
-		   friend class declaration, if there is no prior
-		   declaration, the class that is specified belongs to the
-		   innermost enclosing non-class scope, but if it is
-		   subsequently referenced, its name is not found by name
-		   lookup until a matching declaration is provided in the
-		   innermost enclosing nonclass scope.
-
-		   So just keep looking for a non-hidden binding.
-		*/
-		gcc_assert (TREE_CODE (binding) == TYPE_DECL);
-		continue;
+		/* The saved lookups for an operator record 'nothing
+		   found' as error_mark_node.  We need to stop the search
+		   here, but not return the error mark node.  */
+		if (binding == error_mark_node)
+		  binding = NULL_TREE;
+
+		val = binding;
+		goto found;
 	      }
-
-	    /* The saved lookups for an operator record 'nothing
-	       found' as error_mark_node.  We need to stop the search
-	       here, but not return the error mark node.  */
-	    if (binding == error_mark_node)
-	      binding = NULL_TREE;
-
-	    val = binding;
-	    goto found;
 	  }
       }
 
@@ -6649,17 +6646,55 @@ lookup_elaborated_type_1 (tree name, TAG_how how)
 	     typedef struct C {} C;
 	   correctly.  */
 
+	tree found = NULL_TREE;
+	bool reveal = false;
 	if (tree type = iter->type)
-	  if (qualify_lookup (type, LOOK_want::TYPE)
-	      && (how != TAG_how::CURRENT_ONLY
-		  || LOCAL_BINDING_P (iter)
-		  || DECL_CONTEXT (type) == iter->scope->this_entity))
-	    return type;
-
-	if (qualify_lookup (iter->value, LOOK_want::TYPE)
-	    && (how != TAG_how::CURRENT_ONLY
-		|| !INHERITED_VALUE_BINDING_P (iter)))
-	  return iter->value;
+	  {
+	    if (qualify_lookup (type, LOOK_want::TYPE)
+		&& (how != TAG_how::CURRENT_ONLY
+		    || LOCAL_BINDING_P (iter)
+		    || DECL_CONTEXT (type) == iter->scope->this_entity))
+	      {
+		found = type;
+		if (how != TAG_how::HIDDEN_FRIEND)
+		  reveal = HIDDEN_TYPE_BINDING_P (iter);
+	      }
+	  }
+	else
+	  {
+	    if (qualify_lookup (iter->value, LOOK_want::TYPE)
+		&& (how != TAG_how::CURRENT_ONLY
+		    || !INHERITED_VALUE_BINDING_P (iter)))
+	      {
+		found = iter->value;
+		if (how != TAG_how::HIDDEN_FRIEND)
+		  reveal = !iter->type && HIDDEN_TYPE_BINDING_P (iter);
+	      }
+	  }
+
+	if (found)
+	  {
+	    if (reveal)
+	      {
+		/* It is no longer a hidden binding.  */
+		HIDDEN_TYPE_BINDING_P (iter) = false;
+
+		/* Unanticipate the decl itself.  */
+		DECL_ANTICIPATED (found) = false;
+		DECL_FRIEND_P (found) = false;
+
+		gcc_checking_assert (TREE_CODE (found) != TEMPLATE_DECL);
+
+		if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found)))
+		  {
+		    tree tmpl = TI_TEMPLATE (ti);
+		    DECL_ANTICIPATED (tmpl) = false;
+		    DECL_FRIEND_P (tmpl) = false;
+		  }
+	      }
+
+	    return found;
+	  }
       }
 
   /* Now check if we can look in namespace scope.  */
@@ -6675,13 +6710,63 @@ lookup_elaborated_type_1 (tree name, TAG_how how)
   if (tree *slot = find_namespace_slot (ns, name))
     {
       /* If this is the kind of thing we're looking for, we're done.  */
+      tree found = NULL_TREE;
+      bool reveal = false;
+
       if (tree type = MAYBE_STAT_TYPE (*slot))
-	if (qualify_lookup (type, LOOK_want::TYPE))
-	  return type;
+	{
+	  found = type;
+	  if (how != TAG_how::HIDDEN_FRIEND)
+	    {
+	      reveal = STAT_TYPE_HIDDEN_P (*slot);
+	      STAT_TYPE_HIDDEN_P (*slot) = false;
+	    }
+	}
+      else if (tree decl = MAYBE_STAT_DECL (*slot))
+	{
+	  if (qualify_lookup (decl, LOOK_want::TYPE))
+	    {
+	      found = decl;
+
+	      if (how != TAG_how::HIDDEN_FRIEND  && STAT_HACK_P (*slot))
+		{
+		  reveal = STAT_DECL_HIDDEN_P (*slot);
+		  if (reveal)
+		    {
+		      if (STAT_TYPE (*slot))
+			STAT_DECL_HIDDEN_P (*slot) = false;
+		      else
+			/* There is no type, just remove the stat
+			   hack.  */
+			*slot = decl;
+		    }
+		}
+	    }
+	}
+
+      if (found)
+	{
+	  if (reveal)
+	    {
+	      /* Reveal the previously hidden thing.  */
+	      DECL_ANTICIPATED (found) = false;
+	      DECL_FRIEND_P (found) = false;
+
+	      if (TREE_CODE (found) == TEMPLATE_DECL)
+		{
+		  DECL_ANTICIPATED (DECL_TEMPLATE_RESULT (found)) = false;
+		  DECL_FRIEND_P (DECL_TEMPLATE_RESULT (found)) = false;
+		}
+	      else if (tree ti = TYPE_TEMPLATE_INFO (TREE_TYPE (found)))
+		{
+		  tree tmpl = TI_TEMPLATE (ti);
+		  DECL_ANTICIPATED (tmpl) = false;
+		  DECL_FRIEND_P (tmpl) = false;
+		}
+	    }
 
-      if (tree decl = MAYBE_STAT_DECL (*slot))
-	if (qualify_lookup (decl, LOOK_want::TYPE))
-	  return decl;
+	  return found;
+	}
     }
 
   return NULL_TREE;
diff --git i/gcc/cp/name-lookup.h w/gcc/cp/name-lookup.h
index 7b463386725..01643fb9b34 100644
--- i/gcc/cp/name-lookup.h
+++ w/gcc/cp/name-lookup.h
@@ -58,6 +58,12 @@ struct cp_binding_level;
    currently being defined.  */
 #define INHERITED_VALUE_BINDING_P(NODE) ((NODE)->value_is_inherited)
 
+/* The IMPLICIT_TYPEDEF is hidden from ordinary name lookup (it was
+   injected via a local class's friend decl). The typdef may be in the
+   VALUE or the TYPE slot.  We do not get the situation where the
+   value and type slots are both filled and both hidden.  */
+#define HIDDEN_TYPE_BINDING_P(NODE) ((NODE)->type_is_hidden)
+
 /* Datatype that represents binding established by a declaration between
    a name and a C++ entity.  */
 struct GTY(()) cxx_binding {
@@ -72,6 +78,7 @@ struct GTY(()) cxx_binding {
 
   bool value_is_inherited : 1;
   bool is_local : 1;
+  bool type_is_hidden : 1;
 };
 
 /* Datatype used to temporarily save C++ bindings (for implicit
diff --git i/gcc/cp/tree.c w/gcc/cp/tree.c
index e8606602bd2..0b80d8ed408 100644
--- i/gcc/cp/tree.c
+++ w/gcc/cp/tree.c
@@ -2237,13 +2237,13 @@ ovl_make (tree fn, tree next)
   return result;
 }
 
-/* Add FN to the (potentially NULL) overload set OVL.  USING_P is
-   true, if FN is via a using declaration.  We also pay attention to
-   DECL_HIDDEN.  We keep the hidden decls first, but remaining ones
-   are unordered.  */
+/* Add FN to the (potentially NULL) overload set OVL.  USING_OR_HIDDEN
+   is > 0, if FN is via a using declaration.  USING_OR_HIDDEN is < 0,
+   if FN is hidden.  (A decl cannot be both using and hidden.)  We
+   keep the hidden decls first, but remaining ones are unordered.  */
 
 tree
-ovl_insert (tree fn, tree maybe_ovl, bool using_p)
+ovl_insert (tree fn, tree maybe_ovl, int using_or_hidden)
 {
   tree result = maybe_ovl;
   tree insert_after = NULL_TREE;
@@ -2257,13 +2257,15 @@ ovl_insert (tree fn, tree maybe_ovl, bool using_p)
       insert_after = maybe_ovl;
     }
 
-  bool hidden_p = DECL_HIDDEN_P (fn);
-  if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL)
+  if (maybe_ovl || using_or_hidden || TREE_CODE (fn) == TEMPLATE_DECL)
     {
       maybe_ovl = ovl_make (fn, maybe_ovl);
-      if (hidden_p)
+
+      gcc_checking_assert ((using_or_hidden < 0) == DECL_HIDDEN_P (fn));
+
+      if (using_or_hidden < 0)
 	OVL_HIDDEN_P (maybe_ovl) = true;
-      if (using_p)
+      if (using_or_hidden > 0)
 	OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true;
     }
   else
@@ -2290,13 +2292,9 @@ ovl_skip_hidden (tree ovl)
        ovl = OVL_CHAIN (ovl))
     gcc_checking_assert (DECL_HIDDEN_P (OVL_FUNCTION (ovl)));
 
-  if (ovl && TREE_CODE (ovl) != OVERLOAD && DECL_HIDDEN_P (ovl))
-    {
-      /* Any hidden functions should have been wrapped in an
-	 overload, but injected friend classes will not.  */
-      gcc_checking_assert (!DECL_DECLARES_FUNCTION_P (ovl));
-      ovl = NULL_TREE;
-    }
+  /* We should not see a naked hidden decl.  */
+  gcc_checking_assert (!(ovl && TREE_CODE (ovl) != OVERLOAD
+			 && DECL_HIDDEN_P (ovl)));
 
   return ovl;
 }
