2019-11-12  Nathan Sidwell  <nathan@acm.org>

	gcc/cp/
	* name-lookup.c (lookup_using_decl): New function, merged from ...
	(do_class_using_decl): ... here.  Call it.  And ...
	(finish_nonmember_using_decl): ... here.  Call it.

	gcc/testsuite/
	* g++.dg/cpp0x/using-enum-2.C: Adjust expected error text.
	* g++.dg/cpp0x/using-enum-3.C: Likewise.
	* g++.dg/lookup/using4.C: Likewise.
	* g++.dg/lookup/using7.C: Likewise.
	* g++.dg/template/using12.C: Likewise.
	* g++.dg/template/using18.C: Likewise.
	* g++.dg/template/using22.C: Likewise.

Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 278096)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -4585,100 +4585,164 @@ push_class_level_binding (tree name, tre
 }
 
-/* Process "using SCOPE::NAME" in a class scope.  Return the
-   USING_DECL created.  */
+/* Process and lookup a using decl SCOPE::lookup.name, filling in
+   lookup.values & lookup.type.  Return true if ok.  */
 
-tree
-do_class_using_decl (tree scope, tree name)
+static bool
+lookup_using_decl (tree scope, name_lookup &lookup)
 {
-  if (name == error_mark_node)
-    return NULL_TREE;
+  tree current = current_scope ();
+  bool dependent_p = false;
 
-  if (!scope || !TYPE_P (scope))
+  if (TREE_CODE (scope) == NAMESPACE_DECL)
     {
-      error ("using-declaration for non-member at class scope");
-      return NULL_TREE;
-    }
+      /* Naming a namespace member.  */
+      if (TYPE_P (current))
+	{
+	  error ("using-declaration for non-member at class scope");
+	  return false;
+	}
 
-  /* Make sure the name is not invalid */
-  if (TREE_CODE (name) == BIT_NOT_EXPR)
-    {
-      error ("%<%T::%D%> names destructor", scope, name);
-      return NULL_TREE;
+      qualified_namespace_lookup (scope, &lookup);
     }
-
-  /* Using T::T declares inheriting ctors, even if T is a typedef.  */
-  if (MAYBE_CLASS_TYPE_P (scope)
-      && (name == TYPE_IDENTIFIER (scope)
-	  || constructor_name_p (name, scope)))
+  else if (TREE_CODE (scope) == ENUMERAL_TYPE)
     {
-      maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
-      name = ctor_identifier;
-      CLASSTYPE_NON_AGGREGATE (current_class_type) = true;
-      TYPE_HAS_USER_CONSTRUCTOR (current_class_type) = true;
+      error ("using-declaration may not name enumerator %<%E::%D%>",
+	     scope, lookup.name);
+      return false;
     }
-
-  /* Cannot introduce a constructor name.  */
-  if (constructor_name_p (name, current_class_type))
+  else
     {
-      error ("%<%T::%D%> names constructor in %qT",
-	     scope, name, current_class_type);
-      return NULL_TREE;
-    }
+      /* Naming a class member.  */
+      if (!TYPE_P (current))
+	{
+	  error ("using-declaration for member at non-class scope");
+	  return false;
+	}
+
+      /* Make sure the name is not invalid */
+      if (TREE_CODE (lookup.name) == BIT_NOT_EXPR)
+	{
+	  error ("%<%T::%D%> names destructor", scope, lookup.name);
+	  return false;
+	}
 
-  /* From [namespace.udecl]:
+      /* Using T::T declares inheriting ctors, even if T is a typedef.  */
+      if (MAYBE_CLASS_TYPE_P (scope)
+	  && (lookup.name == TYPE_IDENTIFIER (scope)
+	      || constructor_name_p (lookup.name, scope)))
+	{
+	  maybe_warn_cpp0x (CPP0X_INHERITING_CTORS);
+	  lookup.name = ctor_identifier;
+	  CLASSTYPE_NON_AGGREGATE (current) = true;
+	  TYPE_HAS_USER_CONSTRUCTOR (current) = true;
+    	}
 
-       A using-declaration used as a member-declaration shall refer to a
-       member of a base class of the class being defined.
+      /* Cannot introduce a constructor name.  */
+      if (constructor_name_p (lookup.name, current))
+	{
+	  error ("%<%T::%D%> names constructor in %qT",
+		 scope, lookup.name, current);
+	  return false;
+	}
 
-     In general, we cannot check this constraint in a template because
-     we do not know the entire set of base classes of the current
-     class type. Morover, if SCOPE is dependent, it might match a
-     non-dependent base.  */
+      /* Member using decls finish processing when completing the
+	 class.  */
+      /* From [namespace.udecl]:
 
-  tree decl = NULL_TREE;
-  if (!dependent_scope_p (scope))
-    {
-      base_kind b_kind;
-      tree binfo = lookup_base (current_class_type, scope, ba_any, &b_kind,
-				tf_warning_or_error);
-      if (b_kind < bk_proper_base)
+         A using-declaration used as a member-declaration shall refer
+         to a member of a base class of the class being defined.
+
+         In general, we cannot check this constraint in a template
+         because we do not know the entire set of base classes of the
+         current class type. Morover, if SCOPE is dependent, it might
+         match a non-dependent base.  */
+
+      dependent_p = dependent_scope_p (scope);
+      if (!dependent_p)
 	{
-	  /* If there are dependent bases, scope might resolve at
-	     instantiation time, even if it isn't exactly one of the
-	     dependent bases.  */
-	  if (b_kind == bk_same_type || !any_dependent_bases_p ())
+	  base_kind b_kind;
+	  tree binfo = lookup_base (current, scope, ba_any, &b_kind,
+				    tf_warning_or_error);
+	  if (b_kind < bk_proper_base)
 	    {
-	      error_not_base_type (scope, current_class_type);
-	      return NULL_TREE;
+	      /* If there are dependent bases, scope might resolve at
+		 instantiation time, even if it isn't exactly one of
+		 the dependent bases.  */
+	      if (b_kind == bk_same_type || !any_dependent_bases_p ())
+		{
+		  error_not_base_type (scope, current);
+		  return false;
+		}
+	      /* Treat as-if dependent.  */
+	      dependent_p = true;
 	    }
+	  else if (lookup.name == ctor_identifier && !binfo_direct_p (binfo))
+	    {
+	      error ("cannot inherit constructors from indirect base %qT",
+		     scope);
+	      return false;
+	    }
+	  else if (IDENTIFIER_CONV_OP_P (lookup.name)
+		   && dependent_type_p (TREE_TYPE (lookup.name)))
+	    dependent_p = true;
+	  else
+	    lookup.value = lookup_member (binfo, lookup.name, 0,
+					  false, tf_warning_or_error);
 	}
-      else if (name == ctor_identifier && !binfo_direct_p (binfo))
+    }
+
+  if (!dependent_p)
+    {
+      if (!lookup.value)
 	{
-	  error ("cannot inherit constructors from indirect base %qT", scope);
-	  return NULL_TREE;
+	  error ("%qD has not been declared in %qE", lookup.name, scope);
+	  return false;
 	}
-      else if (!IDENTIFIER_CONV_OP_P (name)
-	       || !dependent_type_p (TREE_TYPE (name)))
+
+      if (TREE_CODE (lookup.value) == TREE_LIST
+	  /* We can (independently) have ambiguous implicit typedefs.  */
+	  || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST))
 	{
-	  decl = lookup_member (binfo, name, 0, false, tf_warning_or_error);
-	  if (!decl)
-	    {
-	      error ("no members matching %<%T::%D%> in %q#T", scope, name,
-		     scope);
-	      return NULL_TREE;
-	    }
+	  error ("reference to %qD is ambiguous", lookup.name);
+	  print_candidates (TREE_CODE (lookup.value) == TREE_LIST
+			    ? lookup.value : lookup.type);
+	  return false;
+	}
 
-	  /* The binfo from which the functions came does not matter.  */
-	  if (BASELINK_P (decl))
-	    decl = BASELINK_FUNCTIONS (decl);
+      if (TREE_CODE (lookup.value) == NAMESPACE_DECL)
+	{
+	  error ("using-declaration may not name namespace %qD", lookup.value);
+	  return false;
 	}
     }
 
-  tree value = build_lang_decl (USING_DECL, name, NULL_TREE);
-  USING_DECL_DECLS (value) = decl;
-  USING_DECL_SCOPE (value) = scope;
-  DECL_DEPENDENT_P (value) = !decl;
+  return true;
+}
 
-  return value;
+/* Process "using SCOPE::NAME" in a class scope.  Return the
+   USING_DECL created.  */
+
+tree
+do_class_using_decl (tree scope, tree name)
+{
+  if (name == error_mark_node
+      || scope == error_mark_node)
+    return NULL_TREE;
+
+  name_lookup lookup (name, 0);
+  if (!lookup_using_decl (scope, lookup))
+    return NULL_TREE;
+
+  tree found = lookup.value;
+  if (found && BASELINK_P (found))
+    /* The binfo from which the functions came does not matter.  */
+    found = BASELINK_FUNCTIONS (found);
+
+  tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE);
+  USING_DECL_SCOPE (using_decl) = scope;
+  USING_DECL_DECLS (using_decl) = found;
+  DECL_DEPENDENT_P (using_decl) = !found;
+
+  return using_decl;
 }
 
@@ -5047,37 +5111,12 @@ finish_nonmember_using_decl (tree scope,
 {
   gcc_checking_assert (current_binding_level->kind != sk_class);
-  gcc_checking_assert (identifier_p (name));
-
-  name_lookup lookup (name, 0);
 
-  if (TREE_CODE (scope) != NAMESPACE_DECL)
-    {
-      error ("%qE is not a namespace or unscoped enum", scope);
-      return;
-    }
-
-  qualified_namespace_lookup (scope, &lookup);
-
-  if (!lookup.value)
-    {
-      error ("%qD has not been declared in %qE", name, scope);
-      return;
-    }
+  if (scope == error_mark_node || name == error_mark_node)
+    return;
 
-  if (TREE_CODE (lookup.value) == TREE_LIST
-      /* But we can (independently) have ambiguous implicit typedefs.  */
-      || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST))
-    {
-      error ("reference to %qD is ambiguous", name);
-      print_candidates (TREE_CODE (lookup.value) == TREE_LIST
-			? lookup.value : lookup.type);
-      return;
-    }
+  name_lookup lookup (name, 0);
 
-  if (TREE_CODE (lookup.value) == NAMESPACE_DECL)
-    {
-      error ("using-declaration may not name namespace %qD", lookup.value);
-      return;
-    }
+  if (!lookup_using_decl (scope, lookup))
+    return;
 
   /* Emit debug info.  */
@@ -5107,5 +5146,5 @@ finish_nonmember_using_decl (tree scope,
   else
     {
-      tree using_decl = build_lang_decl (USING_DECL, name, NULL_TREE);
+      tree using_decl = build_lang_decl (USING_DECL, lookup.name, NULL_TREE);
       USING_DECL_SCOPE (using_decl) = scope;
       add_decl_expr (using_decl);
@@ -5148,5 +5187,4 @@ finish_nonmember_using_decl (tree scope,
 	}
     }
-
 }
 
Index: gcc/testsuite/g++.dg/cpp0x/using-enum-2.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/using-enum-2.C	(revision 278096)
+++ gcc/testsuite/g++.dg/cpp0x/using-enum-2.C	(working copy)
@@ -6,15 +6,15 @@ namespace A
   enum class E { V };
 
-  using E::V;        // { dg-error "not a namespace or unscoped enum" }
+  using E::V;        // { dg-error "name enumerator" }
 }
 
 void foo()
 {
-  using A::E::V;     // { dg-error "not a namespace or unscoped enum" }
+  using A::E::V;     // { dg-error "name enumerator" }
 }
 
-using A::E::V;       // { dg-error "not a namespace or unscoped enum" }
+using A::E::V;       // { dg-error "name enumerator" }
 
 enum class F { U };
 
-using F::U;          // { dg-error "not a namespace or unscoped enum" }
+using F::U;          // { dg-error "name enumerator" }
Index: gcc/testsuite/g++.dg/cpp0x/using-enum-3.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/using-enum-3.C	(revision 278096)
+++ gcc/testsuite/g++.dg/cpp0x/using-enum-3.C	(working copy)
@@ -5,5 +5,5 @@ void f ()
 {
   enum e { a };
-  using e::a; // { dg-error "not a namespace or unscoped enum" }
+  using e::a; // { dg-error "name enumerator" }
 }
 
Index: gcc/testsuite/g++.dg/lookup/using4.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using4.C	(revision 278096)
+++ gcc/testsuite/g++.dg/lookup/using4.C	(working copy)
@@ -11,5 +11,5 @@ struct Bar : public Foo<T> {
         void foo()
         {
-                using Foo<T>::i;	// { dg-error "not a namespace" }
+                using Foo<T>::i;	// { dg-error "member at non-class scope" }
         }
 };
Index: gcc/testsuite/g++.dg/lookup/using7.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using7.C	(revision 278096)
+++ gcc/testsuite/g++.dg/lookup/using7.C	(working copy)
@@ -7,5 +7,4 @@ template <typename T> struct B : A<T> //
 {
   using A<T>::i; // { dg-error "incomplete" "incomplete" } 
-                 // { dg-error "using" "using" { target *-*-* } .-1 }
 };
 
Index: gcc/testsuite/g++.dg/template/using12.C
===================================================================
--- gcc/testsuite/g++.dg/template/using12.C	(revision 278096)
+++ gcc/testsuite/g++.dg/template/using12.C	(working copy)
@@ -4,4 +4,4 @@ struct A {
 template <typename T>
 struct S : public A {
-  using A::operator(); // { dg-error "no member" }
+  using A::operator(); // { dg-error "has not been declared" }
 };
Index: gcc/testsuite/g++.dg/template/using18.C
===================================================================
--- gcc/testsuite/g++.dg/template/using18.C	(revision 278096)
+++ gcc/testsuite/g++.dg/template/using18.C	(working copy)
@@ -26,5 +26,5 @@ template <class T>
 struct C : B1, B2<T>
 {
-    using B1::x; // { dg-error "no member" }
+    using B1::x; // { dg-error "has not been declared" }
     using B2<T>::y;
     using typename B2<T>::type;
Index: gcc/testsuite/g++.dg/template/using22.C
===================================================================
--- gcc/testsuite/g++.dg/template/using22.C	(revision 278096)
+++ gcc/testsuite/g++.dg/template/using22.C	(working copy)
@@ -17,5 +17,5 @@ template <class T>
 struct A<T>::B : A<T>
 {
-  using A::nonexist; // { dg-error "no members matching" }
+  using A::nonexist; // { dg-error "has not been declared" }
 };
 
@@ -23,5 +23,5 @@ template <class T>
 struct A<T>::C : A
 {
-  using A::nonexist; // { dg-error "no members matching" }
+  using A::nonexist; // { dg-error "has not been declared" }
 };
 
@@ -29,5 +29,5 @@ template <class T>
 struct A<T>::D : A<T>
 {
-  using A<T>::nonexist; // { dg-error "no members matching" }
+  using A<T>::nonexist; // { dg-error "has not been declared" }
 };
 
@@ -35,5 +35,5 @@ template <class T>
 struct A<T>::E : A
 {
-  using A<T>::nonexist; // { dg-error "no members matching" }
+  using A<T>::nonexist; // { dg-error "has not been declared" }
 };
 
