2017-05-25  Nathan Sidwell  <nathan@acm.org>

	gcc/cp/
	Kill DECL_NAMESPACE_USERS, DECL_NAMESPACE_ASSOCIATIONS.
	* cp-tree.h (lang_decl_ns): Remove ns_users field.
	(DECL_NAMESPACE_USERS, DECL_NAMESPACE_ASSOCIATIONS): Delete.
	(TREE_INDIRECT_USING): Delete.
	* name-lookup.h (is_associated_namespace): Delete.
	* name-lookup.c (name_lookup::search_usings,
	name_lookup::do_queue_usings): Usings are always direct.
	(is_associated_namespace): Delete.
	(handle_namespace_attrs): Use DECL_NAMESPACE_INLINE_P.
	(namespace_ancestor_1, namespace_ancestor): Delete.
	(push_using_directive_1, push_using_directive): Delete.
	(add_using_namespace_1): Delete.
	(add_using_namespace): Reimplement.
	(emit_debug_info_using_namespace): New.
	(finish_namespace_using_directive, finish_local_using_directive,
	push_namespace): Adjust.
	* tree.c (cp_free_lang_data): Remove DECL_NAMESPACE_USERS handling.

	libcc1/
	* libcp1plugin.cc (plugin_make_namespace_inline): Check and set
	DECL_NAMESPACE_INLINE_P.

	gcc/testsuite/
	* g++.dg/lookup/using56.C: New.
	* g++.dg/lookup/using57.C: New.
	* g++.dg/lookup/using58.C: New.
	* g++.dg/lookup/using59.C: New.

Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 248457)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -328,7 +328,6 @@ extern GTY(()) tree cp_global_trees[CPTI
       BASELINK_QUALIFIED_P (in BASELINK)
       TARGET_EXPR_IMPLICIT_P (in TARGET_EXPR)
       TEMPLATE_PARM_PARAMETER_PACK (in TEMPLATE_PARM_INDEX)
-      TREE_INDIRECT_USING (in a TREE_LIST of using-directives)
       ATTR_IS_DEPENDENT (in the TREE_LIST for an attribute)
       ABI_TAG_IMPLICIT (in the TREE_LIST for the argument of abi_tag)
       CONSTRUCTOR_IS_DIRECT_INIT (in CONSTRUCTOR)
@@ -2513,7 +2512,6 @@ struct GTY(()) lang_decl_ns {
   struct lang_decl_base base;
   cp_binding_level *level;
   tree ns_using;
-  tree ns_users;
 };
 
 /* DECL_LANG_SPECIFIC for parameters.  */
@@ -3085,15 +3083,6 @@ struct GTY(()) lang_decl {
    that is the common ancestor.  */
 #define DECL_NAMESPACE_USING(NODE) (LANG_DECL_NS_CHECK (NODE)->ns_using)
 
-/* In a NAMESPACE_DECL, the DECL_INITIAL is used to record all users
-   of a namespace, to record the transitive closure of using namespace.  */
-#define DECL_NAMESPACE_USERS(NODE) (LANG_DECL_NS_CHECK (NODE)->ns_users)
-
-/* In a NAMESPACE_DECL, the list of namespaces which have associated
-   themselves with this one.  */
-#define DECL_NAMESPACE_ASSOCIATIONS(NODE) \
-  DECL_INITIAL (NAMESPACE_DECL_CHECK (NODE))
-
 /* In a NAMESPACE_DECL, points to the original namespace if this is
    a namespace alias.  */
 #define DECL_NAMESPACE_ALIAS(NODE) \
@@ -3107,10 +3096,6 @@ struct GTY(()) lang_decl {
    && CP_DECL_CONTEXT (NODE) == global_namespace	\
    && DECL_NAME (NODE) == std_identifier)
 
-/* In a TREE_LIST concatenating using directives, indicate indirect
-   directives  */
-#define TREE_INDIRECT_USING(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
-
 /* In a TREE_LIST in an attribute list, indicates that the attribute
    must be applied at instantiation time.  */
 #define ATTR_IS_DEPENDENT(NODE) TREE_LANG_FLAG_0 (TREE_LIST_CHECK (NODE))
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 248465)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -533,8 +533,7 @@ name_lookup::search_usings (tree scope)
   /* Look in direct usings.  */
   for (tree usings = DECL_NAMESPACE_USING (scope);
        usings; usings = TREE_CHAIN (usings))
-    if (!TREE_INDIRECT_USING (usings))
-      found |= search_qualified (TREE_PURPOSE (usings), true);
+    found |= search_qualified (TREE_PURPOSE (usings), true);
 
   /* Look in its inline children.  */
   for (tree inner = NAMESPACE_LEVEL (scope)->namespaces;
@@ -607,8 +606,7 @@ name_lookup::using_queue *
 name_lookup::do_queue_usings (using_queue *queue, int depth, tree usings)
 {
   for (; usings; usings = TREE_CHAIN (usings))
-    if (!TREE_INDIRECT_USING (usings))
-      queue = queue_namespace (queue, depth, TREE_PURPOSE (usings));
+    queue = queue_namespace (queue, depth, TREE_PURPOSE (usings));
 
   return queue;
 }
@@ -1019,7 +1017,6 @@ static void consider_binding_level (tree
 				    cp_binding_level *lvl,
 				    bool look_within_fields,
 				    enum lookup_name_fuzzy_kind kind);
-static tree push_using_directive (tree);
 static void diagnose_name_conflict (tree, tree);
 
 /* ADL lookup of NAME.  FNS is the result of regular lookup, and we
@@ -1036,47 +1033,6 @@ lookup_arg_dependent (tree name, tree fn
   return fns;
 }
 
-/* Returns true iff CURRENT has declared itself to be an associated
-   namespace of SCOPE via a strong using-directive (or transitive chain
-   thereof).  Both are namespaces.  */
-
-bool
-is_associated_namespace (tree current, tree scope)
-{
-  vec<tree, va_gc> *seen = make_tree_vector ();
-  vec<tree, va_gc> *todo = make_tree_vector ();
-  tree t;
-  bool ret;
-
-  while (1)
-    {
-      if (scope == current)
-	{
-	  ret = true;
-	  break;
-	}
-      vec_safe_push (seen, scope);
-      for (t = DECL_NAMESPACE_ASSOCIATIONS (scope); t; t = TREE_CHAIN (t))
-	if (!vec_member (TREE_PURPOSE (t), seen))
-	  vec_safe_push (todo, TREE_PURPOSE (t));
-      if (!todo->is_empty ())
-	{
-	  scope = todo->last ();
-	  todo->pop ();
-	}
-      else
-	{
-	  ret = false;
-	  break;
-	}
-    }
-
-  release_tree_vector (seen);
-  release_tree_vector (todo);
-
-  return ret;
-}
-
 /* Compute the chain index of a binding_entry given the HASH value of its
    name and the total COUNT of chains.  COUNT is assumed to be a power
    of 2.  */
@@ -4426,15 +4382,15 @@ handle_namespace_attrs (tree ns, tree at
 	}
       else if (is_attribute_p ("abi_tag", name))
 	{
-	  if (!DECL_NAMESPACE_ASSOCIATIONS (ns))
+	  if (!DECL_NAME (ns))
 	    {
-	      warning (OPT_Wattributes, "ignoring %qD attribute on non-inline "
+	      warning (OPT_Wattributes, "ignoring %qD attribute on anonymous "
 		       "namespace", name);
 	      continue;
 	    }
-	  if (!DECL_NAME (ns))
+	  if (!DECL_NAMESPACE_INLINE_P (ns))
 	    {
-	      warning (OPT_Wattributes, "ignoring %qD attribute on anonymous "
+	      warning (OPT_Wattributes, "ignoring %qD attribute on non-inline "
 		       "namespace", name);
 	      continue;
 	    }
@@ -4479,32 +4435,6 @@ pop_decl_namespace (void)
   decl_namespace_list->pop ();
 }
 
-/* Return the namespace that is the common ancestor
-   of two given namespaces.  */
-
-static tree
-namespace_ancestor_1 (tree ns1, tree ns2)
-{
-  tree nsr;
-  if (is_ancestor (ns1, ns2))
-    nsr = ns1;
-  else
-    nsr = namespace_ancestor_1 (CP_DECL_CONTEXT (ns1), ns2);
-  return nsr;
-}
-
-/* Wrapper for namespace_ancestor_1.  */
-
-static tree
-namespace_ancestor (tree ns1, tree ns2)
-{
-  tree nsr;
-  bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
-  nsr = namespace_ancestor_1 (ns1, ns2);
-  timevar_cond_stop (TV_NAME_LOOKUP, subtime);
-  return nsr;
-}
-
 /* Process a namespace-alias declaration.  */
 
 void
@@ -5537,44 +5467,6 @@ is_local_extern (tree decl)
   return false;
 }
 
-/* Add namespace to using_directives. Return NULL_TREE if nothing was
-   changed (i.e. there was already a directive), or the fresh
-   TREE_LIST otherwise.  */
-
-static tree
-push_using_directive_1 (tree used)
-{
-  tree ud = current_binding_level->using_directives;
-  tree iter, ancestor;
-
-  /* Check if we already have this.  */
-  if (purpose_member (used, ud) != NULL_TREE)
-    return NULL_TREE;
-
-  ancestor = namespace_ancestor (current_decl_namespace (), used);
-  ud = current_binding_level->using_directives;
-  ud = tree_cons (used, ancestor, ud);
-  current_binding_level->using_directives = ud;
-
-  /* Recursively add all namespaces used.  */
-  for (iter = DECL_NAMESPACE_USING (used); iter; iter = TREE_CHAIN (iter))
-    push_using_directive_1 (TREE_PURPOSE (iter));
-
-  return ud;
-}
-
-/* Wrapper for push_using_directive_1.  */
-
-static tree
-push_using_directive (tree used)
-{
-  tree ret;
-  bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
-  ret = push_using_directive_1 (used);
-  timevar_cond_stop (TV_NAME_LOOKUP, subtime);
-  return ret;
-}
-
 /* The type TYPE is being declared.  If it is a class template, or a
    specialization of a class template, do any processing required and
    perform error-checking.  If IS_FRIEND is nonzero, this TYPE is
@@ -6094,64 +5986,29 @@ do_pop_nested_namespace (tree ns)
   do_pop_from_top_level ();
 }
 
-/* Insert USED into the using list of USER. Set INDIRECT_flag if this
-   directive is not directly from the source. Also find the common
-   ancestor and let our users know about the new namespace */
+/* Add TARGET to USINGS, if it does not already exist there.
+   We used to build the complete graph of usings at this point, from
+   the POV of the source namespaces.  Now we build that as we perform
+   the unqualified search.  */
 
 static void
-add_using_namespace_1 (tree user, tree used, bool indirect)
+add_using_namespace (tree &usings, tree target)
 {
-  tree t;
-  /* Using oneself is a no-op.  */
-  if (user == used)
-    return;
-  gcc_assert (TREE_CODE (user) == NAMESPACE_DECL);
-  gcc_assert (TREE_CODE (used) == NAMESPACE_DECL);
-  /* Check if we already have this.  */
-  t = purpose_member (used, DECL_NAMESPACE_USING (user));
-  if (t != NULL_TREE)
-    {
-      if (!indirect)
-	/* Promote to direct usage.  */
-	TREE_INDIRECT_USING (t) = 0;
+  for (tree probe = usings; probe; probe = TREE_CHAIN (probe))
+    if (target == TREE_PURPOSE (probe))
       return;
-    }
-
-  /* Add used to the user's using list.  */
-  DECL_NAMESPACE_USING (user)
-    = tree_cons (used, namespace_ancestor (user, used),
-		 DECL_NAMESPACE_USING (user));
-
-  TREE_INDIRECT_USING (DECL_NAMESPACE_USING (user)) = indirect;
 
-  /* Add user to the used's users list.  */
-  DECL_NAMESPACE_USERS (used)
-    = tree_cons (user, 0, DECL_NAMESPACE_USERS (used));
-
-  /* Recursively add all namespaces used.  */
-  for (t = DECL_NAMESPACE_USING (used); t; t = TREE_CHAIN (t))
-    /* indirect usage */
-    add_using_namespace_1 (user, TREE_PURPOSE (t), 1);
-
-  /* Tell everyone using us about the new used namespaces.  */
-  for (t = DECL_NAMESPACE_USERS (user); t; t = TREE_CHAIN (t))
-    add_using_namespace_1 (TREE_PURPOSE (t), used, 1);
+  usings = tree_cons (target, NULL_TREE, usings);
 }
 
-/* Wrapper for add_using_namespace_1.  */
+/* Tell the debug system of a using directive.  */
 
 static void
-add_using_namespace (bool namespace_level_p, tree from, tree target)
+emit_debug_info_using_namespace (tree from, tree target)
 {
-  bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
-  add_using_namespace_1 (from, target, false);
-  if (namespace_level_p)
-    {
-      /* Emit debugging info.  */
-      tree context = from != global_namespace ? from : NULL_TREE;
-      debug_hooks->imported_module_or_decl (target, NULL_TREE, context, false);
-    }
-  timevar_cond_stop (TV_NAME_LOOKUP, subtime);
+  /* Emit debugging info.  */
+  tree context = from != global_namespace ? from : NULL_TREE;
+  debug_hooks->imported_module_or_decl (target, NULL_TREE, context, false);
 }
 
 /* Process a namespace-scope using directive.  */
@@ -6163,8 +6020,10 @@ finish_namespace_using_directive (tree t
   if (target == error_mark_node)
     return;
 
-  add_using_namespace (true, current_namespace,
+  add_using_namespace (DECL_NAMESPACE_USING (current_namespace),
 		       ORIGINAL_NAMESPACE (target));
+  emit_debug_info_using_namespace (current_namespace,
+				   ORIGINAL_NAMESPACE (target));
 
   if (attribs == error_mark_node)
     return;
@@ -6198,7 +6057,8 @@ finish_local_using_directive (tree targe
 
   add_stmt (build_stmt (input_location, USING_STMT, target));
 
-  push_using_directive (ORIGINAL_NAMESPACE (target));
+  add_using_namespace (current_binding_level->using_directives,
+		       ORIGINAL_NAMESPACE (target));
 }
 
 /* Pushes X into the global namespace.  */
@@ -6306,20 +6166,14 @@ push_namespace (tree name, bool make_inl
 	      DECL_NAME (ns) = NULL_TREE;
 
 	      if (!make_inline)
-		add_using_namespace (true, current_namespace, ns);
+		add_using_namespace (DECL_NAMESPACE_USING (current_namespace),
+				     ns);
 	    }
 	  else if (TREE_PUBLIC (current_namespace))
 	    TREE_PUBLIC (ns) = 1;
 
 	  if (make_inline)
-	    {
-	      DECL_NAMESPACE_INLINE_P (ns) = true;
-	      /* Set up namespace association.  */
-	      DECL_NAMESPACE_ASSOCIATIONS (ns)
-		= tree_cons (current_namespace, NULL_TREE, NULL_TREE);
-	      /* Import the contents of the inline namespace.  */
-	      add_using_namespace (true, current_namespace, ns);
-	    }
+	    DECL_NAMESPACE_INLINE_P (ns) = true;
 	}
     }
 
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h	(revision 248457)
+++ gcc/cp/name-lookup.h	(working copy)
@@ -325,7 +325,6 @@ extern void do_namespace_alias (tree, tr
 extern tree do_class_using_decl (tree, tree);
 extern void do_using_directive (tree);
 extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
-extern bool is_associated_namespace (tree, tree);
 extern tree innermost_non_namespace_value (tree);
 extern cxx_binding *outer_binding (tree, cxx_binding *, bool);
 extern void cp_emit_debug_info_for_using (tree, tree);
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	(revision 248452)
+++ gcc/cp/tree.c	(working copy)
@@ -5123,14 +5123,9 @@ cp_free_lang_data (tree t)
       TREE_STATIC (t) = 0;
     }
   if (TREE_CODE (t) == NAMESPACE_DECL)
-    {
-      /* The list of users of a namespace isn't useful for the middle-end
-	 or debug generators.  */
-      DECL_NAMESPACE_USERS (t) = NULL_TREE;
-      /* Neither do we need the leftover chaining of namespaces
-         from the binding level.  */
-      DECL_CHAIN (t) = NULL_TREE;
-    }
+    /* We do not need the leftover chaining of namespaces from the
+       binding level.  */
+    DECL_CHAIN (t) = NULL_TREE;
 }
 
 /* Stub for c-common.  Please keep in sync with c-decl.c.
Index: libcc1/libcp1plugin.cc
===================================================================
--- libcc1/libcp1plugin.cc	(revision 248452)
+++ libcc1/libcp1plugin.cc	(working copy)
@@ -930,20 +930,10 @@ plugin_make_namespace_inline (cc1_plugin
 
   tree parent_ns = CP_DECL_CONTEXT (inline_ns);
 
-  if (purpose_member (DECL_NAMESPACE_ASSOCIATIONS (inline_ns),
-		      parent_ns))
+  if (DECL_NAMESPACE_INLINE_P (inline_ns))
     return 0;
 
-  pop_namespace ();
-
-  gcc_assert (current_namespace == parent_ns);
-
-  DECL_NAMESPACE_ASSOCIATIONS (inline_ns)
-    = tree_cons (parent_ns, 0,
-		 DECL_NAMESPACE_ASSOCIATIONS (inline_ns));
-  do_using_directive (inline_ns);
-
-  push_namespace (DECL_NAME (inline_ns));
+  DECL_NAMESPACE_INLINE_P (inline_ns) = true;
 
   return 1;
 }
Index: gcc/testsuite/g++.dg/lookup/using56.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using56.C	(revision 0)
+++ gcc/testsuite/g++.dg/lookup/using56.C	(working copy)
@@ -0,0 +1,16 @@
+
+// The anticipated decl for 'log' got retained, leading to confusion  */
+
+extern double log (double) throw ();
+
+namespace std
+{
+  using ::log;
+  float log (float) throw ();
+  long double log (long double) throw ();
+}
+
+void Foo (double x)
+{
+  std::log (x);
+}
Index: gcc/testsuite/g++.dg/lookup/using57.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using57.C	(revision 0)
+++ gcc/testsuite/g++.dg/lookup/using57.C	(working copy)
@@ -0,0 +1,29 @@
+// Addr of function from multiple namespaces
+
+namespace X
+{
+  void Foo (int);
+  void Foo (short);
+}
+
+namespace Y
+{
+  void Foo (float);
+  void Foo (double);
+}
+
+template <typename T> void Foo (T *);
+
+using namespace X;
+
+using namespace Y;
+
+void (*(Baz ())) (float)
+{
+  return Foo;
+}
+
+void (*(Bar ())) (void *)
+{
+  return Foo;
+}
Index: gcc/testsuite/g++.dg/lookup/using58.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using58.C	(revision 0)
+++ gcc/testsuite/g++.dg/lookup/using58.C	(working copy)
@@ -0,0 +1,18 @@
+
+
+void Foo (int);
+void Foo (double);
+
+namespace Y
+{
+  void Baz (int); // { dg-message "previous declaration" }
+}
+
+void X ()
+{
+  using ::Foo;
+  extern void Foo (int);
+
+  using Y::Baz;
+  extern void Baz (int);  // { dg-error "conflicts with" }
+}
Index: gcc/testsuite/g++.dg/lookup/using59.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using59.C	(revision 0)
+++ gcc/testsuite/g++.dg/lookup/using59.C	(working copy)
@@ -0,0 +1,12 @@
+
+namespace Y
+{
+  extern int I; //  { dg-message "previous declaration" }
+}
+
+using Y::I;
+extern int I; // { dg-error "conflicts with a previous" }
+
+extern int J;
+extern int J; //  { dg-message "previous declaration" }
+extern char J; // { dg-error "conflicting declaration" }
