This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[incremental] Patch: FYI: decl smashing pass


I'm checking this in on the incremental compiler branch.

The incremental compiler avoids decl smashing, because a smashed decl
is much harder to reuse.  This worked surprisingly well, but over time
it was needing more and more changes -- a change to cgraph to teach it
about duplicates, and then it looked like changes to dwarf2out and
varpool too (based on analysis of test suite failures).

This patch reintroduces decl smashing.  The idea is to wait until the
server has forked for code generation, then transform the program to
use canonical decls and types everywhere.  After forking, there is no
danger of messing up reuse.  This approach lets us remove the cgraph
changes, which I think is a plus.  Another plus is that the resulting
trees are closer to the unmodified front end; for instance we now
remove the new VIEW_CONVERT_EXPRs during gimplification.

We also track the "first definition" off a decl.  The idea here is
that we don't want to mess with resetting the DECL_CONTEXT of included
objects; so, if we see a definition, we later use that tree as the
object into which others are smashed.

This patch requires passing "top level" decls to cgraph/varpool after
smashing, which in effect removes -fno-unit-at-a-time operation.  My
impression is that this is desirable to remove anyhow, so I didn't
look into trying to preserve the semantics.

This brings the branch's test suite failures down to 32.  A few of
those are due to tests assuming -fno-unit-at-a-time (e.g, you can see
different output for weak-7.c on the trunk with -funit-at-a-time).  I
haven't analyzed all the failures yet.

Tom

ChangeLog:
2008-02-13  Tom Tromey  <tromey@redhat.com>

	* c-parser.c: Include pointer-set.h.
	(c_parser) <smash_map>: Removed.
	(global_smash_map): New global.
	(struct mark_one_hunk_binding_info): Define.
	(mark_one_hunk_binding): Change argument types.  Use
	htab_clear_slot.
	(c_parser_mark_hunk_set): Update.
	(struct smash_value): Define.
	(struct smash_entry) <value>: Change type.
	(c_parser_find_binding): Update.
	(hash_c_tree_map_entry): New function.
	(eq_c_tree_map_entry): Likewise.
	(copy_to_pointer_map): Likewise.
	(c_parser_create_smash_map): Likewise.
	(c_parser_note_smash): Track canonical definition.
	(c_parse_file): Create global_smash_map.
	* c-common.h: Update comment.
	* c-gimplify.c (c_gimplify_expr) <CALL_EXPR, FDESC_EXPR,
	ADDR_EXPR>: Remove cases.
	<VIEW_CONVERT_EXPR>: Handle C_SMASHED_P.
	* c-typeck.c (build_component_ref): Set C_SMASHED_P.
	(build_indirect_ref): Likewise.
	(build_array_ref): Likewise.
	(build_external_ref): Likewise.
	(build_function_call): Likewise.
	(wrap_pointer_int_sum): Likewise.
	(readonly_error): Remove VIEW_CONVERT_EXPRs.
	* c-decl.c: Include server.h, pointer-set.h.
	(c_decl_re_bind): Don't hand off decls.
	(merge_decls): Don't call cgraph_finalize_function.
	(duplicate_decls): Copy C_FIRST_DEFINITION_P.
	(clone_underlying_type): Update comment.
	(start_decl): Set C_FIRST_DEFINITION_P.
	(finish_decl): Don't call rest_of_decl_compilation for file-scope
	decls.
	(finish_struct): Likewise.
	(start_struct): Set C_FIRST_DEFINITION_P.
	(start_enum): Likewise.
	(finish_enum): Don't call rest_of_type_compilation for file-scope
	type.
	(start_function): Set C_FIRST_DEFINITION_P.
	(finish_function): Don't call cgraph_finalize_function.
	(c_merge_decls): New function.
	(get_smashed_type): Likewise.
	(c_smash_decls): Likewise.
	(rewrite_types_and_globals): Likewise.
	(hand_off_decls): Likewise.
	(c_write_global_declarations_1): Change argument type.
	(c_write_global_declarations_2): Likewise.
	(lowering_smash_map): New global.
	(c_write_global_declarations): Call c_smash_decls.
	* c-tree.h (c_parser_create_smash_map, c_merge_decls): Declare.
	(C_FIRST_DEFINITION_P): New macro.
	(C_SMASHED_P): Likewise.
	(struct c_tree_map_entry): Define.
	* cgraphunit.c (cgraph_analyze_functions): Handle case where child
	is also deleted.
	* cgraph.h (cgraph_note_duplicate, cgraph_canonical_decl):
	Remove.
	* cgraph.c (duplicate_map): Remove.
	(cgraph_reset): Update.
	(cgraph_canonical_decl): Remove.
	(cgraph_note_duplicate): Remove.
	* cgraphbuild.c (record_reference): Don't call
	cgraph_canonical_decl.

Index: cgraphbuild.c
===================================================================
--- cgraphbuild.c	(revision 130053)
+++ cgraphbuild.c	(working copy)
@@ -1,5 +1,5 @@
 /* Callgraph construction.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -59,7 +59,7 @@
 	     functions reachable unconditionally.  */
 	  tree decl = TREE_OPERAND (*tp, 0);
 	  if (TREE_CODE (decl) == FUNCTION_DECL)
-	    cgraph_mark_needed_node (cgraph_node (cgraph_canonical_decl (decl)));
+	    cgraph_mark_needed_node (cgraph_node (decl));
 	}
       break;
 
Index: cgraph.c
===================================================================
--- cgraph.c	(revision 130053)
+++ cgraph.c	(working copy)
@@ -1,5 +1,5 @@
 /* Callgraph handling code.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -131,12 +131,7 @@
    them, to support -fno-toplevel-reorder.  */
 int cgraph_order;
 
-/* A front end may decide not to smash duplicate declarations.  This
-   map records such duplicates so cgraph can always operate on the
-   canonical declaration from a group of duplicates.  */
-static struct pointer_map_t *duplicate_map;
 
-
 /* Reset this module in preparation for the next compilation unit.  */
 
 void
@@ -155,11 +150,6 @@
   cgraph_asm_nodes = NULL;
   cgraph_asm_last_node = NULL;
   cgraph_order = 0;
-  if (duplicate_map)
-    {
-      pointer_map_destroy (duplicate_map);
-      duplicate_map = NULL;
-    }
 }
 
 static hashval_t hash_node (const void *);
@@ -205,19 +195,6 @@
   return node;
 }
 
-/* Return the canonical decl.  */
-tree
-cgraph_canonical_decl (tree decl)
-{
-  if (duplicate_map)
-    {
-      void **slot;
-      while ((slot = pointer_map_contains (duplicate_map, decl)) != NULL)
-	decl = (tree) *slot;
-    }
-  return decl;
-}
-
 /* Return cgraph node assigned to DECL.  Create new one when needed.  */
 
 struct cgraph_node *
@@ -255,47 +232,6 @@
   return node;
 }
 
-/* Tell cgraph that DUPLICATE is the same object as DECL.  */
-void
-cgraph_note_duplicate (tree decl, tree duplicate)
-{
-  void **slot;
-
-  decl = cgraph_canonical_decl (decl);
-
-  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
-	      && TREE_CODE (duplicate) == FUNCTION_DECL);
-  gcc_assert (decl != duplicate);
-
-  if (cgraph_hash)
-    {
-      struct cgraph_node key, **cg_slot;
-      key.decl = decl;
-      cg_slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key,
-							NO_INSERT);
-      if (cg_slot && *cg_slot)
-	{
-	  /* We already saw a definition of the function, so reverse
-	     the duplication.  */
-	  tree tem;
-	  /* If unit-at-a-time, we should only see definitions here.
-	     If no-unit-at-a-time, we might see a declaration.  */
-	  gcc_assert (!flag_unit_at_a_time || DECL_INITIAL (decl));
-	  tem = duplicate;
-	  duplicate = decl;
-	  decl = tem;
-	}
-    }
-
-  if (!duplicate_map)
-    duplicate_map = pointer_map_create ();
-
-  /* Due to the way decl smashing works, the most recent decl is
-     always canonical.  */
-  slot = pointer_map_insert (duplicate_map, decl);
-  *slot = duplicate;
-}
-
 /* Insert already constructed node into hashtable.  */
 
 void
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 130053)
+++ cgraph.h	(working copy)
@@ -1,5 +1,5 @@
 /* Callgraph handling code.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -288,8 +288,6 @@
 
 /* In cgraph.c  */
 void cgraph_reset (void);
-void cgraph_note_duplicate (tree, tree);
-tree cgraph_canonical_decl (tree);
 void dump_cgraph (FILE *);
 void dump_cgraph_node (FILE *, struct cgraph_node *);
 void cgraph_insert_node_to_hashtable (struct cgraph_node *node);
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 130919)
+++ cgraphunit.c	(working copy)
@@ -1,5 +1,5 @@
 /* Callgraph based interprocedural optimizations.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -966,6 +966,11 @@
       tree decl = node->decl;
       next = node->next;
 
+      /* We can see DECL==null here when we delete a node and its
+	 children, and the nodes are ordered in a particular way.  */
+      if (decl == NULL_TREE)
+	continue;
+
       if (node->local.finalized && !DECL_SAVED_TREE (decl))
 	cgraph_reset_node (node);
 
Index: c-tree.h
===================================================================
--- c-tree.h	(revision 131774)
+++ c-tree.h	(working copy)
@@ -455,10 +455,20 @@
 extern void c_parser_lookup_callback (tree, tree, bool);
 extern void c_parse_file_wrapper (int);
 
+extern htab_t c_parser_create_smash_map (void);
+
 /* Only for use by the GC.  */
 extern int c_parser_mark_hunk_set (const void *);
 
-/* True if this decl or type has been smashed.  */
+/* This flag is used to mark the first definition for a given name.
+   When re-smashing, we pick this definition as the canonical object;
+   this particular choice lets us avoid resetting the DECL_CONTEXT for
+   many things.  */
+#define C_FIRST_DEFINITION_P(OBJ) TREE_LANG_FLAG_4 (OBJ)
+
+/* True if this decl or type has been smashed.  On a
+   VIEW_CONVERT_EXPR, it means that the expression was introduced to
+   convert between smashed types.  */
 #define C_SMASHED_P(T) TREE_LANG_FLAG_5 (T)
 
 /* Return the smashed variant of TYPE.  This will look up the
@@ -469,6 +479,13 @@
 			   TYPE_QUALS (TYPE))				\
    : TYPE)
 
+/* This is used when canonicalizing trees before lowering.  */
+struct c_tree_map_entry GTY (())
+{
+  tree key;
+  tree value;
+};
+
 /* in c-aux-info.c */
 extern void gen_aux_info_record (tree, int, int, int);
 
@@ -483,6 +500,7 @@
 extern void insert_block (tree);
 
 extern void c_decl_re_bind (tree, tree);
+extern tree c_merge_decls (tree, tree);
 
 extern void c_init_decl_processing (void);
 extern void c_dup_lang_specific_decl (tree);
Index: c-decl.c
===================================================================
--- c-decl.c	(revision 131638)
+++ c-decl.c	(working copy)
@@ -60,6 +60,8 @@
 #include "except.h"
 #include "langhooks-def.h"
 #include "pointer-set.h"
+#include "server.h"
+#include "pointer-set.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -552,29 +554,6 @@
 	  /*notify_ok=*/false);
 
   TREE_ASM_WRITTEN (decl) = 0;
-  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
-    {
-      /* Function has already been genericized, so just tell cgraph
-	 about it.  */
-      cgraph_finalize_function (decl, false);
-    }
-  else if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      /* FIXME: moral equivalent of decl smashing here.  */
-      if (DECL_INITIAL (decl) == NULL_TREE
-	  || DECL_INITIAL (decl) == error_mark_node)
-	/* Don't output anything
-	   when a tentative file-scope definition is seen.
-	   But at end of compilation, do output code for them.  */
-	DECL_DEFER_OUTPUT (decl) = 1;
-      rest_of_decl_compilation (decl, true, 0);
-    }
-  else if (TREE_CODE (decl) == TYPE_DECL)
-    rest_of_decl_compilation (decl, true, 0);
-  else if (TREE_CODE (decl) == RECORD_TYPE
-	   || TREE_CODE (decl) == UNION_TYPE
-	   || TREE_CODE (decl) == ENUMERAL_TYPE)
-    rest_of_type_compilation (decl, true);
 }
 
 static int
@@ -2077,13 +2056,6 @@
 	  || (TREE_CODE (olddecl) == VAR_DECL
 	      && TREE_STATIC (olddecl))))
     make_decl_rtl (olddecl);
-
-  /* If we changed a function from DECL_EXTERNAL to !DECL_EXTERNAL,
-     and the definition is coming from the old version, cgraph needs
-     to be called again.  */
-  if (extern_changed && !new_is_definition 
-      && TREE_CODE (olddecl) == FUNCTION_DECL && DECL_INITIAL (olddecl))
-    cgraph_finalize_function (olddecl, false);
 }
 
 /* Handle when a new declaration NEWDECL has the same name as an old
@@ -2123,6 +2095,7 @@
 		       C_SMASHED_TYPE_VARIANT (oldtype));
 	  /* FIXME: this triggers building libgcc.  */
 	  /* 	  gcc_assert (binding->decl == olddecl); */
+	  C_FIRST_DEFINITION_P (copy) = C_FIRST_DEFINITION_P (newdecl);
 	  binding->decl = copy;
 	  c_parser_bind_callback (DECL_NAME (copy), copy);
 	  c_parser_note_smash (olddecl, copy);
@@ -2223,12 +2196,8 @@
 
     Obviously, we don't want to generate a duplicate ..._TYPE node if
     the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.
+    standard built-in type.  */
 
-    Since all standard types are effectively declared at line zero
-    in the source file, we can easily check to see if we are working
-    on a standard type by checking the current value of lineno.  */
-
 static void
 clone_underlying_type (tree x)
 {
@@ -3629,6 +3598,11 @@
 
   /* Add this decl to the current scope.
      TEM may equal DECL or it may be a previous decl of the same name.  */
+
+  if (TREE_CODE (decl) == TYPE_DECL
+      || (TREE_CODE (decl) == VAR_DECL
+	  && (initialized || ! DECL_EXTERNAL (decl))))
+    C_FIRST_DEFINITION_P (decl) = 1;
   tem = pushdecl (decl);
 
   if (initialized && DECL_EXTERNAL (tem))
@@ -3850,13 +3824,7 @@
 
       if (DECL_FILE_SCOPE_P (decl))
 	{
-	  if (DECL_INITIAL (decl) == NULL_TREE
-	      || DECL_INITIAL (decl) == error_mark_node)
-	    /* Don't output anything
-	       when a tentative file-scope definition is seen.
-	       But at end of compilation, do output code for them.  */
-	    DECL_DEFER_OUTPUT (decl) = 1;
-	  rest_of_decl_compilation (decl, true, 0);
+	  /* Nothing.  */
 	}
       else
 	{
@@ -3921,7 +3889,8 @@
 	  && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
 	add_stmt (build_stmt (DECL_EXPR, decl));
 
-      rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
+      if (!DECL_FILE_SCOPE_P (decl))
+	rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
     }
 
   /* At the end of a declaration, throw away any variable type sizes
@@ -4062,7 +4031,6 @@
       DECL_ARTIFICIAL (decl) = 1;
       DECL_IGNORED_P (decl) = 1;
       pushdecl (decl);
-      rest_of_decl_compilation (decl, 1, 0);
     }
 
   return complit;
@@ -5676,6 +5644,7 @@
       || !object_in_current_hunk_p (ref))
     {
       tree newval = make_node (code);
+      C_FIRST_DEFINITION_P (newval) = 1;
       pushtag (name, newval);
       if (ref)
 	c_parser_note_smash (ref, newval);
@@ -6061,15 +6030,18 @@
 	  layout_decl (decl, 0);
 	  if (c_dialect_objc ())
 	    objc_check_decl (decl);
-	  rest_of_decl_compilation (decl, toplevel, 0);
 	  if (!toplevel)
-	    expand_decl (decl);
+	    {
+	      rest_of_decl_compilation (decl, toplevel, 0);
+	      expand_decl (decl);
+	    }
 	}
     }
   C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t)) = 0;
 
   /* Finish debugging output for this type.  */
-  rest_of_type_compilation (t, toplevel);
+  if (!toplevel)
+    rest_of_type_compilation (t, toplevel);
 
   /* If we're inside a function proper, i.e. not file-scope and not still
      parsing parameters, then arrange for the size of a variable sized type
@@ -6128,6 +6100,7 @@
       || !object_in_current_hunk_p (enumtype))
     {
       tree newval = make_node (ENUMERAL_TYPE);
+      C_FIRST_DEFINITION_P (newval) = 1;
       pushtag (name, newval);
       if (enumtype)
 	c_parser_note_smash (enumtype, newval);
@@ -6282,7 +6255,8 @@
     }
 
   /* Finish debugging output for this type.  */
-  rest_of_type_compilation (enumtype, toplevel);
+  if (!toplevel)
+    rest_of_type_compilation (enumtype, toplevel);
 
   return enumtype;
 }
@@ -6577,6 +6551,7 @@
   /* Record the decl so that the function name is defined.
      If we already have a decl for this name, note that we smashed it.  */
 
+  C_FIRST_DEFINITION_P (decl1) = 1;
   current_function_decl = pushdecl (decl1);
 
   push_scope ();
@@ -7087,8 +7062,6 @@
 	      c_expand_body (fndecl);
 	      return;
 	    }
-
-	  cgraph_finalize_function (fndecl, false);
 	}
       else
 	{
@@ -8092,18 +8065,364 @@
   return specs;
 }
 
+/* Callback used when creating the final decl canonicalization map.
+   LATEST and DEFINITION are two variants of the same declaration.
+   DEFINITION, if not NULL, is the canonical definition of this
+   object.  LATEST is the most recent merged declaration.  If
+   DEFINITION is not NULL, this function will destructively merge
+   LATEST into DEFINITION and return DEFINITION.  Otherwise, it
+   returns LATEST.  */
+tree
+c_merge_decls (tree latest, tree definition)
+{
+  if (TREE_CODE_CLASS (TREE_CODE (latest)) == tcc_declaration)
+    {
+      if (definition && latest && latest != definition)
+	merge_decls (latest, definition, TREE_TYPE (latest),
+		     TREE_TYPE (definition));
+    }
+  return definition ? definition : latest;
+}
+
+/* Return the smashed version of TYPE.  MAP is the map used to track
+   smashing.  If the type is already in the map, return the smashed
+   copy.  Otherwise, compute the smashed variant and update the
+   map.  */
+static tree
+get_smashed_type (htab_t map, tree type)
+{
+  tree original_type;
+  void **slot;
+  struct c_tree_map_entry entry, *found;
+
+  if (type == error_mark_node)
+    return type;
+
+  gcc_assert (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type);
+
+  entry.key = type;
+  found = (struct c_tree_map_entry *) htab_find (map, &entry);
+  if (found)
+    return found->value;
+
+  original_type = type;
+  if (TYPE_MAIN_VARIANT (type) != type)
+    {
+      tree save = TYPE_MAIN_VARIANT (type);
+      type = get_smashed_type (map, save);
+      if (type == save)
+	type = original_type;
+      else
+	{
+	  type = build_qualified_type (type, TYPE_QUALS (original_type));
+	  /* If the original type was a typedef, preserve that too.  */
+	  if (TYPE_NAME (original_type)
+	      != TYPE_NAME (TYPE_MAIN_VARIANT (original_type)))
+	    {
+	      type = build_variant_type_copy (type);
+	      TYPE_NAME (type) = TYPE_NAME (original_type);
+	      /* FIXME: do we need to reset the TREE_TYPE of the
+		 TYPE_NAME here?  */
+	    }
+	}
+    }
+  else
+    {
+      switch (TREE_CODE (type))
+	{
+	case REFERENCE_TYPE:
+	case OFFSET_TYPE:
+	case BOOLEAN_TYPE:
+	case INTEGER_TYPE:
+	case REAL_TYPE:
+	case FIXED_POINT_TYPE:
+	case COMPLEX_TYPE:
+	case VECTOR_TYPE:
+	case VOID_TYPE:
+	case ENUMERAL_TYPE:
+	case UNION_TYPE:
+	case RECORD_TYPE:
+	  /* Nothing special.  */
+	  break;
+
+	case POINTER_TYPE:
+	  {
+	    tree subtype = get_smashed_type (map, TREE_TYPE (type));
+	    if (subtype != TREE_TYPE (type))
+	      type = build_pointer_type (subtype);
+	  }
+	  break;
+
+	case FUNCTION_TYPE:
+	  {
+	    tree rtype;
+	    tree arg, arglist = NULL_TREE;
+	    bool changed = false;
+
+	    rtype = get_smashed_type (map, TREE_TYPE (type));
+	    if (rtype != TREE_TYPE (type))
+	      changed = true;
+	    for (arg = TYPE_ARG_TYPES (type); arg; arg = TREE_CHAIN (arg))
+	      {
+		tree value = TREE_VALUE (arg);
+		if (value)
+		  {
+		    tree old = value;
+		    value = get_smashed_type (map, value);
+		    if (value != old)
+		      changed = true;
+		  }
+		arglist = tree_cons (NULL_TREE, value, arglist);
+	      }
+	    if (changed)
+	      {
+		arglist = nreverse (arglist);
+		type = build_function_type (rtype, arglist);
+	      }
+	  }
+	  break;
+
+	case ARRAY_TYPE:
+	  {
+	    tree index = NULL_TREE;
+	    if (TYPE_DOMAIN (type))
+	      index = get_smashed_type (map, TYPE_DOMAIN (type));
+	    tree elts = get_smashed_type (map, TREE_TYPE (type));
+	    if (index != TYPE_DOMAIN (type) || elts != TREE_TYPE (type))
+	      type = build_array_type (elts, index);
+	  }
+	  break;
+
+	case QUAL_UNION_TYPE:
+	case METHOD_TYPE:
+	case LANG_TYPE:
+	default:
+	  /* Should not be possible.  */
+	  gcc_unreachable ();
+	}
+    }
+
+  found = GGC_NEW (struct c_tree_map_entry);
+  found->key = original_type;
+  found->value = type;
+  slot = htab_find_slot (map, found, INSERT);
+  if (*slot)
+    {
+      found = (struct c_tree_map_entry *) *slot;
+      gcc_assert (found->value == type);
+    }
+  else
+    *slot = found;
+
+
+  if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE)
+      && type == TYPE_MAIN_VARIANT (type))
+    {
+      /* Canonicalize the type of each field.  We do this here, and
+	 not earlier, to avoid infinite recursion in some cases.  */
+      tree field;
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+	{
+	  gcc_assert (TREE_CODE (field) == FIELD_DECL);
+	  TREE_TYPE (field) = get_smashed_type (map, TREE_TYPE (field));
+	}
+    }
+
+  return type;
+}
+
+/* Re-smash decls and destructively remove non-canonical decls from
+   the chain.  */
+static void
+c_smash_decls (htab_t map, struct pointer_set_t *seen,
+	       VEC (tree, heap) **result, tree list)
+{
+  tree decl;
+  for (decl = list; decl; decl = TREE_CHAIN (decl))
+    {
+      tree canonical;
+      struct c_tree_map_entry entry;
+      void **slot;
+
+      if (! map)
+	{
+	  VEC_safe_push (tree, heap, *result, decl);
+	  continue;
+	}
+
+      /* This can happen with --combine.  FIXME: with combine we get
+	 the wrong result for file-scope variables.  */
+      if (pointer_set_contains (seen, decl))
+	continue;
+
+      /* The first time we see a decl, we insert its canonical copy
+	 into the result list.  If we've already seen the canonical
+	 copy, we simply skip it and move on.  */
+      entry.key = decl;
+      slot = htab_find_slot (map, &entry, NO_INSERT);
+      if (! slot)
+	{
+	  /* If the name was only seen once, then the decl won't
+	     appear in the map.  In this case it is canonical by
+	     itself.  */
+	  canonical = decl;
+	}
+      else
+	{
+	  struct c_tree_map_entry *ep = (struct c_tree_map_entry *) *slot;
+	  canonical = ep->value;
+	  if (pointer_set_contains (seen, canonical))
+	    continue;
+	}
+
+      gcc_assert (TREE_CODE_CLASS (TREE_CODE (canonical)) == tcc_declaration);
+
+      /* Handle typedefs specially.  We re-create the original logic
+	 here.  */
+      if (TREE_CODE (canonical) == TYPE_DECL && DECL_ORIGINAL_TYPE (canonical))
+	{
+	  tree save, type;
+	  gcc_assert (TREE_TYPE (canonical) != DECL_ORIGINAL_TYPE (canonical));
+	  /* First update DECL_ORIGINAL_TYPE.  */
+	  save = DECL_ORIGINAL_TYPE (canonical);
+	  DECL_ORIGINAL_TYPE (canonical)
+	    = get_smashed_type (map, DECL_ORIGINAL_TYPE (canonical));
+	  /* Now update TREE_TYPE.  */
+	  type = TREE_TYPE (canonical);
+	  entry.key = type;
+	  slot = htab_find_slot (map, &entry, INSERT);
+	  if (*slot)
+	    {
+	      TREE_TYPE (canonical)
+		= ((struct c_tree_map_entry *) *slot)->value;
+	      gcc_assert (TREE_TYPE (canonical)
+			  != DECL_ORIGINAL_TYPE (canonical));
+	    }
+	  else
+	    {
+	      struct c_tree_map_entry *nentry;
+
+	      /* If the original type did not change by smashing,
+		 we also don't need to change the TREE_TYPE.  */
+	      if (DECL_ORIGINAL_TYPE (canonical) != save)
+		{
+		  TREE_TYPE (canonical) = DECL_ORIGINAL_TYPE (canonical);
+		  DECL_ORIGINAL_TYPE (canonical) = NULL_TREE;
+		  clone_underlying_type (canonical);
+		}
+
+	      nentry = GGC_NEW (struct c_tree_map_entry);
+	      nentry->key = type;
+	      nentry->value = TREE_TYPE (canonical);
+	      *slot = nentry;
+	    }
+	}
+      else
+	TREE_TYPE (canonical) = get_smashed_type (map, TREE_TYPE (canonical));
+
+      pointer_set_insert (seen, canonical);
+      VEC_safe_push (tree, heap, *result, canonical);
+    }
+}
+
+static tree
+rewrite_types_and_globals (tree *nodep, int *subtrees, void *user_data)
+{
+  htab_t map = (htab_t) user_data;
+  struct c_tree_map_entry entry, *found;
+
+  entry.key = *nodep;
+  found = (struct c_tree_map_entry *) htab_find (map, &entry);
+  if (found)
+    {
+      *nodep = found->value;
+      *subtrees = 0;
+    }
+  else if (TREE_CODE (*nodep) == BLOCK)
+    {
+      /* Weirdly, walk_tree does not handle BLOCK itself.  */
+      walk_tree (&BLOCK_VARS (*nodep), rewrite_types_and_globals,
+		 map, NULL);
+      walk_tree (&BLOCK_CHAIN (*nodep), rewrite_types_and_globals,
+		 map, NULL);
+      walk_tree (&BLOCK_SUBBLOCKS (*nodep), rewrite_types_and_globals,
+		 map, NULL);
+    }
+  else if (TREE_CODE (*nodep) == BIND_EXPR)
+    {
+      /* Do nothing.  */
+    }
+  else if (TREE_TYPE (*nodep) && TREE_TYPE (*nodep) != error_mark_node)
+    TREE_TYPE (*nodep) = get_smashed_type (map, TREE_TYPE (*nodep));
+
+  return NULL_TREE;
+}
+
+static void
+hand_off_decls (htab_t map, VEC (tree, heap) *globals)
+{
+  int ix;
+  tree decl;
+  for (ix = 0; VEC_iterate (tree, globals, ix, decl); ++ix)
+    {
+      switch (TREE_CODE (decl))
+	{
+	case FUNCTION_DECL:
+	  {
+	    bool save = c_override_global_bindings_to_false;
+	    c_override_global_bindings_to_false = true;
+	    walk_tree (&DECL_INITIAL (decl), rewrite_types_and_globals,
+		       map, NULL);
+	    walk_tree (&DECL_SAVED_TREE (decl), rewrite_types_and_globals,
+		       map, NULL);
+	    c_override_global_bindings_to_false = save;
+	    if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
+	      cgraph_finalize_function (decl, false);
+	    else
+	      {
+		DECL_DEFER_OUTPUT (decl) = 1;
+		rest_of_decl_compilation (decl, true, 0);
+	      }
+	  }
+	  break;
+
+	case VAR_DECL:
+	  if (DECL_INITIAL (decl) == NULL_TREE
+	      || DECL_INITIAL (decl) == error_mark_node)
+	    /* Don't output anything
+	       when a tentative file-scope definition is seen.
+	       But at end of compilation, do output code for them.  */
+	    DECL_DEFER_OUTPUT (decl) = 1;
+	  rest_of_decl_compilation (decl, true, false);
+	  break;
+
+	case TYPE_DECL:
+	  rest_of_decl_compilation (decl, true, false);
+	  break;
+
+	case CONST_DECL:
+	  /* Nothing.  */
+	  break;
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+}
+
 /* A subroutine of c_write_global_declarations.  Perform final processing
    on one file scope's declarations (or the external scope's declarations),
    GLOBALS.  */
 
 static void
-c_write_global_declarations_1 (tree globals)
+c_write_global_declarations_1 (VEC (tree, heap) *globals)
 {
   tree decl;
   bool reconsider;
+  int ix;
 
   /* Process the decls in the order they were written.  */
-  for (decl = globals; decl; decl = TREE_CHAIN (decl))
+  for (ix = 0; VEC_iterate (tree, globals, ix, decl); ++ix)
     {
       /* Check for used but undefined static functions using the C
 	 standard's definition of "used", and set TREE_NO_WARNING so
@@ -8124,12 +8443,12 @@
   do
     {
       reconsider = false;
-      for (decl = globals; decl; decl = TREE_CHAIN (decl))
+      for (ix = 0; VEC_iterate (tree, globals, ix, decl); ++ix)
 	reconsider |= wrapup_global_declaration_2 (decl);
     }
   while (reconsider);
 
-  for (decl = globals; decl; decl = TREE_CHAIN (decl))
+  for (ix = 0; VEC_iterate (tree, globals, ix, decl); ++ix)
     check_global_declaration_1 (decl);
 }
 
@@ -8137,11 +8456,12 @@
    information for each of the declarations in GLOBALS.  */
 
 static void
-c_write_global_declarations_2 (tree globals)
+c_write_global_declarations_2 (VEC (tree, heap) *globals)
 {
   tree decl;
+  int ix;
 
-  for (decl = globals; decl ; decl = TREE_CHAIN (decl))
+  for (ix = 0; VEC_iterate (tree, globals, ix, decl); ++ix)
     debug_hooks->global_decl (decl);
 }
 
@@ -8177,24 +8497,55 @@
     }
 }
 
+/* This maps trees to their canonical (smashed) variants.  This must
+   be a global to protect it from the GC.  */
+static GTY ((param_is (struct c_tree_map_entry))) htab_t lowering_smash_map;
+
 void
 c_write_global_declarations (void)
 {
   tree t;
+  VEC (tree, heap) *all_decls = VEC_alloc (tree, heap, 128);
+  struct pointer_set_t *seen_decls = NULL;
 
+  if (! really_call_malloc (52))
+    abort ();
+
+  server_assert_code_generation ();
+
+  lowering_smash_map = c_parser_create_smash_map ();
+  if (lowering_smash_map)
+    seen_decls = pointer_set_create ();
+
+  /* Smash all the types and decls.  If we don't have a smash map,
+     just fill ALL_DECLS with all the decls on the lists.  */
+  for (t = all_translation_units; t; t = TREE_CHAIN (t))
+    c_smash_decls (lowering_smash_map, seen_decls, &all_decls,
+		   BLOCK_VARS (DECL_INITIAL (t)));
+  if (ext_block)
+    c_smash_decls (lowering_smash_map, seen_decls, &all_decls,
+		   BLOCK_VARS (ext_block));
+
+  /* Clean up.  */
+  if (seen_decls)
+    pointer_set_destroy (seen_decls);
+
+  hand_off_decls (lowering_smash_map, all_decls);
+  lowering_smash_map = NULL;
+
   /* Don't waste time on further processing if -fsyntax-only or we've
      encountered errors.  If we are generating a PCH file, then we
      don't want to do this either.  */
   if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in)
       || pch_file)
-    return;
+    {
+      VEC_free (tree, heap, all_decls);
+      return;
+    }
 
   /* Process all file scopes in this compilation, and the external_scope,
      through wrapup_global_declarations and check_global_declarations.  */
-  for (t = all_translation_units; t; t = TREE_CHAIN (t))
-    c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
-  c_write_global_declarations_1 (BLOCK_VARS (ext_block));
-
+  c_write_global_declarations_1 (all_decls);
   
   /* We're done parsing; proceed to optimize and emit assembly.
      FIXME: shouldn't be the front end's responsibility to call this.  */
@@ -8206,12 +8557,11 @@
   if (errorcount == 0 && sorrycount == 0)
     {
       timevar_push (TV_SYMOUT);
-      for (t = all_translation_units; t; t = TREE_CHAIN (t))
-	c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t)));
-      c_write_global_declarations_2 (BLOCK_VARS (ext_block));
+      c_write_global_declarations_2 (all_decls);
       timevar_pop (TV_SYMOUT);
     }
 
+  VEC_free (tree, heap, all_decls);
   ext_block = NULL;
 }
 
Index: c-typeck.c
===================================================================
--- c-typeck.c	(revision 131930)
+++ c-typeck.c	(working copy)
@@ -1809,7 +1809,10 @@
     {
       type = C_SMASHED_TYPE_VARIANT (orig_type);
       if (type != orig_type)
-	datum = build1 (VIEW_CONVERT_EXPR, type, datum);
+	{
+	  datum = build1 (VIEW_CONVERT_EXPR, type, datum);
+	  C_SMASHED_P (datum) = 1;
+	}
     }
 
   if (!objc_is_public (datum, component))
@@ -1916,6 +1919,7 @@
 	      int sf = TREE_SIDE_EFFECTS (pointer);
 	      pointer = build1 (VIEW_CONVERT_EXPR, build_pointer_type (t2),
 				pointer);
+	      C_SMASHED_P (pointer) = 1;
 	      TREE_SIDE_EFFECTS (pointer) = sf;
 	      t = t2;
 	    }
@@ -2080,6 +2084,7 @@
 	  int sf = TREE_SIDE_EFFECTS (ar);
 	  ar = build1 (VIEW_CONVERT_EXPR, build_pointer_type (t2), ar);
 	  TREE_SIDE_EFFECTS (ar) = sf;
+	  C_SMASHED_P (ar) = 1;
 	}
 
       return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, index, 0),
@@ -2175,7 +2180,10 @@
     {
       tree smashtype = C_SMASHED_TYPE_VARIANT (TREE_TYPE (ref));
       if (smashtype != TREE_TYPE (ref))
-	ref = build1 (VIEW_CONVERT_EXPR, smashtype, ref);
+	{
+	  ref = build1 (VIEW_CONVERT_EXPR, smashtype, ref);
+	  C_SMASHED_P (ref) = 1;
+	}
     }
 
   return ref;
@@ -2381,6 +2389,7 @@
       TREE_TYPE (copy) = C_SMASHED_TYPE_VARIANT (TREE_TYPE (copy));
       function = build1 (VIEW_CONVERT_EXPR, build_pointer_type (copy),
 			 function);
+      C_SMASHED_P (function) = 1;
       fntype = copy;
     }
 
@@ -3183,6 +3192,11 @@
 {
   gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
 	      || use == lv_asm);
+
+  /* Remove any type casts inserted due to decl smashing.  */
+  while (TREE_CODE (arg) == VIEW_CONVERT_EXPR)
+    arg = TREE_OPERAND (arg, 0);
+
   /* Using this macro rather than (for example) arrays of messages
      ensures that all the format strings are checked at compile
      time.  */
@@ -7783,6 +7797,7 @@
       int sf = TREE_SIDE_EFFECTS (ptrop);
       ptrop = build1 (VIEW_CONVERT_EXPR, build_pointer_type (t2), ptrop);
       TREE_SIDE_EFFECTS (ptrop) = sf;
+      C_SMASHED_P (ptrop) = 1;
     }
   return pointer_int_sum (code, ptrop, intop);
 }
Index: c-gimplify.c
===================================================================
--- c-gimplify.c	(revision 130603)
+++ c-gimplify.c	(working copy)
@@ -2,7 +2,7 @@
    by the C-based front ends.  The structure of gimplified, or
    language-independent, trees is dictated by the grammar described in this
    file.
-   Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
    Lowering of expressions contributed by Sebastian Pop <s.pop@laposte.net>
    Re-written to support lowering of whole function trees, documentation
    and miscellaneous cleanups by Diego Novillo <dnovillo@redhat.com>
@@ -224,26 +224,20 @@
 	TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1;
       return GS_UNHANDLED;
 
-    case CALL_EXPR:
-      {
- 	tree callee = TREE_OPERAND (*expr_p, 1);
-	if (TREE_CODE (callee) == FUNCTION_DECL)
-	  TREE_OPERAND (*expr_p, 1) = cgraph_canonical_decl (callee);
-      }
-      return GS_UNHANDLED;
-
-    case FDESC_EXPR:
-    case ADDR_EXPR:
-      {
- 	tree decl = TREE_OPERAND (*expr_p, 0);
-	if (TREE_CODE (decl) == FUNCTION_DECL)
-	  TREE_OPERAND (*expr_p, 0) = cgraph_canonical_decl (decl);
-      }
-      return GS_UNHANDLED;
-
     case COMPOUND_LITERAL_EXPR:
       return gimplify_compound_literal_expr (expr_p, pre_p);
 
+    case VIEW_CONVERT_EXPR:
+      /* At this point we should have smashed all the types, so this
+	 conversion should be redundant.  */
+      if (C_SMASHED_P (*expr_p))
+	{
+	  gcc_assert (TREE_TYPE (*expr_p)
+		      == TREE_TYPE (TREE_OPERAND (*expr_p, 0)));
+	  *expr_p = TREE_OPERAND (*expr_p, 0);
+	}
+      return GS_UNHANDLED;
+
     default:
       return GS_UNHANDLED;
     }
Index: c-common.h
===================================================================
--- c-common.h	(revision 130946)
+++ c-common.h	(working copy)
@@ -1,6 +1,6 @@
 /* Definitions for c-common.c.
    Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -33,8 +33,8 @@
       STATEMENT_LIST_STMT_EXPR (in STATEMENT_LIST)
    2: unused
    3: STATEMENT_LIST_HAS_LABEL (in STATEMENT_LIST)
-   4: unused
-   5: C_SMASHED_P (in _TYPE or _DECL)
+   4: C_FIRST_DEFINITION_P (in _TYPE or _DECL)
+   5: C_SMASHED_P (in _TYPE, _DECL, or _EXPR)
 */
 
 /* Reserved identifiers.  This is the union of all the keywords for C,
Index: c-parser.c
===================================================================
--- c-parser.c	(revision 131775)
+++ c-parser.c	(working copy)
@@ -58,6 +58,7 @@
 #include "cgraph.h"
 #include "md5.h"
 #include "server.h"
+#include "pointer-set.h"
 
 
 /* The reserved keyword table.  */
@@ -327,9 +328,6 @@
   /* The current hunk binding.  */
   struct hunk_binding *current_hunk_binding;
 
-  /* Map decls and types onto their smashed variants.  */
-  htab_t GTY ((param_is (struct smash_entry))) smash_map;
-
   /* FIXME: restructure parser main loop so this is not required.  */
   struct hunk_set *current_hset;
 
@@ -796,17 +794,28 @@
 static GTY ((if_marked ("c_parser_mark_hunk_set"), param_is (struct hunk_set)))
      htab_t global_hunk_map;
 
+/* Map decls and types onto their smashed variants.  */
+static GTY ((param_is (struct smash_entry))) htab_t global_smash_map;
+
+/* Used to pass information to mark_one_hunk_binding.  */
+struct mark_one_hunk_binding_info
+{
+  htab_t table;
+  int found_any;
+};
+
 /* "Mark" a hunk_binding as found in a hunk_set.  This is the leaf of
    the global_hunk_map marking functions.  If the hunk_binding is
    already marked, we keep it; otherwise, we remove it.  */
 static int
 mark_one_hunk_binding (void **slot, void *r)
 {
-  int *found_any = (int *) r;
+  struct mark_one_hunk_binding_info *info
+    = (struct mark_one_hunk_binding_info *) r;
   if (ggc_marked_p (*slot))
-    *found_any = 1;
+    info->found_any = 1;
   else
-    *slot = NULL;
+    htab_clear_slot (info->table, slot);
   return 1;
 }
 
@@ -819,9 +828,11 @@
 {
   /* Have to cast away const.  */
   struct hunk_set *hs = (struct hunk_set *) p;
-  int found_any = 0;
-  htab_traverse_noresize (hs->bindings, mark_one_hunk_binding, &found_any);
-  return found_any;
+  struct mark_one_hunk_binding_info info;
+  info.table = hs->bindings;
+  info.found_any = 0;
+  htab_traverse_noresize (hs->bindings, mark_one_hunk_binding, &info);
+  return info.found_any;
 }
 
 /* This is called when making a file-scope binding.  It registers the
@@ -1043,13 +1054,25 @@
 
 
 
+/* An entry in the smash map points to an object of this type.  */
+struct smash_value GTY (())
+{
+  /* The first definition, or NULL if no definition has been seen yet.
+     Of all the decls which are smashed together, this will be the
+     sole decl with C_FIRST_DEFINITION_P set.  */
+  tree definition;
+
+  /* The most recent smashed value.  */
+  tree value;
+};
+
 /* Map an object (a type or a decl) to a smashed copy.  */
 struct smash_entry GTY (())
 {
   /* The original object.  */
   tree key;
-  /* The smashed variant.  */
-  tree value;
+  /* The smash info.  */
+  struct smash_value *value;
 };
 
 /* Hash function for a struct smash_entry.  */
@@ -1076,19 +1099,88 @@
 {
   struct smash_entry **slot;
   struct smash_entry temp;
-  /* We'd like this to be an argument to this function, but that
-     requires many changes.  */
-  c_parser *parser = the_parser;
 
+  if (! global_smash_map)
+    return decl;
+
   temp.key = decl;
-  temp.value = NULL_TREE;
-  slot = (struct smash_entry **) htab_find_slot (parser->smash_map,
+  temp.value = NULL;
+  slot = (struct smash_entry **) htab_find_slot (global_smash_map,
 						 &temp, NO_INSERT);
   if (slot != NULL)
-    decl = (*slot)->value;
+    {
+      decl = (*slot)->value->value;
+      gcc_assert (decl);
+    }
+
   return decl;
 }
 
+/* Hash function for c_tree_map_entry.  */
+static hashval_t
+hash_c_tree_map_entry (const void *e)
+{
+  const struct c_tree_map_entry *entry = (const struct c_tree_map_entry *) e;
+  return htab_hash_pointer (entry->key);
+}
+
+/* Equality function for c_tree_map_entry.  */
+static int
+eq_c_tree_map_entry (const void *a, const void *b)
+{
+  const struct c_tree_map_entry *entrya = (const struct c_tree_map_entry *) a;
+  const struct c_tree_map_entry *entryb = (const struct c_tree_map_entry *) b;
+  return entrya->key == entryb->key;
+}
+
+static int
+copy_to_pointer_map (void **slot, void *user_data)
+{
+  struct smash_entry *entry = (struct smash_entry *) *slot;
+  htab_t map = (htab_t) user_data;
+  void **mapslot;
+  struct c_tree_map_entry *mapentry;
+
+  if (entry->value->definition)
+    {
+      /* The first time we see a canonical definition, smash it with
+	 the latest value.  */
+      entry->value->value = c_merge_decls (entry->value->value,
+					   entry->value->definition);
+      entry->value->definition = NULL_TREE;
+    }
+
+  mapentry = GGC_NEW (struct c_tree_map_entry);
+  mapentry->key = entry->key;
+  mapentry->value = entry->value->value;
+
+  mapslot = htab_find_slot (map, mapentry, INSERT);
+  gcc_assert (! *mapslot);
+  *mapslot = mapentry;
+  return 1;
+}
+
+htab_t
+c_parser_create_smash_map (void)
+{
+  htab_t result;
+
+  /* GLOBAL_SMASH_MAP might be null if we hit an error during
+     compilation.  */
+  if (! global_smash_map)
+    return NULL;
+
+  /* We could do this without allocating by rewriting the map in
+     place.  */
+  result = htab_create_ggc (htab_size (global_smash_map),
+			    hash_c_tree_map_entry,
+			    eq_c_tree_map_entry, NULL);
+  htab_traverse_noresize (global_smash_map, copy_to_pointer_map, result);
+  /* We don't need the smash map any more.  */
+  global_smash_map = NULL;
+  return result;
+}
+
 /* This is a callback that is called when a decl or type is smashed.
    It notes the relationship between the original decl (FROM) and the
    smashed variant (TO).  */
@@ -1096,23 +1188,65 @@
 c_parser_note_smash (tree from, tree to)
 {
   struct smash_entry **slot;
-  struct smash_entry *entry = GGC_NEW (struct smash_entry);
-  /* We'd like this to be an argument to this function, but that
-     requires many changes.  */
-  c_parser *parser = the_parser;
+  struct smash_entry temp, *entry;
+  struct smash_value *value;
 
-  entry->key = from;
-  entry->value = to;
-  slot = (struct smash_entry **) htab_find_slot (parser->smash_map,
+  /* First, insert an entry for FROM.  */
+  temp.key = from;
+  temp.value = NULL;
+  slot = (struct smash_entry **) htab_find_slot (global_smash_map,
+						 &temp, INSERT);
+  if (! *slot)
+    {
+      entry = GGC_NEW (struct smash_entry);
+      entry->key = from;
+      entry->value = GGC_CNEW (struct smash_value);
+      *slot = entry;
+    }
+
+  value = (*slot)->value;
+
+  /* We also insert an entry for TO.  This lets us keep tabs on the
+     definition, even if this is the last smash for this family of
+     decls.  */
+  entry = GGC_NEW (struct smash_entry);
+  entry->key = to;
+  entry->value = value;
+  slot = (struct smash_entry **) htab_find_slot (global_smash_map,
 						 entry, INSERT);
-  /* We might see multiple smashes for a given base decl.  We always
-     use the most recent value.  */
-  /*   gcc_assert (slot && !*slot); */
+  gcc_assert (slot && !*slot);
   *slot = entry;
+
+  /* Always use the most recent decl as the smashed value, but only
+     use the first definition as the decl family's definition.  */
+  value->value = to;
+  if (C_FIRST_DEFINITION_P (from))
+    {
+      gcc_assert (! value->definition || value->definition == from);
+      value->definition = from;
+    }
+
+  /* Both FROM and TO can be definitions, if we see an inline function
+     or a tentative definition.  */
+  if (C_FIRST_DEFINITION_P (to))
+    {
+      if (! value->definition || (TREE_CODE (from) == TREE_CODE (to)
+				  && (TREE_CODE (from) == FUNCTION_DECL
+				      || TREE_CODE (to) == VAR_DECL)))
+	{
+	  value->definition = to;
+	  C_FIRST_DEFINITION_P (from) = 0;
+	}
+      else
+	{
+	  /* This can happen if a struct is redefined, but we will
+	     always have emitted an error.  */
+	  gcc_assert (errorcount);
+	}
+    }
+
   C_SMASHED_P (from) = 1;
-
-  if (TREE_CODE (from) == FUNCTION_DECL && TREE_CODE (to) == FUNCTION_DECL)
-    cgraph_note_duplicate (from, to);
+  C_SMASHED_P (to) = 1;
 }
 
 /* Update a checksum for a numeric constant of some kind.  */
@@ -9120,8 +9254,8 @@
   the_parser = GGC_CNEW (c_parser);
   the_parser->used_hunks = htab_create_ggc (20, htab_hash_pointer,
 					    htab_eq_pointer, NULL);
-  the_parser->smash_map = htab_create_ggc (20, hash_smash_entry, eq_smash_entry,
-					   NULL);
+  global_smash_map = htab_create_ggc (20, hash_smash_entry, eq_smash_entry,
+				      NULL);
 
   c_parser_lex_all (the_parser, &token);
   c_parser_translation_unit (the_parser);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]