diff mbox series

[C++] Merge some using-decl handling

Message ID ebfb9a19-0f56-e05a-2cdf-6c8a42519df0@acm.org
State New
Headers show
Series [C++] Merge some using-decl handling | expand

Commit Message

Nathan Sidwell Nov. 12, 2019, 9:20 p.m. UTC
We currently process member and nonmember using decls completely 
separately.  C++20 will have some new using decls for enums (see 
wg21.link/p1099 for details), and there will be some commonality -- 
member using decls can refer to non-member enumerators and non-member 
using-decls can refer to member enumerators.

It makes sense to handle the lookup of using decls in one place, rather 
than duplicate the handling.  This patch does that, with no change to 
semantics.  Some error messages change, that is all.

nathan
diff mbox series

Patch

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" }
 };