[C++ PATCH] Using decls
authorNathan Sidwell <nathan@acm.org>
Tue, 21 May 2019 14:33:24 +0000 (14:33 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Tue, 21 May 2019 14:33:24 +0000 (14:33 +0000)
https://gcc.gnu.org/ml/gcc-patches/2019-05/msg01396.html
gcc/cp/
* name-lookup.h (struct cp_binding_level): Drop usings field.
(finish_namespace_using_decl, finish_local_using_decl): Replace with ...
(finish_nonmember_using_decl): ... this.
* name-lookup.c (push_using_decl_1, push_using_decl):
(do_nonmember_using_decl): ... here.  Add INSERT_P arg.  Reimplement.
(validate_nonmember_using_decl, finish_namespace_using_decl)
(finish_local_using_decl): Replace with ...
(finish_nonmember_using_decl): ... this.  Drop DECL parm.
* parser.c (cp_parser_using_declaration): Don't do lookup here.
* pt.c (tsubst_expr): Do not do using decl lookup here.

gcc/testsuite/
* g++.dg/lookup/using53.C: Adjust diagnostic.

libcc1/
* libcp1plugin.cc (plugin_add_using_decl): Use
finish_nonmember_using_decl.

From-SVN: r271467

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/using53.C
libcc1/ChangeLog
libcc1/libcp1plugin.cc

index f895f139ca7857d437d3b71881d7e44f9ce6f5e0..2095e1f5b4b2b77ffb6df84e6779198ee18193e9 100644 (file)
@@ -1,3 +1,16 @@
+2019-05-21  Nathan Sidwell  <nathan@acm.org>
+
+       * name-lookup.h (struct cp_binding_level): Drop usings field.
+       (finish_namespace_using_decl, finish_local_using_decl): Replace with ...
+       (finish_nonmember_using_decl): ... this.
+       * name-lookup.c (push_using_decl_1, push_using_decl):
+       (do_nonmember_using_decl): ... here.  Add INSERT_P arg.  Reimplement.
+       (validate_nonmember_using_decl, finish_namespace_using_decl)
+       (finish_local_using_decl): Replace with ...
+       (finish_nonmember_using_decl): ... this.  Drop DECL parm.
+       * parser.c (cp_parser_using_declaration): Don't do lookup here.
+       * pt.c (tsubst_expr): Do not do using decl lookup here.
+
 2019-05-21  Eric Botcazou  <ebotcazou@adacore.com>
 
        * decl2.c (cpp_check) <IS_ASSIGNMENT_OPERATOR>: New case.
index 476ba509231d233144e39e8b3434377e1b617c9e..1c21adba68268480c00bdaa4c80fb447d5e627e5 100644 (file)
@@ -3829,42 +3829,6 @@ make_lambda_name (void)
   return get_identifier (buf);
 }
 
-/* Insert another USING_DECL into the current binding level, returning
-   this declaration. If this is a redeclaration, do nothing, and
-   return NULL_TREE if this not in namespace scope (in namespace
-   scope, a using decl might extend any previous bindings).  */
-
-static tree
-push_using_decl_1 (tree scope, tree name)
-{
-  tree decl;
-
-  gcc_assert (TREE_CODE (scope) == NAMESPACE_DECL);
-  gcc_assert (identifier_p (name));
-  for (decl = current_binding_level->usings; decl; decl = DECL_CHAIN (decl))
-    if (USING_DECL_SCOPE (decl) == scope && DECL_NAME (decl) == name)
-      break;
-  if (decl)
-    return namespace_bindings_p () ? decl : NULL_TREE;
-  decl = build_lang_decl (USING_DECL, name, NULL_TREE);
-  USING_DECL_SCOPE (decl) = scope;
-  DECL_CHAIN (decl) = current_binding_level->usings;
-  current_binding_level->usings = decl;
-  return decl;
-}
-
-/* Wrapper for push_using_decl_1.  */
-
-static tree
-push_using_decl (tree scope, tree name)
-{
-  tree ret;
-  timevar_start (TV_NAME_LOOKUP);
-  ret = push_using_decl_1 (scope, name);
-  timevar_stop (TV_NAME_LOOKUP);
-  return ret;
-}
-
 /* Same as pushdecl, but define X in binding-level LEVEL.  We rely on the
    caller to set DECL_CONTEXT properly.
 
@@ -3918,91 +3882,19 @@ pushdecl_outermost_localscope (tree x)
   return ret;
 }
 
-/* Check a non-member using-declaration. Return the name and scope
-   being used, and the USING_DECL, or NULL_TREE on failure.  */
-
-static tree
-validate_nonmember_using_decl (tree decl, tree scope, tree name)
-{
-  /* [namespace.udecl]
-       A using-declaration for a class member shall be a
-       member-declaration.  */
-  if (TYPE_P (scope))
-    {
-      error ("%qT is not a namespace or unscoped enum", scope);
-      return NULL_TREE;
-    }
-  else if (scope == error_mark_node)
-    return NULL_TREE;
-
-  if (TREE_CODE (decl) == TEMPLATE_ID_EXPR)
-    {
-      /* 7.3.3/5
-          A using-declaration shall not name a template-id.  */
-      error ("a using-declaration cannot specify a template-id.  "
-            "Try %<using %D%>", name);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (decl) == NAMESPACE_DECL)
-    {
-      error ("namespace %qD not allowed in using-declaration", decl);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (decl) == SCOPE_REF)
-    {
-      /* It's a nested name with template parameter dependent scope.
-        This can only be using-declaration for class member.  */
-      error ("%qT is not a namespace", TREE_OPERAND (decl, 0));
-      return NULL_TREE;
-    }
-
-  decl = OVL_FIRST (decl);
-
-  /* Make a USING_DECL.  */
-  tree using_decl = push_using_decl (scope, name);
-
-  if (using_decl == NULL_TREE
-      && at_function_scope_p ()
-      && VAR_P (decl))
-    /* C++11 7.3.3/10.  */
-    error ("%qD is already declared in this scope", name);
-  
-  return using_decl;
-}
-
-/* Process a local-scope or namespace-scope using declaration.  SCOPE
+/* Process a local-scope or namespace-scope using declaration.
+   FIXME
    is the nominated scope to search for NAME.  VALUE_P and TYPE_P
    point to the binding for NAME in the current scope and are
    updated.  */
 
-static void
-do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
+static bool
+do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
+                        bool insert_p, tree *value_p, tree *type_p)
 {
-  name_lookup lookup (name, 0);
-
-  if (!qualified_namespace_lookup (scope, &lookup))
-    {
-      error ("%qD not declared", name);
-      return;
-    }
-  else if (TREE_CODE (lookup.value) == TREE_LIST)
-    {
-      error ("reference to %qD is ambiguous", name);
-      print_candidates (lookup.value);
-      lookup.value = NULL_TREE;
-    }
-
-  if (lookup.type && TREE_CODE (lookup.type) == TREE_LIST)
-    {
-      error ("reference to %qD is ambiguous", name);
-      print_candidates (lookup.type);
-      lookup.type = NULL_TREE;
-    }
-
   tree value = *value_p;
   tree type = *type_p;
+  bool failed = false;
 
   /* Shift the old and new bindings around so we're comparing class and
      enumeration names to each other.  */
@@ -4018,79 +3910,95 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
       lookup.value = NULL_TREE;
     }
 
-  if (lookup.value && lookup.value != value)
+  if (!lookup.value)
+    /* Nothing.  */;
+  else if (OVL_P (lookup.value) && (!value || OVL_P (value)))
     {
-      /* Check for using functions.  */
-      if (OVL_P (lookup.value) && (!value || OVL_P (value)))
+      for (lkp_iterator usings (lookup.value); usings; ++usings)
        {
-         for (lkp_iterator usings (lookup.value); usings; ++usings)
-           {
-             tree new_fn = *usings;
+         tree new_fn = *usings;
 
-             /* [namespace.udecl]
+         /* [namespace.udecl]
 
-                If a function declaration in namespace scope or block
-                scope has the same name and the same parameter types as a
-                function introduced by a using declaration the program is
-                ill-formed.  */
-             bool found = false;
-             for (ovl_iterator old (value); !found && old; ++old)
+            If a function declaration in namespace scope or block
+            scope has the same name and the same parameter types as a
+            function introduced by a using declaration the program is
+            ill-formed.  */
+         bool found = false;
+         for (ovl_iterator old (value); !found && old; ++old)
+           {
+             tree old_fn = *old;
+
+             if (new_fn == old_fn)
                {
-                 tree old_fn = *old;
-
-                 if (new_fn == old_fn)
-                   /* The function already exists in the current
-                      namespace.  */
-                   found = true;
-                 else if (old.using_p ())
-                   continue; /* This is a using decl. */
-                 else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn))
-                   continue; /* This is an anticipated builtin.  */
-                 else if (!matching_fn_p (new_fn, old_fn))
-                   continue; /* Parameters do not match.  */
-                 else if (decls_match (new_fn, old_fn))
-                   found = true;
-                 else
-                   {
-                     diagnose_name_conflict (new_fn, old_fn);
-                     found = true;
-                   }
+                 /* The function already exists in the current
+                    namespace.  */
+                 found = true;
+                 break;
+               }
+             else if (old.using_p ())
+               continue; /* This is a using decl. */
+             else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn))
+               continue; /* This is an anticipated builtin.  */
+             else if (!matching_fn_p (new_fn, old_fn))
+               continue; /* Parameters do not match.  */
+             else if (decls_match (new_fn, old_fn))
+               {
+                 /* Extern "C" in different namespaces.  */
+                 found = true;
+                 break;
+               }
+             else
+               {
+                 diagnose_name_conflict (new_fn, old_fn);
+                 failed = true;
+                 found = true;
+                 break;
                }
-
-             if (!found)
-               /* Unlike the overload case we don't drop anticipated
-                  builtins here.  They don't cause a problem, and
-                  we'd like to match them with a future
-                  declaration.  */
-               value = ovl_insert (new_fn, value, true);
            }
+
+         if (!found && insert_p)
+           /* Unlike the decl-pushing case we don't drop anticipated
+              builtins here.  They don't cause a problem, and we'd
+              like to match them with a future declaration.  */
+           value = ovl_insert (new_fn, value, true);
        }
-      else if (value
-              /* Ignore anticipated builtins.  */
-              && !anticipated_builtin_p (value)
-              && !decls_match (lookup.value, value))
-       diagnose_name_conflict (lookup.value, value);
-      else
-       value = lookup.value;
     }
+  else if (value
+          /* Ignore anticipated builtins.  */
+          && !anticipated_builtin_p (value)
+          && (fn_scope_p || !decls_match (lookup.value, value)))
+    {
+      diagnose_name_conflict (lookup.value, value);
+      failed = true;
+    }
+  else if (insert_p)
+    value = lookup.value;
 
   if (lookup.type && lookup.type != type)
     {
       if (type && !decls_match (lookup.type, type))
-       diagnose_name_conflict (lookup.type, type);
-      else
+       {
+         diagnose_name_conflict (lookup.type, type);
+         failed = true;
+       }
+      else if (insert_p)
        type = lookup.type;
     }
 
-  /* If bind->value is empty, shift any class or enumeration name back.  */
-  if (!value)
+  if (insert_p)
     {
-      value = type;
-      type = NULL_TREE;
+      /* If value is empty, shift any class or enumeration name back.  */
+      if (!value)
+       {
+         value = type;
+         type = NULL_TREE;
+       }
+      *value_p = value;
+      *type_p = type;
     }
 
-  *value_p = value;
-  *type_p = type;
+  return failed;
 }
 
 /* Returns true if ANCESTOR encloses DESCENDANT, including matching.
@@ -5120,84 +5028,115 @@ pushdecl_namespace_level (tree x, bool is_friend)
   return t;
 }
 
-/* Process a using-declaration appearing in namespace scope.  */
+/* Process a using declaration in non-class scope.  */
 
 void
-finish_namespace_using_decl (tree decl, tree scope, tree name)
+finish_nonmember_using_decl (tree scope, tree name)
 {
-  tree orig_decl = decl;
+  gcc_checking_assert (current_binding_level->kind != sk_class);
+  gcc_checking_assert (identifier_p (name));
 
-  gcc_checking_assert (current_binding_level->kind == sk_namespace
-                      && !processing_template_decl);
-  decl = validate_nonmember_using_decl (decl, scope, name);
-  if (decl == NULL_TREE)
-    return;
+  name_lookup lookup (name, 0);
 
-  tree *slot = find_namespace_slot (current_namespace, name, true);
-  tree val = slot ? MAYBE_STAT_DECL (*slot) : NULL_TREE;
-  tree type = slot ? MAYBE_STAT_TYPE (*slot) : NULL_TREE;
-  do_nonmember_using_decl (scope, name, &val, &type);
-  if (STAT_HACK_P (*slot))
+  if (TREE_CODE (scope) != NAMESPACE_DECL)
     {
-      STAT_DECL (*slot) = val;
-      STAT_TYPE (*slot) = type;
+      error ("%qE is not a namespace or unscoped enum", scope);
+      return;
     }
-  else if (type)
-    *slot = stat_hack (val, type);
-  else
-    *slot = val;
 
-  /* Emit debug info.  */
-  cp_emit_debug_info_for_using (orig_decl, current_namespace);
-}
+  qualified_namespace_lookup (scope, &lookup);
 
-/* Process a using-declaration at function scope.  */
+  if (!lookup.value)
+    {
+      error ("%qD has not been declared in %qE", name, scope);
+      return;
+    }
 
-void
-finish_local_using_decl (tree decl, tree scope, tree name)
-{
-  tree orig_decl = decl;
+  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;
+    }
 
-  gcc_checking_assert (current_binding_level->kind != sk_class
-                      && current_binding_level->kind != sk_namespace);
-  decl = validate_nonmember_using_decl (decl, scope, name);
-  if (decl == NULL_TREE)
-    return;
+  if (TREE_CODE (lookup.value) == NAMESPACE_DECL)
+    {
+      error ("using-declaration may not name namespace %qD", lookup.value);
+      return;
+    }
 
-  add_decl_expr (decl);
+  /* Emit debug info.  */
+  if (!processing_template_decl)
+    cp_emit_debug_info_for_using (lookup.value,
+                                 current_binding_level->this_entity);
 
-  cxx_binding *binding = find_local_binding (current_binding_level, name);
-  tree value = binding ? binding->value : NULL_TREE;
-  tree type = binding ? binding->type : NULL_TREE;
+  if (current_binding_level->kind == sk_namespace)
+    {
+      tree *slot = find_namespace_slot (current_namespace, name, true);
 
-  do_nonmember_using_decl (scope, name, &value, &type);
+      tree value = MAYBE_STAT_DECL (*slot);
+      tree type = MAYBE_STAT_TYPE (*slot);
 
-  if (!value)
-    ;
-  else if (binding && value == binding->value)
-    ;
-  else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
-    {
-      update_local_overload (IDENTIFIER_BINDING (name), value);
-      IDENTIFIER_BINDING (name)->value = value;
-    }
-  else
-    /* Install the new binding.  */
-    push_local_binding (name, value, true);
+      do_nonmember_using_decl (lookup, false, true, &value, &type);
 
-  if (!type)
-    ;
-  else if (binding && type == binding->type)
-    ;
+      if (STAT_HACK_P (*slot))
+       {
+         STAT_DECL (*slot) = value;
+         STAT_TYPE (*slot) = type;
+       }
+      else if (type)
+       *slot = stat_hack (value, type);
+      else
+       *slot = value;
+    }
   else
     {
-      push_local_binding (name, type, true);
-      set_identifier_type_value (name, type);
+      tree using_decl = build_lang_decl (USING_DECL, name, NULL_TREE);
+      USING_DECL_SCOPE (using_decl) = scope;
+      add_decl_expr (using_decl);
+
+      cxx_binding *binding = find_local_binding (current_binding_level, name);
+      tree value = NULL;
+      tree type = NULL;
+      if (binding)
+       {
+         value = binding->value;
+         type = binding->type;
+       }
+
+      /* DR 36 questions why using-decls at function scope may not be
+        duplicates.  Disallow it, as C++11 claimed and PR 20420
+        implemented.  */
+      do_nonmember_using_decl (lookup, true, true, &value, &type);
+
+      if (!value)
+       ;
+      else if (binding && value == binding->value)
+       ;
+      else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
+       {
+         update_local_overload (IDENTIFIER_BINDING (name), value);
+         IDENTIFIER_BINDING (name)->value = value;
+       }
+      else
+       /* Install the new binding.  */
+       // FIXME: Short circuit P_L_B
+       push_local_binding (name, value, true);
+
+      if (!type)
+       ;
+      else if (binding && type == binding->type)
+       ;
+      else
+       {
+         push_local_binding (name, type, true);
+         set_identifier_type_value (name, type);
+       }
     }
 
-  /* Emit debug info.  */
-  if (!processing_template_decl)
-    cp_emit_debug_info_for_using (orig_decl, current_scope ());
 }
 
 /* Return the declarations that are members of the namespace NS.  */
index aa6180f2d2a45706f2df18a9e0327fb8a00fdd72..b44687e96bb6653fe421226fc108b131e456ca90 100644 (file)
@@ -176,9 +176,6 @@ struct GTY(()) cp_binding_level {
       are wrapped in TREE_LISTs; the TREE_VALUE is the OVERLOAD.  */
   tree names;
 
-  /* A list of USING_DECL nodes.  */
-  tree usings;
-
   /* Using directives.  */
   vec<tree, va_gc> *using_directives;
 
@@ -315,9 +312,8 @@ 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);
 
-extern void finish_namespace_using_decl (tree, tree, tree);
-extern void finish_local_using_decl (tree, tree, tree);
-extern void finish_using_directive (tree, tree);
+extern void finish_nonmember_using_decl (tree scope, tree name);
+extern void finish_using_directive (tree target, tree attribs);
 extern tree pushdecl (tree, bool is_friend = false);
 extern tree pushdecl_outermost_localscope (tree);
 extern tree pushdecl_top_level (tree, bool is_friend = false);
index b2d6c33300d40f4195c7f21ce23550694296c25c..290f897ec140e79173511c218252e8333e63c7ed 100644 (file)
@@ -19519,24 +19519,7 @@ cp_parser_using_declaration (cp_parser* parser,
            finish_member_declaration (decl);
        }
       else
-       {
-         decl = cp_parser_lookup_name_simple (parser,
-                                              identifier,
-                                              token->location);
-         if (decl == error_mark_node)
-           cp_parser_name_lookup_error (parser, identifier,
-                                        decl, NLE_NULL,
-                                        token->location);
-         else if (check_for_bare_parameter_packs (decl))
-           {
-             cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
-             return false;
-           }
-         else if (!at_namespace_scope_p ())
-           finish_local_using_decl (decl, qscope, identifier);
-         else
-           finish_namespace_using_decl (decl, qscope, identifier);
-       }
+       finish_nonmember_using_decl (qscope, identifier);
     }
 
   if (!access_declaration_p
index 3519c7a34a6ea9e23d1d8708b4370aa86cfa613e..592adfcf5c1c1c4a53e7c42b7b3e83417f7b2c59 100644 (file)
@@ -17072,13 +17072,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
            tree name = DECL_NAME (decl);
 
            scope = tsubst (scope, args, complain, in_decl);
-           decl = lookup_qualified_name (scope, name,
-                                         /*is_type_p=*/false,
-                                         /*complain=*/false);
-           if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
-             qualified_name_lookup_error (scope, name, decl, input_location);
-           else
-             finish_local_using_decl (decl, scope, name);
+           finish_nonmember_using_decl (scope, name);
          }
        else if (is_capture_proxy (decl)
                 && !DECL_TEMPLATE_INSTANTIATION (current_function_decl))
index d68685ba9dbded804c3854e228bc95dda62ac816..bdc58ba14e44a318e96bdf42d53e7eda45d919ba 100644 (file)
@@ -1,3 +1,7 @@
+2019-05-21  Nathan Sidwell  <nathan@acm.org>
+
+       * g++.dg/lookup/using53.C: Adjust diagnostic.
+
 2019-05-21  Richard Biener  <rguenther@suse.de>
 
        PR middle-end/90510
index a108b50ef89d59a7d2bb903db45ac4c3210a3dd2..595612e4efe7d5b748d588e9f3981fef573ed6ae 100644 (file)
@@ -49,5 +49,5 @@ void
 f ()
 {
   using N::i;
-  using N::i;       // { dg-error "declared" }
+  using N::i;       // { dg-error "redeclaration" }
 }
index 376e3622410fb4e72725d53d1264695c3606d603..e243e554d6404de2f07c732428a3f43773ce0f2a 100644 (file)
@@ -1,3 +1,8 @@
+2019-05-21  Nathan Sidwell  <nathan@acm.org>
+
+       * libcp1plugin.cc (plugin_add_using_decl): Use
+       finish_nonmember_using_decl.
+
 2019-05-20  Nathan Sidwell  <nathan@acm.org>
 
        * libcp1plugin.cc (plugin_add_using_namespace): Call renamed
index eed94662f85d07d00a13173418febebbf791fe0c..d241ea1033dfda9e60118074d4b6ceb526a578d2 100644 (file)
@@ -1019,7 +1019,7 @@ plugin_add_using_decl (cc1_plugin::connection *,
     {
       /* We can't be at local scope.  */
       gcc_assert (at_namespace_scope_p ());
-      finish_namespace_using_decl (target, tcontext, identifier);
+      finish_nonmember_using_decl (tcontext, identifier);
     }
 
   return 1;