public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] Using decls
@ 2019-05-21 14:32 Nathan Sidwell
  2019-05-21 14:44 ` Marek Polacek
  0 siblings, 1 reply; 5+ messages in thread
From: Nathan Sidwell @ 2019-05-21 14:32 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 224 bytes --]

This patch reimplements using-decl handling.  It removes the double 
lookup of the target name, and commonizes the local- and namespace- 
scope handling into a single function.

Applying to trunk.

nathan
-- 
Nathan Sidwell

[-- Attachment #2: using-1.diff --]
[-- Type: text/x-patch, Size: 17874 bytes --]

2019-05-21  Nathan Sidwell  <nathan@acm.org>

	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.

Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 271427)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -3830,40 +3830,4 @@ make_lambda_name (void)
 }
 
-/* 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.
@@ -3919,89 +3883,17 @@ pushdecl_outermost_localscope (tree x)
 }
 
-/* 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
@@ -4019,77 +3911,93 @@ do_nonmember_using_decl (tree scope, tre
     }
 
-  if (lookup.value && lookup.value != value)
-    {
-      /* Check for using functions.  */
-      if (OVL_P (lookup.value) && (!value || OVL_P (value)))
-	{
-	  for (lkp_iterator usings (lookup.value); usings; ++usings)
+  if (!lookup.value)
+    /* Nothing.  */;
+  else if (OVL_P (lookup.value) && (!value || OVL_P (value)))
+    {
+      for (lkp_iterator usings (lookup.value); usings; ++usings)
+	{
+	  tree new_fn = *usings;
+
+	  /* [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)
 	    {
-	      tree new_fn = *usings;
+	      tree old_fn = *old;
 
-	      /* [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 (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);
 	    }
-	}
-      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;
+
+	  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)
+	   && (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;
 }
 
@@ -5121,82 +5029,113 @@ pushdecl_namespace_level (tree x, bool i
 }
 
-/* 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;
+    }
+
+  /* Emit debug info.  */
+  if (!processing_template_decl)
+    cp_emit_debug_info_for_using (lookup.value,
+				  current_binding_level->this_entity);
 
-  add_decl_expr (decl);
+  if (current_binding_level->kind == sk_namespace)
+    {
+      tree *slot = find_namespace_slot (current_namespace, name, true);
 
-  cxx_binding *binding = find_local_binding (current_binding_level, name);
-  tree value = binding ? binding->value : NULL_TREE;
-  tree type = binding ? binding->type : NULL_TREE;
+      tree value = MAYBE_STAT_DECL (*slot);
+      tree type = MAYBE_STAT_TYPE (*slot);
 
-  do_nonmember_using_decl (scope, name, &value, &type);
+      do_nonmember_using_decl (lookup, false, 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;
+      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
-    /* Install the new binding.  */
-    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);
+      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 ());
 }
 
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h	(revision 271427)
+++ gcc/cp/name-lookup.h	(working copy)
@@ -177,7 +177,4 @@ struct GTY(()) cp_binding_level {
   tree names;
 
-  /* A list of USING_DECL nodes.  */
-  tree usings;
-
   /* Using directives.  */
   vec<tree, va_gc> *using_directives;
@@ -316,7 +313,6 @@ extern cxx_binding *outer_binding (tree,
 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);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 271427)
+++ gcc/cp/parser.c	(working copy)
@@ -19520,22 +19520,5 @@ cp_parser_using_declaration (cp_parser*
 	}
       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);
     }
 
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 271427)
+++ gcc/cp/pt.c	(working copy)
@@ -17061,11 +17061,5 @@ tsubst_expr (tree t, tree args, tsubst_f
 
 	    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)
Index: gcc/testsuite/g++.dg/lookup/using53.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using53.C	(revision 271427)
+++ gcc/testsuite/g++.dg/lookup/using53.C	(working copy)
@@ -50,4 +50,4 @@ f ()
 {
   using N::i;
-  using N::i;       // { dg-error "declared" }
+  using N::i;       // { dg-error "redeclaration" }
 }
Index: libcc1/libcp1plugin.cc
===================================================================
--- libcc1/libcp1plugin.cc	(revision 271427)
+++ libcc1/libcp1plugin.cc	(working copy)
@@ -1020,5 +1020,5 @@ plugin_add_using_decl (cc1_plugin::conne
       /* 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);
     }
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [C++ PATCH] Using decls
  2019-05-21 14:32 [C++ PATCH] Using decls Nathan Sidwell
@ 2019-05-21 14:44 ` Marek Polacek
  2019-05-21 14:47   ` Nathan Sidwell
  2019-05-21 15:30   ` Nathan Sidwell
  0 siblings, 2 replies; 5+ messages in thread
From: Marek Polacek @ 2019-05-21 14:44 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: GCC Patches

Thanks for the patch and sorry for nitpicking:

On Tue, May 21, 2019 at 10:32:31AM -0400, Nathan Sidwell wrote:
> -/* Process a local-scope or namespace-scope using declaration.  SCOPE
> +/* Process a local-scope or namespace-scope using declaration.
> +   FIXME

This ain't look right.  You meant to document the INSERT_P param, right.

> +      /* 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

Was this FIXME meant to be here?

Marek

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [C++ PATCH] Using decls
  2019-05-21 14:44 ` Marek Polacek
@ 2019-05-21 14:47   ` Nathan Sidwell
  2019-05-21 15:30   ` Nathan Sidwell
  1 sibling, 0 replies; 5+ messages in thread
From: Nathan Sidwell @ 2019-05-21 14:47 UTC (permalink / raw)
  To: gcc-patches

On 5/21/19 10:43 AM, Marek Polacek wrote:
> Thanks for the patch and sorry for nitpicking:
> 
> On Tue, May 21, 2019 at 10:32:31AM -0400, Nathan Sidwell wrote:
>> -/* Process a local-scope or namespace-scope using declaration.  SCOPE
>> +/* Process a local-scope or namespace-scope using declaration.
>> +   FIXME
> 
> This ain't look right.  You meant to document the INSERT_P param, right.

Yes indeed.  Found these when merging back to modules.  Thanks for noticing!


-- 
Nathan Sidwell

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [C++ PATCH] Using decls
  2019-05-21 14:44 ` Marek Polacek
  2019-05-21 14:47   ` Nathan Sidwell
@ 2019-05-21 15:30   ` Nathan Sidwell
  1 sibling, 0 replies; 5+ messages in thread
From: Nathan Sidwell @ 2019-05-21 15:30 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 554 bytes --]

On 5/21/19 10:43 AM, Marek Polacek wrote:
> Thanks for the patch and sorry for nitpicking:
> 
> On Tue, May 21, 2019 at 10:32:31AM -0400, Nathan Sidwell wrote:
>> -/* Process a local-scope or namespace-scope using declaration.  SCOPE
>> +/* Process a local-scope or namespace-scope using declaration.
>> +   FIXME
> 
> This ain't look right.  You meant to document the INSERT_P param, right.

The INSERT_P parameter is not (yet) needed.  This patch removes it and 
cleans up the inadvertent stray FIXMEs.  Sorry for the noise.

nathan
-- 
Nathan Sidwell

[-- Attachment #2: ns-using-2.diff --]
[-- Type: text/x-patch, Size: 5340 bytes --]

2019-05-20  Nathan Sidwell  <nathan@acm.org>

	gcc/cp/
	* name-lookup.c (finish_namespace_using_directive)
	(finish_local_using_directive): Merge to ...
	(finish_using_directive): ... here.  Handle both contexts.
	* name-lookup.h (finish_namespace_using_directive)
	(finish_local_using_directive): Replace with ...
	(finish_using_directive): ... this.
	* parser.c (cp_parser_using_directive): Adjust.
	* pt.c (tsubst_expr): Likewise.

	libcc1/
	* libcp1plugin.cc (plugin_add_using_namespace): Call renamed
	finish_using_directive.

Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 271416)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -7235,52 +7235,36 @@ emit_debug_info_using_namespace (tree fr
 }
 
-/* Process a namespace-scope using directive.  */
+/* Process a using directive.  */
 
 void
-finish_namespace_using_directive (tree target, tree attribs)
+finish_using_directive (tree target, tree attribs)
 {
-  gcc_checking_assert (namespace_bindings_p ());
   if (target == error_mark_node)
     return;
 
-  add_using_namespace (current_binding_level->using_directives,
-		       ORIGINAL_NAMESPACE (target));
-  emit_debug_info_using_namespace (current_namespace,
-				   ORIGINAL_NAMESPACE (target), false);
-
-  if (attribs == error_mark_node)
-    return;
-
-  for (tree a = attribs; a; a = TREE_CHAIN (a))
-    {
-      tree name = get_attribute_name (a);
-      if (is_attribute_p ("strong", name))
-	{
-	  warning (0, "strong using directive no longer supported");
-	  if (CP_DECL_CONTEXT (target) == current_namespace)
-	    inform (DECL_SOURCE_LOCATION (target),
-		    "you may use an inline namespace instead");
-	}
-      else
-	warning (OPT_Wattributes, "%qD attribute directive ignored", name);
-    }
-}
-
-/* Process a function-scope using-directive.  */
-
-void
-finish_local_using_directive (tree target, tree attribs)
-{
-  gcc_checking_assert (local_bindings_p ());
-  if (target == error_mark_node)
-    return;
-
-  if (attribs)
-    warning (OPT_Wattributes, "attributes ignored on local using directive");
-
-  add_stmt (build_stmt (input_location, USING_STMT, target));
+  if (current_binding_level->kind != sk_namespace)
+    add_stmt (build_stmt (input_location, USING_STMT, target));
+  else
+    emit_debug_info_using_namespace (current_binding_level->this_entity,
+				     ORIGINAL_NAMESPACE (target), false);
 
   add_using_namespace (current_binding_level->using_directives,
 		       ORIGINAL_NAMESPACE (target));
+
+  if (attribs != error_mark_node)
+    for (tree a = attribs; a; a = TREE_CHAIN (a))
+      {
+	tree name = get_attribute_name (a);
+	if (current_binding_level->kind == sk_namespace
+	    && is_attribute_p ("strong", name))
+	  {
+	    warning (0, "strong using directive no longer supported");
+	    if (CP_DECL_CONTEXT (target) == current_namespace)
+	      inform (DECL_SOURCE_LOCATION (target),
+		      "you may use an inline namespace instead");
+	  }
+	else
+	  warning (OPT_Wattributes, "%qD attribute directive ignored", name);
+      }
 }
 
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h	(revision 271416)
+++ gcc/cp/name-lookup.h	(working copy)
@@ -1,3 +1,3 @@
-/* Declarations for C++ name lookup routines.
+/* Declarations for -*- C++ -*- name lookup routines.
    Copyright (C) 2003-2019 Free Software Foundation, Inc.
    Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
@@ -318,6 +318,5 @@ extern void cp_emit_debug_info_for_using
 extern void finish_namespace_using_decl (tree, tree, tree);
 extern void finish_local_using_decl (tree, tree, tree);
-extern void finish_namespace_using_directive (tree, tree);
-extern void finish_local_using_directive (tree, tree);
+extern void finish_using_directive (tree, tree);
 extern tree pushdecl (tree, bool is_friend = false);
 extern tree pushdecl_outermost_localscope (tree);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 271416)
+++ gcc/cp/parser.c	(working copy)
@@ -19738,8 +19738,5 @@ cp_parser_using_directive (cp_parser* pa
 
   /* Update the symbol table.  */
-  if (namespace_bindings_p ())
-    finish_namespace_using_directive (namespace_decl, attribs);
-  else
-    finish_local_using_directive (namespace_decl, attribs);
+  finish_using_directive (namespace_decl, attribs);
 
   /* Look for the final `;'.  */
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 271416)
+++ gcc/cp/pt.c	(working copy)
@@ -17044,6 +17044,5 @@ tsubst_expr (tree t, tree args, tsubst_f
 
     case USING_STMT:
-      finish_local_using_directive (USING_STMT_NAMESPACE (t),
-				    /*attribs=*/NULL_TREE);
+      finish_using_directive (USING_STMT_NAMESPACE (t), /*attribs=*/NULL_TREE);
       break;
 
Index: libcc1/libcp1plugin.cc
===================================================================
--- libcc1/libcp1plugin.cc	(revision 271416)
+++ libcc1/libcp1plugin.cc	(working copy)
@@ -942,5 +942,5 @@ plugin_add_using_namespace (cc1_plugin::
   gcc_assert (TREE_CODE (used_ns) == NAMESPACE_DECL);
 
-  finish_namespace_using_directive (used_ns, NULL_TREE);
+  finish_using_directive (used_ns, NULL_TREE);
 
   return 1;

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [C++ PATCH] using decls
@ 2017-05-23 11:07 Nathan Sidwell
  0 siblings, 0 replies; 5+ messages in thread
From: Nathan Sidwell @ 2017-05-23 11:07 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 441 bytes --]

This patch addresses namespace and local scope using declarations. 
Unlike the using directive case, we already had separate workers for 
these, they just needed a bit of cleanup to use the new iterator and 
make them ready for the pushdecl change that's coming.  I renamed them 
consistently with the directive name change I made yesterday.

There'll be a final change to these once the other pieces have landed.

nathan
-- 
Nathan Sidwell

[-- Attachment #2: udecl.diff --]
[-- Type: text/x-patch, Size: 25705 bytes --]

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

	gcc/cp
	* cp-tree.h (OVL_P): New.
	* name-lookup.h (push_local_binding): Delete.
	(do_toplevel_using_decl, do_local_using_decl): Rename to ...
	(finish_namespace_using_decl, finish_local_using_decl): ... here
	* name-lookup.c (add_decl_to_level): Swap args.
	(pop_bindings_and_leave_scope): Look inside TREE_LIST.
	(diagnose_name_conflict): Check contexts are same for redecl.
	(update_local_overload): New.
	(compparms_for_decl_and_using): Rename to ...
	(matching_fn_p): ... here.
	(pushdecl_maybe_friend_1): Adjust add_decl_to_level,
	push_local_bindings call.
	(push_local_binding): Make static, replace FLAGS arg with
	IS_USING.
	(validate_nonmember_using_decl): Use OVL_FIRST.
	(do_nonmember_using_decl): Use in/out parameters.  Use
	lkp_iterator and simplify.
	(do_toplevel_using_decl, do_local_using_decl): Rename to ...
	(finish_namespace_using_decl, finish_local_using_decl): ... here.
	Adjust.
	(lookup_type_current_level): Delete.
	* parser.c (cp_parser_using_declaration): Adjust.
	* pt.c (tsubst_expr): Adjust.

	libcc1/
	* libcp1plugin.cc (plugin_add_using_decl): Call
	finish_namespace_using_decl.  Use assert not unreachable.

	gcc/testsuite/
	* g++.dg/lookup/using13.C: Adjust expected error.

Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 248338)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -671,6 +671,11 @@ typedef struct ptrmem_cst * ptrmem_cst_t
 /* The name of the overload set.  */
 #define OVL_NAME(NODE) DECL_NAME (OVL_FIRST (NODE))
 
+/* Whether this is a set of overloaded functions.  TEMPLATE_DECLS are
+   always wrapped in an OVERLOAD, so we don't need to check them
+   here.  */
+#define OVL_P(NODE) \
+  (TREE_CODE (NODE) == FUNCTION_DECL || TREE_CODE (NODE) == OVERLOAD)
 /* Whether this is a single member overload.  */
 #define OVL_SINGLE_P(NODE) \
   (TREE_CODE (NODE) != OVERLOAD || !OVL_CHAIN (NODE))
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 248338)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -38,6 +38,7 @@ static cp_binding_level *innermost_noncl
 static void set_identifier_type_value_with_scope (tree id, tree decl,
 						  cp_binding_level *b);
 static void set_namespace_binding (tree scope, tree name, tree val);
+static void push_local_binding (tree, tree, bool);
 
 /* The bindings for a particular name in a particular scope.  */
 
@@ -58,14 +59,13 @@ static void consider_binding_level (tree
 				    cp_binding_level *lvl,
 				    bool look_within_fields,
 				    enum lookup_name_fuzzy_kind kind);
-static tree lookup_type_current_level (tree);
 static tree push_using_directive (tree);
 static void diagnose_name_conflict (tree, tree);
 
 /* Add DECL to the list of things declared in B.  */
 
 static void
-add_decl_to_level (tree decl, cp_binding_level *b)
+add_decl_to_level (cp_binding_level *b, tree decl)
 {
   /* We used to record virtual tables as if they were ordinary
      variables, but no longer do so.  */
@@ -995,7 +995,13 @@ void
 pop_bindings_and_leave_scope (void)
 {
   for (tree t = get_local_decls (); t; t = DECL_CHAIN (t))
-    pop_local_binding (DECL_NAME (t), t);
+    {
+      tree decl = TREE_CODE (t) == TREE_LIST ? TREE_VALUE (t) : t;
+      tree name = OVL_NAME (decl);
+
+      pop_local_binding (name, decl);
+    }
+
   leave_scope ();
 }
 
@@ -1179,7 +1185,8 @@ diagnose_name_conflict (tree decl, tree
       && (TREE_CODE (decl) != TYPE_DECL
 	  || (DECL_ARTIFICIAL (decl) && DECL_ARTIFICIAL (bval))
 	  || (!DECL_ARTIFICIAL (decl) && !DECL_ARTIFICIAL (bval)))
-      && !is_overloaded_fn (decl))
+      && !DECL_DECLARES_FUNCTION_P (decl)
+      && CP_DECL_CONTEXT (decl) == CP_DECL_CONTEXT (bval))
     error ("redeclaration of %q#D", decl);
   else
     error ("%q#D conflicts with a previous declaration", decl);
@@ -1199,6 +1206,56 @@ supplement_binding (cxx_binding *binding
   return ret;
 }
 
+/* Replace BINDING's current value on its scope's name list with
+   NEWVAL.  */
+
+static void
+update_local_overload (cxx_binding *binding, tree newval)
+{
+  tree *d;
+
+  for (d = &binding->scope->names; ; d = &TREE_CHAIN (*d))
+    if (*d == binding->value)
+      {
+	/* Stitch new list node in.  */
+	*d = tree_cons (NULL_TREE, NULL_TREE, TREE_CHAIN (*d));
+	break;
+      }
+    else if (TREE_CODE (*d) == TREE_LIST && TREE_VALUE (*d) == binding->value)
+      break;
+
+  TREE_VALUE (*d) = newval;
+}
+
+/* Compares the parameter-type-lists of ONE and TWO and
+   returns false if they are different.  If the DECLs are template
+   functions, the return types and the template parameter lists are
+   compared too (DR 565).  */
+
+static bool
+matching_fn_p (tree one, tree two)
+{
+  if (!compparms (TYPE_ARG_TYPES (TREE_TYPE (one)),
+		  TYPE_ARG_TYPES (TREE_TYPE (two))))
+    return false;
+
+  if (TREE_CODE (one) == TEMPLATE_DECL
+      && TREE_CODE (two) == TEMPLATE_DECL)
+    {
+      /* Compare template parms.  */
+      if (!comp_template_parms (DECL_TEMPLATE_PARMS (one),
+				DECL_TEMPLATE_PARMS (two)))
+	return false;
+
+      /* And return type.  */
+      if (!same_type_p (TREE_TYPE (TREE_TYPE (one)),
+			TREE_TYPE (TREE_TYPE (two))))
+	return false;
+    }
+
+  return true;
+}
+
 /* Map of identifiers to extern C functions (or LISTS thereof).  */
 
 static GTY(()) hash_map<lang_identifier *, tree> *extern_c_fns;
@@ -1699,7 +1756,7 @@ pushdecl_maybe_friend_1 (tree x, bool is
 	{
 	  t = push_overloaded_decl (x, PUSH_GLOBAL, is_friend);
 	  if (t == x)
-	    add_decl_to_level (x, NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)));
+	    add_decl_to_level (NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)), x);
 	}
 
       if (DECL_DECLARES_FUNCTION_P (t))
@@ -1814,7 +1871,7 @@ pushdecl_maybe_friend_1 (tree x, bool is
 
 	  if (need_new_binding)
 	    {
-	      push_local_binding (name, x, 0);
+	      push_local_binding (name, x, false);
 	      /* Because push_local_binding will hook X on to the
 		 current_binding_level's name list, we don't want to
 		 do that again below.  */
@@ -1881,10 +1938,9 @@ pushdecl_maybe_friend_1 (tree x, bool is
     }
 
   if (need_new_binding)
-    add_decl_to_level (x,
-		       DECL_NAMESPACE_SCOPE_P (x)
+    add_decl_to_level (DECL_NAMESPACE_SCOPE_P (x)
 		       ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
-		       : current_binding_level);
+		       : current_binding_level, x);
 
   return x;
 }
@@ -1932,12 +1988,11 @@ maybe_push_decl (tree decl)
 }
 
 /* Bind DECL to ID in the current_binding_level, assumed to be a local
-   binding level.  If PUSH_USING is set in FLAGS, we know that DECL
-   doesn't really belong to this binding level, that it got here
-   through a using-declaration.  */
+   binding level.  If IS_USING is true, DECL got here through a
+   using-declaration.  */
 
-void
-push_local_binding (tree id, tree decl, int flags)
+static void
+push_local_binding (tree id, tree decl, bool is_using)
 {
   cp_binding_level *b;
 
@@ -1958,15 +2013,14 @@ push_local_binding (tree id, tree decl,
     /* Create a new binding.  */
     push_binding (id, decl, b);
 
-  if (TREE_CODE (decl) == OVERLOAD || (flags & PUSH_USING))
-    /* We must put the OVERLOAD into a TREE_LIST since the
-       TREE_CHAIN of an OVERLOAD is already used.  Similarly for
-       decls that got here through a using-declaration.  */
+  if (TREE_CODE (decl) == OVERLOAD || is_using)
+    /* We must put the OVERLOAD or using into a TREE_LIST since we
+       cannot use the decl's chain itself.  */
     decl = build_tree_list (NULL_TREE, decl);
 
   /* And put DECL on the list of things declared by the current
      binding level.  */
-  add_decl_to_level (decl, b);
+  add_decl_to_level (b, decl);
 }
 
 /* Check to see whether or not DECL is a variable that would have been
@@ -2840,28 +2894,6 @@ pushdecl_outermost_localscope (tree x)
   return ret;
 }
 
-/* Helper function for push_overloaded_decl_1 and do_nonmember_using_decl.
-   Compares the parameter-type-lists of DECL1 and DECL2 and returns false
-   if they are different.  If the DECLs are template functions, the return
-   types and the template parameter lists are compared too (DR 565).  */
-
-static bool
-compparms_for_decl_and_using_decl (tree decl1, tree decl2)
-{
-  if (!compparms (TYPE_ARG_TYPES (TREE_TYPE (decl1)),
-		  TYPE_ARG_TYPES (TREE_TYPE (decl2))))
-    return false;
-
-  if (! DECL_FUNCTION_TEMPLATE_P (decl1)
-      || ! DECL_FUNCTION_TEMPLATE_P (decl2))
-    return true;
-
-  return (comp_template_parms (DECL_TEMPLATE_PARMS (decl1),
-			       DECL_TEMPLATE_PARMS (decl2))
-	  && same_type_p (TREE_TYPE (TREE_TYPE (decl1)),
-			  TREE_TYPE (TREE_TYPE (decl2))));
-}
-
 /* DECL is a FUNCTION_DECL for a non-member function, which may have
    other definitions already in place.  We get around this by making
    the value of the identifier point to a list of all the things that
@@ -2918,7 +2950,7 @@ push_overloaded_decl_1 (tree decl, int f
 
 	      if (TREE_CODE (tmp) == OVERLOAD && OVL_USING_P (tmp)
 		  && !(flags & PUSH_USING)
-		  && compparms_for_decl_and_using_decl (fn, decl)
+		  && matching_fn_p (fn, decl)
 		  && ! decls_match (fn, decl))
 		diagnose_name_conflict (decl, fn);
 
@@ -3047,10 +3079,7 @@ validate_nonmember_using_decl (tree decl
       return NULL_TREE;
     }
 
-  if (is_overloaded_fn (decl))
-    decl = get_first_fn (decl);
-
-  gcc_assert (DECL_P (decl));
+  decl = OVL_FIRST (decl);
 
   /* Make a USING_DECL.  */
   tree using_decl = push_using_decl (scope, name);
@@ -3064,60 +3093,64 @@ validate_nonmember_using_decl (tree decl
   return using_decl;
 }
 
-/* Process local and global using-declarations.  */
+/* Process a local-scope or namespace-scope using declaration.  SCOPE
+   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 oldval, tree oldtype,
-			 tree *newval, tree *newtype)
+do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
 {
-  struct scope_binding decls = EMPTY_SCOPE_BINDING;
+  struct scope_binding lookup = EMPTY_SCOPE_BINDING;
 
-  *newval = *newtype = NULL_TREE;
-  if (!qualified_lookup_using_namespace (name, scope, &decls, 0))
+  if (!qualified_lookup_using_namespace (name, scope, &lookup, 0))
     /* Lookup error */
     return;
 
-  if (!decls.value && !decls.type)
+  if (!lookup.value)
     {
       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;
 
   /* Shift the old and new bindings around so we're comparing class and
      enumeration names to each other.  */
-  if (oldval && DECL_IMPLICIT_TYPEDEF_P (oldval))
+  if (value && DECL_IMPLICIT_TYPEDEF_P (value))
     {
-      oldtype = oldval;
-      oldval = NULL_TREE;
+      type = value;
+      value = NULL_TREE;
     }
 
-  if (decls.value && DECL_IMPLICIT_TYPEDEF_P (decls.value))
+  if (lookup.value && DECL_IMPLICIT_TYPEDEF_P (lookup.value))
     {
-      decls.type = decls.value;
-      decls.value = NULL_TREE;
+      lookup.type = lookup.value;
+      lookup.value = NULL_TREE;
     }
 
-  if (decls.value)
+  if (lookup.value && lookup.value != value)
     {
       /* Check for using functions.  */
-      if (is_overloaded_fn (decls.value))
+      if (OVL_P (lookup.value) && (!value || OVL_P (value)))
 	{
-	  tree tmp, tmp1;
-
-	  if (oldval && !is_overloaded_fn (oldval))
+	  for (lkp_iterator usings (lookup.value); usings; ++usings)
 	    {
-	      error ("%qD is already declared in this scope", name);
-	      oldval = NULL_TREE;
-	    }
-
-	  *newval = oldval;
-	  for (tmp = decls.value; tmp; tmp = OVL_NEXT (tmp))
-	    {
-	      tree new_fn = OVL_CURRENT (tmp);
-
-	      /* Don't import functions that haven't been declared.  */
-	      if (DECL_ANTICIPATED (new_fn))
-		continue;
+	      tree new_fn = *usings;
 
 	      /* [namespace.udecl]
 
@@ -3125,138 +3158,67 @@ do_nonmember_using_decl (tree scope, tre
 		 scope has the same name and the same parameter types as a
 		 function introduced by a using declaration the program is
 		 ill-formed.  */
-	      for (tmp1 = oldval; tmp1; tmp1 = OVL_NEXT (tmp1))
+	      bool found = false;
+	      for (ovl_iterator old (value); !found && old; ++old)
 		{
-		  tree old_fn = OVL_CURRENT (tmp1);
+		  tree old_fn = *old;
 
 		  if (new_fn == old_fn)
-		    /* The function already exists in the current namespace.  */
-		    break;
-		  else if (TREE_CODE (tmp1) == OVERLOAD && OVL_USING_P (tmp1))
-		    continue; /* this is a using decl */
-		  else if (compparms_for_decl_and_using_decl (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 (DECL_ANTICIPATED (old_fn)
+			   && !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
 		    {
-		      /* There was already a non-using declaration in
-			 this scope with the same parameter types. If both
-			 are the same extern "C" functions, that's ok.  */
-		      if (DECL_ANTICIPATED (old_fn)
-			  && !DECL_HIDDEN_FRIEND_P (old_fn))
-			/* Ignore anticipated built-ins.  */;
-		      else if (decls_match (new_fn, old_fn))
-			break;
-		      else
-			{
-			  diagnose_name_conflict (new_fn, old_fn);
-			  break;
-			}
+		      diagnose_name_conflict (new_fn, old_fn);
+		      found = true;
 		    }
 		}
 
-	      /* If we broke out of the loop, there's no reason to add
-		 this function to the using declarations for this
-		 scope.  */
-	      if (tmp1)
-		continue;
-
-	      /* If we are adding to an existing OVERLOAD, then we no
-		 longer know the type of the set of functions.  */
-	      if (*newval && TREE_CODE (*newval) == OVERLOAD)
-		TREE_TYPE (*newval) = unknown_type_node;
-	      /* Add this new function to the set.  */
-	      *newval = ovl_insert (OVL_CURRENT (tmp), *newval, true);
+	      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);
 	    }
 	}
+      else if (value
+	       /* Ignore anticipated builtins.  */
+	       && !(TREE_CODE (value) == FUNCTION_DECL
+		    && DECL_ANTICIPATED (value)
+		    && !DECL_HIDDEN_FRIEND_P (value))
+	       && !decls_match (lookup.value, value))
+	diagnose_name_conflict (lookup.value, value);
       else
-	{
-	  /* If we're declaring a non-function and OLDVAL is an anticipated
-	     built-in, just pretend it isn't there.  */
-	  if (oldval
-	      && TREE_CODE (oldval) == FUNCTION_DECL
-	      && DECL_ANTICIPATED (oldval)
-	      && !DECL_HIDDEN_FRIEND_P (oldval))
-	    oldval = NULL_TREE;
-
-	  *newval = decls.value;
-	  if (oldval && !decls_match (*newval, oldval))
-	    error ("%qD is already declared in this scope", name);
-	}
+	value = lookup.value;
     }
-  else
-    *newval = oldval;
 
-  if (decls.type && TREE_CODE (decls.type) == TREE_LIST)
-    {
-      error ("reference to %qD is ambiguous", name);
-      print_candidates (decls.type);
-    }
-  else
+  if (lookup.type && lookup.type != type)
     {
-      *newtype = decls.type;
-      if (oldtype && *newtype && !decls_match (oldtype, *newtype))
-	error ("%qD is already declared in this scope", name);
-    }
-
-    /* If *newval is empty, shift any class or enumeration name down.  */
-    if (!*newval)
-      {
-	*newval = *newtype;
-	*newtype = NULL_TREE;
-      }
-}
-
-/* Process a using-declaration at function scope.  */
-
-void
-do_local_using_decl (tree decl, tree scope, tree name)
-{
-  tree oldval, oldtype, newval, newtype;
-  tree orig_decl = decl;
-
-  decl = validate_nonmember_using_decl (decl, scope, name);
-  if (decl == NULL_TREE)
-    return;
-
-  if (building_stmt_list_p ()
-      && at_function_scope_p ())
-    add_decl_expr (decl);
-
-  oldval = lookup_name_innermost_nonclass_level (name);
-  oldtype = lookup_type_current_level (name);
-
-  do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
-
-  if (newval)
-    {
-      if (is_overloaded_fn (newval))
-	{
-	  tree fn, term;
-
-	  /* We only need to push declarations for those functions
-	     that were not already bound in the current level.
-	     The old value might be NULL_TREE, it might be a single
-	     function, or an OVERLOAD.  */
-	  if (oldval && TREE_CODE (oldval) == OVERLOAD)
-	    term = OVL_FUNCTION (oldval);
-	  else
-	    term = oldval;
-	  for (fn = newval; fn && OVL_CURRENT (fn) != term;
-	       fn = OVL_NEXT (fn))
-	    push_overloaded_decl (OVL_CURRENT (fn),
-				  PUSH_LOCAL | PUSH_USING,
-				  false);
-	}
+      if (type && !decls_match (lookup.type, type))
+	diagnose_name_conflict (lookup.type, type);
       else
-	push_local_binding (name, newval, PUSH_USING);
+	type = lookup.type;
     }
-  if (newtype)
+
+  /* If bind->value is empty, shift any class or enumeration name back.  */
+  if (!value)
     {
-      push_local_binding (name, newtype, PUSH_USING);
-      set_identifier_type_value (name, newtype);
+      value = type;
+      type = NULL_TREE;
     }
 
-  /* Emit debug info.  */
-  if (!processing_template_decl)
-    cp_emit_debug_info_for_using (orig_decl, current_scope());
+  *value_p = value;
+  *type_p = type;
 }
 
 /* Returns true if ANCESTOR encloses DESCENDANT, including matching.
@@ -4337,35 +4299,86 @@ pushdecl_namespace_level (tree x, bool i
   return t;
 }
 
-/* Process a using-declaration not appearing in class or local scope.  */
+/* Process a using-declaration appearing in namespace scope.  */
 
 void
-do_toplevel_using_decl (tree decl, tree scope, tree name)
+finish_namespace_using_decl (tree decl, tree scope, tree name)
 {
-  tree oldval, oldtype, newval, newtype;
   tree orig_decl = decl;
-  cxx_binding *binding;
 
+  gcc_checking_assert (current_binding_level->kind == sk_namespace);
   decl = validate_nonmember_using_decl (decl, scope, name);
   if (decl == NULL_TREE)
     return;
 
-  binding = binding_for_name (NAMESPACE_LEVEL (current_namespace), name);
+  cxx_binding *binding
+    = binding_for_name (NAMESPACE_LEVEL (current_namespace), name);
+
+  tree value = binding->value;
+  tree type = binding->type;
 
-  oldval = binding->value;
-  oldtype = binding->type;
+  do_nonmember_using_decl (scope, name, &value, &type);
 
-  do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
+  /* Copy declarations found.  */
+  binding->value = value;
+  binding->type = type;
 
   /* Emit debug info.  */
+  gcc_assert (!processing_template_decl);
   if (!processing_template_decl)
     cp_emit_debug_info_for_using (orig_decl, current_namespace);
+}
 
-  /* Copy declarations found.  */
-  if (newval)
-    binding->value = newval;
-  if (newtype)
-    binding->type = newtype;
+/* Process a using-declaration at local scope.  */
+
+void
+finish_local_using_decl (tree decl, tree scope, tree name)
+{
+  tree orig_decl = decl;
+
+  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;
+
+  gcc_assert (building_stmt_list_p ());
+  if (building_stmt_list_p ()
+      && at_function_scope_p ())
+    add_decl_expr (decl);
+
+  cxx_binding *binding = find_local_binding (current_binding_level, name);
+  tree value = binding ? binding->value : NULL_TREE;
+  tree type = binding ? binding->type : NULL_TREE;
+
+  do_nonmember_using_decl (scope, name, &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.  */
+    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 ());
 }
 
 /* Combines two sets of overloaded functions into an OVERLOAD chain, removing
@@ -5651,38 +5664,6 @@ is_local_extern (tree decl)
   return false;
 }
 
-/* Like lookup_name_innermost_nonclass_level, but for types.  */
-
-static tree
-lookup_type_current_level (tree name)
-{
-  tree t = NULL_TREE;
-
-  timevar_start (TV_NAME_LOOKUP);
-  gcc_assert (current_binding_level->kind != sk_namespace);
-
-  if (REAL_IDENTIFIER_TYPE_VALUE (name) != NULL_TREE
-      && REAL_IDENTIFIER_TYPE_VALUE (name) != global_type_node)
-    {
-      cp_binding_level *b = current_binding_level;
-      while (1)
-	{
-	  if (purpose_member (name, b->type_shadowed))
-	    {
-	      t = REAL_IDENTIFIER_TYPE_VALUE (name);
-	      break;
-	    }
-	  if (b->kind == sk_cleanup)
-	    b = b->level_chain;
-	  else
-	    break;
-	}
-    }
-
-  timevar_stop (TV_NAME_LOOKUP);
-  return t;
-}
-
 /* 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.  */
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h	(revision 248338)
+++ gcc/cp/name-lookup.h	(working copy)
@@ -315,7 +315,6 @@ extern tree lookup_name_nonclass (tree);
 extern tree lookup_name_innermost_nonclass_level (tree);
 extern bool is_local_extern (tree);
 extern tree lookup_function_nonclass (tree, vec<tree, va_gc> *, bool);
-extern void push_local_binding (tree, tree, int);
 extern bool pushdecl_class_level (tree);
 extern tree pushdecl_namespace_level (tree, bool);
 extern bool push_class_level_binding (tree, tree);
@@ -326,8 +325,6 @@ extern void set_decl_namespace (tree, tr
 extern void push_decl_namespace (tree);
 extern void pop_decl_namespace (void);
 extern void do_namespace_alias (tree, tree);
-extern void do_toplevel_using_decl (tree, tree, tree);
-extern void do_local_using_decl (tree, tree, tree);
 extern tree do_class_using_decl (tree, tree);
 extern void do_using_directive (tree);
 extern cp_expr lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
@@ -336,6 +333,8 @@ extern tree innermost_non_namespace_valu
 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_namespace_using_directive (tree, tree);
 extern void finish_local_using_directive (tree, tree);
 extern tree pushdecl_outermost_localscope (tree);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 248338)
+++ gcc/cp/parser.c	(working copy)
@@ -18499,9 +18499,9 @@ cp_parser_using_declaration (cp_parser*
 	      return false;
 	    }
 	  else if (!at_namespace_scope_p ())
-	    do_local_using_decl (decl, qscope, identifier);
+	    finish_local_using_decl (decl, qscope, identifier);
 	  else
-	    do_toplevel_using_decl (decl, qscope, identifier);
+	    finish_namespace_using_decl (decl, qscope, identifier);
 	}
     }
 
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 248338)
+++ gcc/cp/pt.c	(working copy)
@@ -15696,7 +15696,7 @@ tsubst_expr (tree t, tree args, tsubst_f
 	    if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
 	      qualified_name_lookup_error (scope, name, decl, input_location);
 	    else
-	      do_local_using_decl (decl, scope, name);
+	      finish_local_using_decl (decl, scope, name);
 	  }
 	else if (DECL_PACK_P (decl))
 	  {
Index: libcc1/libcp1plugin.cc
===================================================================
--- libcc1/libcp1plugin.cc	(revision 248338)
+++ libcc1/libcp1plugin.cc	(working copy)
@@ -1030,13 +1030,12 @@ plugin_add_using_decl (cc1_plugin::conne
 
       finish_member_declaration (decl);
     }
-  else if (!at_namespace_scope_p ())
+  else
     {
-      gcc_unreachable ();
-      do_local_using_decl (target, tcontext, identifier);
+      /* We can't be at local scope.  */
+      gcc_assert (at_namespace_scope_p ());
+      finish_namespace_using_decl (target, tcontext, identifier);
     }
-  else
-    do_toplevel_using_decl (target, tcontext, identifier);
 
   return 1;
 }
Index: gcc/testsuite/g++.dg/lookup/using13.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using13.C	(revision 248338)
+++ gcc/testsuite/g++.dg/lookup/using13.C	(working copy)
@@ -8,5 +8,5 @@ namespace A { int a; }
 
 namespace C{
   int a;
-  using A::a;		// { dg-error "already declared" }
+  using A::a;		// { dg-error "conflicts with a previous" }
 }

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-05-21 15:30 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-21 14:32 [C++ PATCH] Using decls Nathan Sidwell
2019-05-21 14:44 ` Marek Polacek
2019-05-21 14:47   ` Nathan Sidwell
2019-05-21 15:30   ` Nathan Sidwell
  -- strict thread matches above, loose matches on Subject: below --
2017-05-23 11:07 [C++ PATCH] using decls Nathan Sidwell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).