[C++ PATCH] Merge some using-decl handling
authorNathan Sidwell <nathan@gcc.gnu.org>
Tue, 12 Nov 2019 21:21:13 +0000 (21:21 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Tue, 12 Nov 2019 21:21:13 +0000 (21:21 +0000)
https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00971.html
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.

From-SVN: r278106

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/using-enum-2.C
gcc/testsuite/g++.dg/cpp0x/using-enum-3.C
gcc/testsuite/g++.dg/lookup/using4.C
gcc/testsuite/g++.dg/lookup/using7.C
gcc/testsuite/g++.dg/template/using12.C
gcc/testsuite/g++.dg/template/using18.C
gcc/testsuite/g++.dg/template/using22.C

index 3742e71fe3a7416bfdb927b40c184d1c042db8fb..bf50b1bcfa97d569e0a730c9fc551b90abaa2e46 100644 (file)
@@ -1,3 +1,9 @@
+2019-11-12  Nathan Sidwell  <nathan@acm.org>
+
+       * 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.
+
 2019-11-12  Martin Liska  <mliska@suse.cz>
 
        * name-lookup.c: Do not include params.h.
@@ -5,9 +11,9 @@
 
 2019-11-12  Martin Liska  <mliska@suse.cz>
 
-       * name-lookup.c (namespace_hints::namespace_hints): Replace old parameter syntax
-       with the new one, include opts.h if needed.  Use SET_OPTION_IF_UNSET
-       macro.
+       * name-lookup.c (namespace_hints::namespace_hints): Replace old
+       parameter syntax with the new one, include opts.h if needed.  Use
+       SET_OPTION_IF_UNSET macro.
        * typeck.c (comptypes): Likewise.
 
 2019-11-12  Maciej W. Rozycki  <macro@codesourcery.com>
index d114c8873b268401cbe1fa146cf370a508280a30..b399b4ed39dbd0bf9a9d74d47d628aadddf71024 100644 (file)
@@ -4584,102 +4584,166 @@ push_class_level_binding (tree name, tree x)
   return ret;
 }
 
-/* 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;
+       }
 
-  /* From [namespace.udecl]:
+      /* 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;
+       }
 
-       A using-declaration used as a member-declaration shall refer to a
-       member of a base class of the class being defined.
+      /* 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;
+       }
+
+      /* 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)
+           {
+             /* 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_not_base_type (scope, current_class_type);
-             return NULL_TREE;
+             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;
+}
+
+/* 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 value;
+  return using_decl;
 }
 
 \f
@@ -5046,39 +5110,14 @@ void
 finish_nonmember_using_decl (tree scope, tree name)
 {
   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.  */
   if (!processing_template_decl)
@@ -5106,7 +5145,7 @@ finish_nonmember_using_decl (tree scope, tree name)
     }
   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);
 
@@ -5147,7 +5186,6 @@ finish_nonmember_using_decl (tree scope, tree name)
          set_identifier_type_value (name, type);
        }
     }
-
 }
 
 /* Return the declarations that are members of the namespace NS.  */
index 557209336fffafd0e376417783c9e736aa09c412..a03b6844d290ee437a58c7606b94b0d0be193734 100644 (file)
@@ -1,3 +1,13 @@
+2019-11-12  Nathan Sidwell  <nathan@acm.org>
+
+       * 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.
+
 2019-11-12  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR target/92449
index 0738c802b3446927178e57a089ccb1ced9e9613e..faa381793055fd851509b628b5b10f2e03dd1afd 100644 (file)
@@ -5,16 +5,16 @@ 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 edc16890cb1aa42004b38c10f87016a22935921f..ecc4ddcccd86a38553113f1a26e726e733be886e 100644 (file)
@@ -4,7 +4,7 @@
 void f ()
 {
   enum e { a };
-  using e::a; // { dg-error "not a namespace or unscoped enum" }
+  using e::a; // { dg-error "name enumerator" }
 }
 
 struct S {
index a6421c87598b701b6c2cd57babddab53eda6c565..facb2b4fd31d981a4b8db3a732bc7c711381769b 100644 (file)
@@ -10,6 +10,6 @@ template <class T>
 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 f774021d9b44649e72c24825be7effa5058cbe7b..d92bf23d71d28ba15f642395a70958803af5c797 100644 (file)
@@ -6,7 +6,6 @@ template <typename T, bool=T::X> struct A
 template <typename T> struct B : A<T> // { dg-error "incomplete" }
 {
   using A<T>::i; // { dg-error "incomplete" "incomplete" } 
-                 // { dg-error "using" "using" { target *-*-* } .-1 }
 };
 
 B<void> b; // { dg-message "required" }
index cebfab1ee0bef5e88c389f61e0a8020d50f37a7b..0b652350e2a96d83a3fa8db310b7ee1cfc68ea19 100644 (file)
@@ -3,5 +3,5 @@ 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 b4ef6df478c34ce742e4bfbaad776c82149a7c51..caafdcfe1405d582e93722cac63bd4e76a71c2de 100644 (file)
@@ -25,7 +25,7 @@ template <class T> struct B2 {};
 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 9ea3d8a1e49283ee82d4e820ab6eb0538df91978..041b5c1348fcde8557160a970490e3a266e020d8 100644 (file)
@@ -16,25 +16,25 @@ struct A
 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" }
 };
 
 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" }
 };
 
 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" }
 };
 
 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" }
 };
 
 template <class T>