public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] pushdecl
@ 2017-05-08 18:02 Nathan Sidwell
  0 siblings, 0 replies; 2+ messages in thread
From: Nathan Sidwell @ 2017-05-08 18:02 UTC (permalink / raw)
  To: GCC Patches

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

This small patch replaces pushdecl_with_scope with a more-specific 
pushdecl_outermost_localscope.  It's used in 2 places to inject an 
artifical decl into the outermost block scope of a function 
(__FUNCTION__ var and lambda capture proxies).

This moves some binding-level handling into name-lookup, where it belongs.

Applied to trunk.

nathan
-- 
Nathan Sidwell

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

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

	* name-lookup.h (pushdecl_with_scope): Replace with ...
	(pushdecl_outermost_localscope): ... this.
	* name-lookup.c (pushdecl_with_scope): Replace with ...
	(pushdecl_outermost_localscope): ... this.
	(pushdecl_namespace_level): Adjust.
	* decl.c (cp_make_fname_decl): Use pushdecl_outermost_localscope.
	* lambda.c (insert_capture_proxy): Likewise.

Index: decl.c
===================================================================
--- decl.c	(revision 247751)
+++ decl.c	(working copy)
@@ -4335,9 +4335,6 @@ cp_make_fname_decl (location_t loc, tree
   if (name)
     free (CONST_CAST (char *, name));
 
-  /* As we're using pushdecl_with_scope, we must set the context.  */
-  DECL_CONTEXT (decl) = current_function_decl;
-
   TREE_STATIC (decl) = 1;
   TREE_READONLY (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
@@ -4346,12 +4343,8 @@ cp_make_fname_decl (location_t loc, tree
 
   if (current_function_decl)
     {
-      cp_binding_level *b = current_binding_level;
-      if (b->kind == sk_function_parms)
-	return error_mark_node;
-      while (b->level_chain->kind != sk_function_parms)
-	b = b->level_chain;
-      pushdecl_with_scope (decl, b, /*is_friend=*/false);
+      DECL_CONTEXT (decl) = current_function_decl;
+      decl = pushdecl_outermost_localscope (decl);
       cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE,
 		      LOOKUP_ONLYCONVERTING);
     }
Index: lambda.c
===================================================================
--- lambda.c	(revision 247751)
+++ lambda.c	(working copy)
@@ -295,24 +295,13 @@ is_normal_capture_proxy (tree decl)
 void
 insert_capture_proxy (tree var)
 {
-  cp_binding_level *b;
-  tree stmt_list;
-
   /* Put the capture proxy in the extra body block so that it won't clash
      with a later local variable.  */
-  b = current_binding_level;
-  for (;;)
-    {
-      cp_binding_level *n = b->level_chain;
-      if (n->kind == sk_function_parms)
-	break;
-      b = n;
-    }
-  pushdecl_with_scope (var, b, false);
+  pushdecl_outermost_localscope (var);
 
   /* And put a DECL_EXPR in the STATEMENT_LIST for the same block.  */
   var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
-  stmt_list = (*stmt_list_stack)[1];
+  tree stmt_list = (*stmt_list_stack)[1];
   gcc_assert (stmt_list);
   append_to_statement_list_force (var, &stmt_list);
 }
Index: name-lookup.c
===================================================================
--- name-lookup.c	(revision 247751)
+++ name-lookup.c	(working copy)
@@ -2870,14 +2870,23 @@ pushdecl_with_scope_1 (tree x, cp_bindin
   return x;
 }
  
-/* Wrapper for pushdecl_with_scope_1.  */
+/* Inject X into the local scope just before the function parms.  */
 
 tree
-pushdecl_with_scope (tree x, cp_binding_level *level, bool is_friend)
+pushdecl_outermost_localscope (tree x)
 {
-  tree ret;
   bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
-  ret = pushdecl_with_scope_1 (x, level, is_friend);
+  cp_binding_level *b  = NULL, *n = current_binding_level;
+
+  if (n->kind == sk_function_parms)
+    return error_mark_node;
+  do
+    {
+      b = n;
+      n = b->level_chain;
+    }
+  while (n->kind != sk_function_parms);
+  tree ret = pushdecl_with_scope_1 (x, b, false);
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
   return ret;
 }
@@ -4350,7 +4359,8 @@ pushdecl_namespace_level (tree x, bool i
   tree t;
 
   bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
-  t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace), is_friend);
+  t = pushdecl_with_scope_1
+    (x, NAMESPACE_LEVEL (current_namespace), is_friend);
 
   /* Now, the type_shadowed stack may screw us.  Munge it so it does
      what we want.  */
Index: name-lookup.h
===================================================================
--- name-lookup.h	(revision 247751)
+++ name-lookup.h	(working copy)
@@ -300,6 +300,7 @@ extern tree push_inner_scope (tree);
 extern void pop_inner_scope (tree, tree);
 extern void push_binding_level (cp_binding_level *);
 \f
+extern tree pushdecl_outermost_localscope (tree);
 extern bool push_namespace (tree);
 extern void pop_namespace (void);
 extern void push_nested_namespace (tree);
@@ -307,7 +308,6 @@ extern void pop_nested_namespace (tree);
 extern bool handle_namespace_attrs (tree, tree);
 extern void pushlevel_class (void);
 extern void poplevel_class (void);
-extern tree pushdecl_with_scope (tree, cp_binding_level *, bool);
 extern tree lookup_name_prefer_type (tree, int);
 extern tree lookup_name_real (tree, int, int, bool, int, int);
 extern tree lookup_type_scope (tree, tag_scope);

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

* [C++ PATCH] pushdecl
@ 2017-05-23 22:04 Nathan Sidwell
  0 siblings, 0 replies; 2+ messages in thread
From: Nathan Sidwell @ 2017-05-23 22:04 UTC (permalink / raw)
  To: GCC Patches

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

This patch reimplements the innards of pushdecl, which deals with local 
and namespace scope pushing.

I managed to collapse or remove a lot of special casing, which I think 
greatly improves the readability of this piece of code.  We're still not 
onto the performance improvements though.

nathan
-- 
Nathan Sidwell

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

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

	* cp-tree.h (PUSH_GLOBAL, PUSH_LOCAL, PUSH_USING): Delete.
	* name-lookup.c (create_local_binding): New.
	(update_binding): New.
	(pushdecl_maybe_friend_1): Rename to ...
	(do_pushdecl): ... this.  Reimplement.
	(pushdecl): Adjust.
	(push_overloaded_decl_1, push_overloaded_decl): Delete.

Index: cp-tree.h
===================================================================
--- cp-tree.h	(revision 248377)
+++ cp-tree.h	(working copy)
@@ -5312,14 +5312,6 @@ enum overload_flags { NO_SPECIAL = 0, DT
 				   will be identical to
 				   COMPARE_STRICT.  */
 
-/* Used with push_overloaded_decl.  */
-#define PUSH_GLOBAL	     0  /* Push the DECL into namespace scope,
-				   regardless of the current scope.  */
-#define PUSH_LOCAL	     1  /* Push the DECL into the current
-				   scope.  */
-#define PUSH_USING	     2  /* We are pushing this DECL as the
-				   result of a using declaration.  */
-
 /* Used with start function.  */
 #define SF_DEFAULT	     0  /* No flags.  */
 #define SF_PRE_PARSED	     1  /* The function declaration has
Index: name-lookup.c
===================================================================
--- name-lookup.c	(revision 248382)
+++ name-lookup.c	(working copy)
@@ -48,7 +48,6 @@ struct scope_binding {
 };
 #define EMPTY_SCOPE_BINDING { NULL_TREE, NULL_TREE }
 
-static tree push_overloaded_decl (tree, int, bool);
 static bool lookup_using_namespace (tree, struct scope_binding *, tree,
 				    tree, int);
 static bool qualified_lookup_using_namespace (tree, tree,
@@ -61,6 +60,23 @@ static void consider_binding_level (tree
 static tree push_using_directive (tree);
 static void diagnose_name_conflict (tree, tree);
 
+/* Create a local binding level for NAME.  */
+
+static cxx_binding *
+create_local_binding (cp_binding_level *level, tree name)
+{
+  cxx_binding *binding = cxx_binding_make (NULL, NULL);
+
+  INHERITED_VALUE_BINDING_P (binding) = false;
+  LOCAL_BINDING_P (binding) = true;
+  binding->scope = level;
+  binding->previous = IDENTIFIER_BINDING (name);
+
+  IDENTIFIER_BINDING (name) = binding;
+  
+  return binding;
+}
+
 /* Find the binding for NAME in namespace NS.  If CREATE_P is true,
    make an empty binding if there wasn't one.  */
 
@@ -1281,6 +1297,173 @@ matching_fn_p (tree one, tree two)
   return true;
 }
 
+/* Push DECL into nonclass LEVEL BINDING.  OLD is the current
+   binding value (possibly with anticipated builtins stripped).
+   Diagnose conflicts and return updated decl.  */
+
+static tree
+update_binding (cp_binding_level *level, cxx_binding *binding,
+		tree old, tree decl, bool is_friend)
+{
+  tree to_val = decl;
+  tree to_type = NULL_TREE;
+
+  gcc_assert (level->kind != sk_class);
+  if (old == error_mark_node)
+    old = NULL_TREE;
+
+  if (old && TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
+    {
+      /* Slide the tdef out of the way.  We'll undo this below, if
+	 we're pushing a matching tdef.  */
+      to_type = old;
+      old = NULL_TREE;
+    }
+
+  if (DECL_DECLARES_FUNCTION_P (decl))
+    {
+      if (!old)
+	;
+      else if (OVL_P (old))
+	{
+	  for (ovl_iterator iter (old); iter; ++iter)
+	    {
+	      tree fn = *iter;
+
+	      if (iter.using_p () && matching_fn_p (fn, decl))
+		{
+		  /* If a function declaration in namespace scope or
+		     block scope has the same name and the same
+		     parameter-type- list (8.3.5) as a function
+		     introduced by a using-declaration, and the
+		     declarations do not declare the same function,
+		     the program is ill-formed.  [namespace.udecl]/14 */
+		  if (tree match = duplicate_decls (decl, fn, is_friend))
+		    return match;
+		  else
+		    /* FIXME: To preserve existing error behavior, we
+		       still push the decl.  This might change.  */
+		    diagnose_name_conflict (decl, fn);
+		}
+	    }
+	}
+      else
+	goto conflict;
+
+      to_val = ovl_insert (decl, old);
+    }
+  else if (to_type && TREE_CODE (decl) == TYPE_DECL)
+    {
+      /* We thought we wanted to slide an artificial typedef out of
+	 the way, to make way for another typedef.  That's not always
+	 what we want to do.  */
+      if (!DECL_ARTIFICIAL (decl))
+	; /* Slide.  */
+      else if (same_type_p (TREE_TYPE (to_type), TREE_TYPE (decl)))
+	/* Two artificial decls to same type.  Do nothing.  */
+	return to_type;
+      else
+	goto conflict;
+    }
+  else if (!old)
+    ;
+  else if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
+    {
+      /* Slide DECL into the type slot.  */
+      to_type = decl;
+      to_val = old;
+    }
+  else if (TREE_CODE (old) != TREE_CODE (decl))
+    /* Different kinds of decls conflict.  */
+    goto conflict;
+  else if (TREE_CODE (old) == TYPE_DECL)
+    {
+      if (DECL_ARTIFICIAL (decl))
+	{
+	  /* Slide DECL into the type slot instead.  */
+	  to_type = decl;
+	  to_val = old;
+	}
+      else if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl)))
+	/* Two type decls to the same type.  Do nothing.  */
+	return old;
+      else
+	goto conflict;
+    }
+  else if (TREE_CODE (old) == NAMESPACE_DECL)
+    {
+      if (DECL_NAMESPACE_ALIAS (old) && DECL_NAMESPACE_ALIAS (decl)
+	  && ORIGINAL_NAMESPACE (old) == ORIGINAL_NAMESPACE (decl))
+	/* In a declarative region, a namespace-alias-definition can be
+	   used to redefine a namespace-alias declared in that declarative
+	   region to refer only to the namespace to which it already
+	   refers.  [namespace.alias] */
+	return old;
+      else
+	goto conflict;
+    }
+  else if (TREE_CODE (old) == VAR_DECL)
+    {
+      /* There can be two block-scope declarations of the same
+	 variable, so long as they are `extern' declarations.  */
+      if (!DECL_EXTERNAL (old) || !DECL_EXTERNAL (decl))
+	goto conflict;
+      else if (tree match = duplicate_decls (decl, old, false))
+	return match;
+      else
+	goto conflict;
+    }
+  else
+    {
+    conflict:
+      diagnose_name_conflict (decl, old);
+      to_val = NULL_TREE;
+    }
+
+  if (to_val)
+    {
+      if (level->kind != sk_namespace
+	  && !to_type && binding->value && OVL_P (to_val))
+	update_local_overload (binding, to_val);
+      else
+	{
+	  tree to_add = to_val;
+      
+	  if (level->kind == sk_namespace)
+	    to_add = decl;
+	  else if (to_type == decl)
+	    to_add = decl;
+	  else if (TREE_CODE (to_add) == OVERLOAD)
+	    to_add = build_tree_list (NULL_TREE, to_add);
+
+	  add_decl_to_level (level, to_add);
+	}
+
+      if (to_type == binding->type)
+	to_type = NULL_TREE;
+
+      if (to_type)
+	{
+	  gcc_checking_assert (TREE_CODE (to_type) == TYPE_DECL
+			       && DECL_ARTIFICIAL (to_type));
+
+	  tree type = TREE_TYPE (to_type);
+	  if (to_type != decl
+	      && MAYBE_CLASS_TYPE_P (type) && warn_shadow
+	      && (!DECL_IN_SYSTEM_HEADER (decl)
+		  || !DECL_IN_SYSTEM_HEADER (to_type)))
+	    warning (OPT_Wshadow, "%q#D hides constructor for %q#T",
+		     decl, type);
+	}
+
+      if (to_type)
+	binding->type = to_type;
+      binding->value = to_val;
+    }
+
+  return decl;
+}
+
 /* Map of identifiers to extern C functions (or LISTS thereof).  */
 
 static GTY(()) hash_map<lang_identifier *, tree> *extern_c_fns;
@@ -1690,338 +1873,146 @@ set_local_extern_decl_linkage (tree decl
     }
 }
 
-/* Record a decl-node X as belonging to the current lexical scope.
-   Check for errors (such as an incompatible declaration for the same
-   name already seen in the same scope).  IS_FRIEND is true if X is
+/* Record DECL as belonging to the current lexical scope.  Check for
+   errors (such as an incompatible declaration for the same name
+   already seen in the same scope).  IS_FRIEND is true if DECL is
    declared as a friend.
 
-   Returns either X or an old decl for the same name.
-   If an old decl is returned, it may have been smashed
-   to agree with what X says.  */
+   Returns either DECL or an old decl for the same name.  If an old
+   decl is returned, it may have been smashed to agree with what DECL
+   says.  */
 
 static tree
-pushdecl_maybe_friend_1 (tree x, bool is_friend)
+do_pushdecl (tree decl, bool is_friend)
 {
-  tree t;
-  tree name;
-  int need_new_binding;
-
-  if (x == error_mark_node)
+  if (decl == error_mark_node)
     return error_mark_node;
 
-  need_new_binding = 1;
-
-  if (!DECL_TEMPLATE_PARM_P (x) && current_function_decl)
-    set_decl_context_in_fn (current_function_decl, x);
+  if (!DECL_TEMPLATE_PARM_P (decl) && current_function_decl)
+    set_decl_context_in_fn (current_function_decl, decl);
 
-  name = DECL_NAME (x);
-  if (name)
-    {
-      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
-	name = TREE_OPERAND (name, 0);
-
-      /* In case this decl was explicitly namespace-qualified, look it
-	 up in its namespace context.  */
-      if (DECL_NAMESPACE_SCOPE_P (x) && namespace_bindings_p ())
-	t = get_namespace_binding (CP_DECL_CONTEXT (x), name);
+  /* The binding level we will be pushing into.  During local class
+     pushing, we want to push to the containing scope.  */
+  cp_binding_level *level = current_binding_level;
+  while (level->kind == sk_class)
+    level = level->level_chain;
+
+  if (tree name = DECL_NAME (decl))
+    {
+      cxx_binding *binding = NULL;
+      tree ns = NULL_TREE; /* Searched namespace.  */
+      tree old = NULL_TREE;
+
+      if (level->kind == sk_namespace)
+	{
+	  /* We look in the decl's namespace for an existing
+	     declaration, even though we push into the current
+	     namespace.  */
+	  ns = (DECL_NAMESPACE_SCOPE_P (decl)
+		? CP_DECL_CONTEXT (decl) : current_namespace);
+	  /* Create the binding, if this is current namespace, because
+	     that's where we'll be pushing anyway.  */
+	  binding = find_namespace_binding (ns, name, ns == current_namespace);
+	}
       else
-	t = lookup_name_innermost_nonclass_level (name);
-
-      if (current_function_decl && VAR_OR_FUNCTION_DECL_P (x)
-	  && DECL_EXTERNAL (x))
-	set_local_extern_decl_linkage (x, t != NULL_TREE);
-
-      /* If we are declaring a function, and the result of name-lookup
-	 was an OVERLOAD, look for an overloaded instance that is
-	 actually the same as the function we are declaring.  (If
-	 there is one, we have to merge our declaration with the
-	 previous declaration.)  */
-      if (t && TREE_CODE (t) == OVERLOAD)
-	{
-	  tree match;
-
-	  if (TREE_CODE (x) == FUNCTION_DECL)
-	    for (match = t; match; match = OVL_NEXT (match))
-	      {
-		if (decls_match (OVL_CURRENT (match), x))
-		  break;
-	      }
-	  else
-	    /* Just choose one.  */
-	    match = t;
+	binding = find_local_binding (level, name);
 
-	  if (match)
-	    t = OVL_CURRENT (match);
-	  else
-	    t = NULL_TREE;
-	}
+      if (binding)
+	old = binding->value;
 
-      if (t && t != error_mark_node)
-	{
-	  if (TREE_CODE (t) == PARM_DECL)
-	    {
-	      /* Check for duplicate params.  */
-	      tree d = duplicate_decls (x, t, is_friend);
-	      if (d)
-		return d;
-	    }
-	  else if ((DECL_EXTERN_C_FUNCTION_P (x)
-		    || DECL_FUNCTION_TEMPLATE_P (x))
-		   && is_overloaded_fn (t))
-	    /* Don't do anything just yet.  */;
-	  else if (t == wchar_decl_node)
-	    {
-	      if (! DECL_IN_SYSTEM_HEADER (x))
-		pedwarn (input_location, OPT_Wpedantic, "redeclaration of %<wchar_t%> as %qT",
-			 TREE_TYPE (x));
-	      
-	      /* Throw away the redeclaration.  */
-	      return t;
-	    }
-	  else
-	    {
-	      tree olddecl = duplicate_decls (x, t, is_friend);
+      if (current_function_decl && VAR_OR_FUNCTION_DECL_P (decl)
+	  && DECL_EXTERNAL (decl))
+	set_local_extern_decl_linkage (decl, old != NULL_TREE);
 
-	      /* If the redeclaration failed, we can stop at this
-		 point.  */
-	      if (olddecl == error_mark_node)
-		return error_mark_node;
+      if (old == error_mark_node)
+	old = NULL_TREE;
 
-	      if (olddecl)
-		{
-		  if (TREE_CODE (t) == TYPE_DECL)
-		    SET_IDENTIFIER_TYPE_VALUE (name, TREE_TYPE (t));
+      for (ovl_iterator iter (old); iter; ++iter)
+	if (iter.using_p ())
+	  ; /* Ignore using decls here.  */
+	else if (tree match = duplicate_decls (decl, *iter, is_friend))
+	  return match;
+
+      /* We are pushing a new decl.  */
+
+      /* Skip a hidden builtin we failed to match already.  */
+      if (old && TREE_CODE (old) == FUNCTION_DECL
+	  && DECL_ANTICIPATED (old)
+	  && !DECL_HIDDEN_FRIEND_P (old))
+	old = NULL_TREE;
 
-		  return t;
-		}
-	      else if (DECL_MAIN_P (x) && TREE_CODE (t) == FUNCTION_DECL)
-		{
-		  /* A redeclaration of main, but not a duplicate of the
-		     previous one.
+      check_template_shadow (decl);
 
-		     [basic.start.main]
+      if (DECL_DECLARES_FUNCTION_P (decl))
+	{
+	  check_default_args (decl);
 
-		     This function shall not be overloaded.  */
-		  error ("invalid redeclaration of %q+D", t);
-		  error ("as %qD", x);
-		  /* We don't try to push this declaration since that
-		     causes a crash.  */
-		  return x;
-		}
+	  if (is_friend)
+	    {
+	      if (level->kind != sk_namespace)
+		/* In a local class, a friend function declaration must
+		   find a matching decl in the innermost non-class scope.
+		   [class.friend/11] */
+		error ("friend declaration %qD in local class without "
+		       "prior local declaration", decl);
+	      else if (!flag_friend_injection)
+		/* Hide it from ordinary lookup.  */
+		DECL_ANTICIPATED (decl) = DECL_HIDDEN_FRIEND_P (decl) = true;
 	    }
 	}
 
-      check_template_shadow (x);
-
-      /* If this is a function conjured up by the back end, massage it
-	 so it looks friendly.  */
-      if (DECL_NON_THUNK_FUNCTION_P (x) && ! DECL_LANG_SPECIFIC (x))
+      if (level->kind != sk_namespace)
 	{
-	  retrofit_lang_decl (x);
-	  SET_DECL_LANGUAGE (x, lang_c);
-	}
+	  check_local_shadow (decl);
 
-      t = x;
-      if (DECL_NON_THUNK_FUNCTION_P (x) && ! DECL_FUNCTION_MEMBER_P (x))
-	{
-	  t = push_overloaded_decl (x, PUSH_LOCAL, is_friend);
-	  if (!namespace_bindings_p ())
-	    /* We do not need to create a binding for this name;
-	       push_overloaded_decl will have already done so if
-	       necessary.  */
-	    need_new_binding = 0;
+	  if (TREE_CODE (decl) == NAMESPACE_DECL)
+	    /* A local namespace alias.  */
+	    set_identifier_type_value (name, NULL_TREE);
+
+	  if (!binding)
+	    binding = create_local_binding (level, name);
 	}
-      else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
+      else if (!binding)
 	{
-	  t = push_overloaded_decl (x, PUSH_GLOBAL, is_friend);
-	  if (t == x)
-	    add_decl_to_level (NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)), x);
+	  ns = current_namespace;
+	  binding = find_namespace_binding (ns, name, true);
 	}
 
-      if (DECL_DECLARES_FUNCTION_P (t))
+      old = update_binding (level, binding, old, decl, is_friend);
+
+      if (old != decl)
+	/* An existing decl matched, use it.  */
+	decl = old;
+      else if (TREE_CODE (decl) == TYPE_DECL)
 	{
-	  check_default_args (t);
+	  tree type = TREE_TYPE (decl);
 
-	  if (is_friend && t == x && !flag_friend_injection)
+	  if (type != error_mark_node)
 	    {
-	      /* This is a new friend declaration of a function or a
-		 function template, so hide it from ordinary function
-		 lookup.  */
-	      DECL_ANTICIPATED (t) = 1;
-	      DECL_HIDDEN_FRIEND_P (t) = 1;
-	    }
-	}
-
-      if (t != x || DECL_FUNCTION_TEMPLATE_P (t))
-	return t;
+	      if (TYPE_NAME (type) != decl)
+		set_underlying_type (decl);
 
-      /* If declaring a type as a typedef, copy the type (unless we're
-	 at line 0), and install this TYPE_DECL as the new type's typedef
-	 name.  See the extensive comment of set_underlying_type ().  */
-      if (TREE_CODE (x) == TYPE_DECL)
-	{
-	  tree type = TREE_TYPE (x);
-
-	  if (DECL_IS_BUILTIN (x)
-	      || (TREE_TYPE (x) != error_mark_node
-		  && TYPE_NAME (type) != x
-		  /* We don't want to copy the type when all we're
-		     doing is making a TYPE_DECL for the purposes of
-		     inlining.  */
-		  && (!TYPE_NAME (type)
-		      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
-	    set_underlying_type (x);
-
-	  if (type != error_mark_node
-	      && TYPE_IDENTIFIER (type))
-	    set_identifier_type_value (DECL_NAME (x), x);
+	      if (!ns)
+		set_identifier_type_value_with_scope (name, decl, level);
+	      else
+		SET_IDENTIFIER_TYPE_VALUE (name, global_type_node);
+	    }
 
 	  /* If this is a locally defined typedef in a function that
 	     is not a template instantation, record it to implement
 	     -Wunused-local-typedefs.  */
 	  if (!instantiating_current_function_p ())
-	    record_locally_defined_typedef (x);
-	}
-
-      /* Multiple external decls of the same identifier ought to match.
-
-	 We get warnings about inline functions where they are defined.
-	 We get warnings about other functions from push_overloaded_decl.
-
-	 Avoid duplicate warnings where they are used.  */
-      if (TREE_PUBLIC (x) && TREE_CODE (x) != FUNCTION_DECL)
-	{
-	  tree decl;
-
-	  decl = get_namespace_binding (current_namespace, name);
-	  if (decl && TREE_CODE (decl) == OVERLOAD)
-	    decl = OVL_FUNCTION (decl);
-
-	  if (decl && decl != error_mark_node
-	      && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl))
-	      /* If different sort of thing, we already gave an error.  */
-	      && TREE_CODE (decl) == TREE_CODE (x)
-	      && !comptypes (TREE_TYPE (x), TREE_TYPE (decl),
-			     COMPARE_REDECLARATION))
-	    {
-	      if (permerror (input_location, "type mismatch with previous "
-			     "external decl of %q#D", x))
-		inform (DECL_SOURCE_LOCATION (decl),
-			"previous external decl of %q#D", decl);
-	    }
+	    record_locally_defined_typedef (decl);
 	}
+      else if (VAR_P (decl))
+	maybe_register_incomplete_var (decl);
+      else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_EXTERN_C_P (decl))
+	check_extern_c_conflict (decl);
+    }
+  else
+    add_decl_to_level (level, decl);
 
-      /* This name is new in its binding level.
-	 Install the new declaration and return it.  */
-      if (namespace_bindings_p ())
-	{
-	  /* Install a global value.  */
-
-	  /* If the first global decl has external linkage,
-	     warn if we later see static one.  */
-	  if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x))
-	    TREE_PUBLIC (name) = 1;
-
-	  /* Bind the name for the entity.  */
-	  if (!(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)
-		&& t != NULL_TREE)
-	      && (TREE_CODE (x) == TYPE_DECL
-		  || VAR_P (x)
-		  || TREE_CODE (x) == NAMESPACE_DECL
-		  || TREE_CODE (x) == CONST_DECL
-		  || TREE_CODE (x) == TEMPLATE_DECL))
-	    set_namespace_binding (current_namespace, name, x);
-
-	  /* If new decl is `static' and an `extern' was seen previously,
-	     warn about it.  */
-	  if (x != NULL_TREE && t != NULL_TREE && decls_match (x, t))
-	    warn_extern_redeclared_static (x, t);
-	}
-      else
-	{
-	  /* Here to install a non-global value.  */
-	  tree oldglobal = get_namespace_binding (current_namespace, name);
-	  tree oldlocal = NULL_TREE;
-	  cxx_binding *oldbinding = outer_binding (name, NULL, true);
-	  if (oldbinding)
-	    oldlocal = oldbinding->value;
-
-	  check_local_shadow (x);
-
-	  if (need_new_binding)
-	    {
-	      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.  */
-	      need_new_binding = 0;
-	    }
-
-	  /* If this is a TYPE_DECL, push it into the type value slot.  */
-	  if (TREE_CODE (x) == TYPE_DECL)
-	    set_identifier_type_value (name, x);
-
-	  /* Clear out any TYPE_DECL shadowed by a namespace so that
-	     we won't think this is a type.  The C struct hack doesn't
-	     go through namespaces.  */
-	  if (TREE_CODE (x) == NAMESPACE_DECL)
-	    set_identifier_type_value (name, NULL_TREE);
-
-	  if (oldlocal)
-	    {
-	      tree d = oldlocal;
-
-	      while (oldlocal
-		     && VAR_P (oldlocal)
-		     && DECL_DEAD_FOR_LOCAL (oldlocal))
-		oldlocal = DECL_SHADOWED_FOR_VAR (oldlocal);
-
-	      if (oldlocal == NULL_TREE)
-		oldlocal
-		  = get_namespace_binding (current_namespace, DECL_NAME (d));
-	    }
-
-	  /* If this is an extern function declaration, see if we
-	     have a global definition or declaration for the function.  */
-	  if (oldlocal == NULL_TREE
-	      && DECL_EXTERNAL (x)
-	      && oldglobal != NULL_TREE
-	      && TREE_CODE (x) == FUNCTION_DECL
-	      && TREE_CODE (oldglobal) == FUNCTION_DECL)
-	    {
-	      /* We have one.  Their types must agree.  */
-	      if (decls_match (x, oldglobal))
-		/* OK */;
-	      else
-		{
-		  warning (0, "extern declaration of %q#D doesn%'t match", x);
-		  warning_at (DECL_SOURCE_LOCATION (oldglobal), 0,
-			      "global declaration %q#D", oldglobal);
-		}
-	    }
-	  /* If we have a local external declaration,
-	     and no file-scope declaration has yet been seen,
-	     then if we later have a file-scope decl it must not be static.  */
-	  if (oldlocal == NULL_TREE
-	      && oldglobal == NULL_TREE
-	      && DECL_EXTERNAL (x)
-	      && TREE_PUBLIC (x))
-	    TREE_PUBLIC (name) = 1;
-	}
-
-      if (VAR_P (x))
-	maybe_register_incomplete_var (x);
-      if (TREE_CODE (x) == FUNCTION_DECL && DECL_EXTERN_C_P (x))
-	/* We need to check and register the fn now.  */
-	check_extern_c_conflict (x);
-    }
-
-  if (need_new_binding)
-    add_decl_to_level (DECL_NAMESPACE_SCOPE_P (x)
-		       ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
-		       : current_binding_level, x);
-
-  return x;
+  return decl;
 }
 
 /* Record a decl-node X as belonging to the current lexical scope.
@@ -2032,7 +2023,7 @@ pushdecl (tree x, bool is_friend)
 {
   tree ret;
   bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
-  ret = pushdecl_maybe_friend_1 (x, is_friend);
+  ret = do_pushdecl (x, is_friend);
   timevar_cond_stop (TV_NAME_LOOKUP, subtime);
   return ret;
 }
@@ -2924,151 +2915,6 @@ pushdecl_outermost_localscope (tree x)
   return ret;
 }
 
-/* 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
-   want to be referenced by that name.  It is then up to the users of
-   that name to decide what to do with that list.
-
-   DECL may also be a TEMPLATE_DECL, with a FUNCTION_DECL in its
-   DECL_TEMPLATE_RESULT.  It is dealt with the same way.
-
-   FLAGS is a bitwise-or of the following values:
-     PUSH_LOCAL: Bind DECL in the current scope, rather than at
-		 namespace scope.
-     PUSH_USING: DECL is being pushed as the result of a using
-		 declaration.
-
-   IS_FRIEND is true if this is a friend declaration.
-
-   The value returned may be a previous declaration if we guessed wrong
-   about what language DECL should belong to (C or C++).  Otherwise,
-   it's always DECL (and never something that's not a _DECL).  */
-
-static tree
-push_overloaded_decl_1 (tree decl, int flags, bool is_friend)
-{
-  tree name = DECL_NAME (decl);
-  tree old;
-  tree new_binding;
-  int doing_global = (namespace_bindings_p () || !(flags & PUSH_LOCAL));
-
-  if (doing_global)
-    old = get_namespace_binding (CP_DECL_CONTEXT (decl), name);
-  else
-    old = lookup_name_innermost_nonclass_level (name);
-
-  if (old)
-    {
-      if (TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
-	{
-	  tree t = TREE_TYPE (old);
-	  if (MAYBE_CLASS_TYPE_P (t) && warn_shadow
-	      && (! DECL_IN_SYSTEM_HEADER (decl)
-		  || ! DECL_IN_SYSTEM_HEADER (old)))
-	    warning (OPT_Wshadow, "%q#D hides constructor for %q#T", decl, t);
-	  old = NULL_TREE;
-	}
-      else if (is_overloaded_fn (old))
-	{
-	  tree tmp;
-
-	  for (tmp = old; tmp; tmp = OVL_NEXT (tmp))
-	    {
-	      tree fn = OVL_CURRENT (tmp);
-	      tree dup;
-
-	      if (TREE_CODE (tmp) == OVERLOAD && OVL_USING_P (tmp)
-		  && !(flags & PUSH_USING)
-		  && matching_fn_p (fn, decl)
-		  && ! decls_match (fn, decl))
-		diagnose_name_conflict (decl, fn);
-
-	      dup = duplicate_decls (decl, fn, is_friend);
-	      /* If DECL was a redeclaration of FN -- even an invalid
-		 one -- pass that information along to our caller.  */
-	      if (dup == fn || dup == error_mark_node)
-		return dup;
-	    }
-
-	  /* We don't overload implicit built-ins.  duplicate_decls()
-	     may fail to merge the decls if the new decl is e.g. a
-	     template function.  */
-	  if (TREE_CODE (old) == FUNCTION_DECL
-	      && DECL_ANTICIPATED (old)
-	      && !DECL_HIDDEN_FRIEND_P (old))
-	    old = NULL;
-	}
-      else if (old == error_mark_node)
-	/* Ignore the undefined symbol marker.  */
-	old = NULL_TREE;
-      else
-	{
-	  error ("previous non-function declaration %q+#D", old);
-	  error ("conflicts with function declaration %q#D", decl);
-	  return decl;
-	}
-    }
-
-  new_binding = ovl_insert (decl, old, flags & PUSH_USING);
-
-  if (doing_global)
-    set_namespace_binding (current_namespace, name, new_binding);
-  else
-    {
-      /* We only create an OVERLOAD if there was a previous binding at
-	 this level, or if decl is a template. In the former case, we
-	 need to remove the old binding and replace it with the new
-	 binding.  We must also run through the NAMES on the binding
-	 level where the name was bound to update the chain.  */
-
-      if (TREE_CODE (new_binding) == OVERLOAD && old)
-	{
-	  tree *d;
-
-	  for (d = &IDENTIFIER_BINDING (name)->scope->names;
-	       *d;
-	       d = &TREE_CHAIN (*d))
-	    if (*d == old
-		|| (TREE_CODE (*d) == TREE_LIST
-		    && TREE_VALUE (*d) == old))
-	      {
-		if (TREE_CODE (*d) == TREE_LIST)
-		  /* Just replace the old binding with the new.  */
-		  TREE_VALUE (*d) = new_binding;
-		else
-		  /* Build a TREE_LIST to wrap the OVERLOAD.  */
-		  *d = tree_cons (NULL_TREE, new_binding,
-				  TREE_CHAIN (*d));
-
-		/* And update the cxx_binding node.  */
-		IDENTIFIER_BINDING (name)->value = new_binding;
-		return decl;
-	      }
-
-	  /* We should always find a previous binding in this case.  */
-	  gcc_unreachable ();
-	}
-
-      /* Install the new binding.  */
-      push_local_binding (name, new_binding, flags);
-    }
-
-  return decl;
-}
-
-/* Wrapper for push_overloaded_decl_1.  */
-
-static tree
-push_overloaded_decl (tree decl, int flags, bool is_friend)
-{
-  tree ret;
-  bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
-  ret = push_overloaded_decl_1 (decl, flags, is_friend);
-  timevar_cond_stop (TV_NAME_LOOKUP, subtime);
-  return ret;
-}
-
 /* Check a non-member using-declaration. Return the name and scope
    being used, and the USING_DECL, or NULL_TREE on failure.  */
 

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

end of thread, other threads:[~2017-05-23 21:17 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-08 18:02 [C++ PATCH] pushdecl Nathan Sidwell
2017-05-23 22:04 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).