[C++ PATCH] Avoid sharing DECL_UID between different decls (was Re: checked in patch for PR 27793)

Jakub Jelinek jakub@redhat.com
Fri Jun 9 19:05:00 GMT 2006


On Wed, Jun 07, 2006 at 09:20:25PM -0400, Andrew MacLeod wrote:
> On Tue, 2006-06-06 at 23:11 -0400, Andrew MacLeod wrote:
> > I checked the following patch in the 4.1 branch. bootstrapped and no new
> > regressions on i686-pc-linux-gnu.
> > 
> > 4.2 to follow later.
> 
> Mainline patch attached and checked in.  Again, bootstrapped and no new
> regressions on i686-pc-linux-gnu. 
> 
> Its almost the same, just juggled around where things are done slightly
> to match mainline changes for 26757.

Here is a patch that avoids sharing DECL_UID between different decls,
by remapping them during genericization.
As only local externs are handled this way, there is no need to mess up
with DECL_UIDs at all, as only one of the decls will be seen by cgraph.

I have bootstrapped/regtested this on the trunk on i686-linux after
reverting revision 114480 (i.e. Andrew's PR middle-end/27793 workaround).

The cxx_int_tree_map* was introduced to avoid including tree-flow.h
in cp-tree.h and therefore the whole cp frontend (and the 2 functions
are really short).

Ok for trunk?

2006-06-09  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/27793
	* cp-tree.h (cxx_int_tree_map): New struct.
	(struct language_function): Add extern_decl_map field.
	* name-lookup.c (pushdecl_maybe_friend): Add x -> t mapping
	to cp_function_chain->extern_decl_map hash table instead of
	copying over DECL_UID.
	* cp-gimplify.c (cxx_int_tree_map_eq, cxx_int_tree_map_hash): New
	functions.
	(cp_genericize_r): Remap DECL_EXTERN local decls using
	cp_function_chain->extern_decl_map hash table.
	* decl.c (finish_function): Clear extern_decl_map.

--- gcc/cp/name-lookup.c.jj	2006-06-07 13:28:43.000000000 +0200
+++ gcc/cp/name-lookup.c	2006-06-09 14:36:33.000000000 +0200
@@ -670,14 +670,28 @@ pushdecl_maybe_friend (tree x, bool is_f
 	      if (decls_match (x, t))
 		/* The standard only says that the local extern
 		   inherits linkage from the previous decl; in
-		   particular, default args are not shared.  We must
-		   also tell cgraph to treat these decls as the same,
-		   or we may neglect to emit an "unused" static - we
-		   do this by making the DECL_UIDs equal, which should
-		   be viewed as a kludge.  FIXME.  */
+		   particular, default args are not shared.  Add
+		   the decl into a hash table to make sure only
+		   the previous decl in this case is seen by the
+		   middle end.  */
 		{
+		  struct cxx_int_tree_map *h;
+		  void **loc;
+
 		  TREE_PUBLIC (x) = TREE_PUBLIC (t);
-		  DECL_UID (x) = DECL_UID (t);
+
+		  if (cp_function_chain->extern_decl_map == NULL)
+		    cp_function_chain->extern_decl_map
+		      = htab_create_ggc (20, cxx_int_tree_map_hash,
+					 cxx_int_tree_map_eq, NULL);
+
+		  h = GGC_NEW (struct cxx_int_tree_map);
+		  h->uid = DECL_UID (x);
+		  h->to = t;
+		  loc = htab_find_slot_with_hash
+			  (cp_function_chain->extern_decl_map, h,
+			   h->uid, INSERT);
+		  *(struct cxx_int_tree_map **) loc = h;
 		}
 	    }
 	  else if (TREE_CODE (t) == PARM_DECL)
--- gcc/cp/cp-gimplify.c.jj	2006-06-07 13:28:43.000000000 +0200
+++ gcc/cp/cp-gimplify.c	2006-06-09 14:34:34.000000000 +0200
@@ -601,6 +601,24 @@ is_invisiref_parm (tree t)
 	  && DECL_BY_REFERENCE (t));
 }
 
+/* Return true if the uid in both int tree maps are equal.  */
+
+int
+cxx_int_tree_map_eq (const void *va, const void *vb)
+{
+  const struct cxx_int_tree_map *a = (const struct cxx_int_tree_map *) va;
+  const struct cxx_int_tree_map *b = (const struct cxx_int_tree_map *) vb;
+  return (a->uid == b->uid);
+}
+
+/* Hash a UID in a cxx_int_tree_map.  */
+
+unsigned int
+cxx_int_tree_map_hash (const void *item)
+{
+  return ((const struct cxx_int_tree_map *)item)->uid;
+}
+
 /* Perform any pre-gimplification lowering of C++ front end trees to
    GENERIC.  */
 
@@ -620,6 +638,25 @@ cp_genericize_r (tree *stmt_p, int *walk
       return NULL;
     }
 
+  /* Map block scope extern declarations to visible declarations with the
+     same name and type in outer scopes if any.  */
+  if (cp_function_chain->extern_decl_map
+      && (TREE_CODE (stmt) == FUNCTION_DECL || TREE_CODE (stmt) == VAR_DECL)
+      && DECL_EXTERNAL (stmt))
+    {
+      struct cxx_int_tree_map *h, in;
+      in.uid = DECL_UID (stmt);
+      h = (struct cxx_int_tree_map *)
+	  htab_find_with_hash (cp_function_chain->extern_decl_map,
+			       &in, in.uid);
+      if (h)
+	{
+	  *stmt_p = h->to;
+	  *walk_subtrees = 0;
+	  return NULL;
+	}
+    }
+
   /* Other than invisiref parms, don't walk the same tree twice.  */
   if (pointer_set_contains (p_set, stmt))
     {
--- gcc/cp/cp-tree.h.jj	2006-06-07 13:28:42.000000000 +0200
+++ gcc/cp/cp-tree.h	2006-06-09 13:52:13.000000000 +0200
@@ -721,6 +721,15 @@ struct saved_scope GTY(())
 
 extern GTY(()) struct saved_scope *scope_chain;
 
+struct cxx_int_tree_map GTY(())
+{
+  unsigned int uid;
+  tree to;
+};
+
+extern unsigned int cxx_int_tree_map_hash (const void *);
+extern int cxx_int_tree_map_eq (const void *, const void *);
+
 /* Global state pertinent to the current function.  */
 
 struct language_function GTY(())
@@ -747,6 +756,7 @@ struct language_function GTY(())
   htab_t GTY((param_is(struct named_label_entry))) x_named_labels;
   struct cp_binding_level *bindings;
   VEC(tree,gc) *x_local_names;
+  htab_t GTY((param_is (struct cxx_int_tree_map))) extern_decl_map;
 };
 
 /* The current C++-specific per-function global variables.  */
--- gcc/cp/decl.c.jj	2006-06-07 13:28:42.000000000 +0200
+++ gcc/cp/decl.c	2006-06-09 14:29:13.000000000 +0200
@@ -11102,6 +11102,7 @@ finish_function (int flags)
       f->x_vtt_parm = NULL;
       f->x_return_value = NULL;
       f->bindings = NULL;
+      f->extern_decl_map = NULL;
 
       /* Handle attribute((warn_unused_result)).  Relies on gimple input.  */
       c_warn_unused_result (&DECL_SAVED_TREE (fndecl));


	Jakub



More information about the Gcc-patches mailing list