diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 07da35b6c6ab13814a7ecbc2ed1706efd4cd2c30..71123fc08c0376f685c43497aa9d0cc7a74d6f91 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2003-09-11  Richard Henderson  <rth@redhat.com>
+
+	* cgraphunit.c (cgraph_finalize_function): Add nested arg.
+	Tweek tests for function already generated.
+	(cgraph_expand_function): Don't double announce in !unit-at-a-time.
+	* cgraph.h (cgraph_finalize_function): Update for extra arg.
+	* c-decl.c (finish_function): Likewise.
+
 2003-09-10  Joe Buck  <jbuck@welsh-buck.org>
 
 	* c-decl.c (poplevel): Eliminate use of |= in function_body assignment.
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 26a012a021c60295ca57fdcf572814fc5575e105..1eb3482cc12d36114c4c0e87a4cbc849573a5f33 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -6144,7 +6144,7 @@ finish_function ()
   /* ??? Objc emits functions after finalizing the compilation unit.
      This should be cleaned up later and this conditional removed.  */
   if (!cgraph_global_info_ready)
-    cgraph_finalize_function (fndecl);
+    cgraph_finalize_function (fndecl, false);
   else
     c_expand_body (fndecl);
   current_function_decl = NULL;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 2e6e68918ec68c796600dd3a1103cf29a55a8906..3ec89b606592851a865a952bc9afd9b71b0271b2 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -168,7 +168,7 @@ void cgraph_varpool_finalize_decl (tree);
 bool cgraph_varpool_assemble_pending_decls (void);
 
 /* In cgraphunit.c  */
-void cgraph_finalize_function (tree);
+void cgraph_finalize_function (tree, bool);
 void cgraph_finalize_compilation_unit (void);
 void cgraph_create_edges (tree, tree);
 void cgraph_optimize (void);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index bb55d2d3e8cab0dedcef5803885613d8c8d7695b..3519359e9bf0fd8dc2f7afb73bcca433ea455d2b 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -106,7 +106,7 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
   /* "extern inline" functions are never output locally.  */
   if (DECL_EXTERNAL (decl))
     return false;
-  /* We want to emit COMDAT functions only when they turns out to be neccesary.  */
+  /* We want to emit COMDAT functions only when absolutely neccesary.  */
   if (DECL_COMDAT (decl))
     return false;
   if (!DECL_INLINE (decl)
@@ -142,34 +142,39 @@ cgraph_assemble_pending_functions (void)
   return output;
 }
 
-/* Analyze function once it is parsed.  Set up the local information
-   available - create cgraph edges for function calls via BODY.  */
+/* DECL has been parsed.  Take it, queue it, compile it at the whim of the
+   logic in effect.  If NESTED is true, then our caller cannot stand to have
+   the garbage collector run at the moment.  We would need to either create
+   a new GC context, or just not compile right now.  */
 
 void
-cgraph_finalize_function (tree decl)
+cgraph_finalize_function (tree decl, bool nested)
 {
   struct cgraph_node *node = cgraph_node (decl);
 
   if (node->local.finalized)
     {
       /* As an GCC extension we allow redefinition of the function.  The
-	 semantics when both copies of bodies differ is not well defined.  We
-	 replace the old body with new body so in unit at a time mode we always
-	 use new body, while in normal mode we may end up with old body inlined
-	 into some functions and new body expanded and inlined in others.
+	 semantics when both copies of bodies differ is not well defined.
+	 We replace the old body with new body so in unit at a time mode
+	 we always use new body, while in normal mode we may end up with
+	 old body inlined into some functions and new body expanded and
+	 inlined in others.
 	 
-	 ??? It may make more sense to use one body for inlining and other body
-	 for expanding the function but this is dificult to do.  */
-      /* Reset our datastructures so we can analyze the function body
-	 again.  */
+	 ??? It may make more sense to use one body for inlining and other
+	 body for expanding the function but this is dificult to do.  */
+
+      if (TREE_ASM_WRITTEN (decl))
+	abort ();
+
+      /* Reset our datastructures so we can analyze the function again.  */
       memset (&node->local, 0, sizeof (node->local));
       memset (&node->global, 0, sizeof (node->global));
       memset (&node->rtl, 0, sizeof (node->rtl));
       node->analyzed = false;
-      if (node->output)
-	abort ();
       while (node->callees)
 	cgraph_remove_call (node->decl, node->callees->callee->decl);
+
       /* We may need to re-queue the node for assembling in case
          we already proceeded it and ignored as not needed.  */
       if (node->reachable && !flag_unit_at_a_time)
@@ -183,6 +188,7 @@ cgraph_finalize_function (tree decl)
 	    node->reachable = 0;
 	}
     }
+
   notice_global_symbol (decl);
   node->decl = decl;
   node->local.finalized = true;
@@ -195,13 +201,13 @@ cgraph_finalize_function (tree decl)
   if (decide_is_function_needed (node, decl))
     cgraph_mark_needed_node (node);
 
-  /* If not unit at a time, go ahead and emit everything we've
-     found to be reachable at this time.  Do this only at top-level.  */
-  if (!node->origin)
+  /* If not unit at a time, go ahead and emit everything we've found
+     to be reachable at this time.  */
+  if (!nested)
     cgraph_assemble_pending_functions ();
 
   /* If we've not yet emitted decl, tell the debug info about it.  */
-  if (flag_unit_at_a_time || !node->reachable)
+  if (!TREE_ASM_WRITTEN (decl))
     (*debug_hooks->deferred_inline_function) (decl);
 }
 
@@ -465,7 +471,8 @@ cgraph_expand_function (struct cgraph_node *node)
   tree decl = node->decl;
   struct cgraph_edge *e;
 
-  announce_function (decl);
+  if (flag_unit_at_a_time)
+    announce_function (decl);
 
   cgraph_optimize_function (node);
 
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 4d53eb74e1a302ed23469d3fe4fc047db7ce5612..5c123b97bcb78e3f3070097b5a834c07d67cad22 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,8 @@
+2003-09-11  Richard Henderson  <rth@redhat.com>
+
+	* semantics.c (expand_or_defer_fn): Update for new
+	cgraph_finalize_function argument.
+
 2003-09-10  Richard Henderson  <rth@redhat.com>
 
 	* decl2.c (cxx_callgraph_analyze_expr): Mark argument unused.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 50923abb8e79852431bc86339d2fc8605849179a..b4ea1a18563f5dd3f493777e66d7fee76d97996c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2940,7 +2940,7 @@ expand_or_defer_fn (tree fn)
     import_export_decl (fn);
 
   /* Expand or defer, at the whim of the compilation unit manager.  */
-  cgraph_finalize_function (fn);
+  cgraph_finalize_function (fn, function_depth > 1);
 }
 
 /* Helper function for walk_tree, used by finish_function to override all
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 68841af41b12d765126517bdd4ff01d1c9a2abce..337c2b1066cc9a211aab68daaa991bf1969df033 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,8 @@
+2003-09-11  Richard Henderson  <rth@redhat.com>
+
+        * parse.y (source_end_java_method): Update for new
+        cgraph_finalize_function argument.
+
 2003-09-09  Richard Henderson  <rth@redhat.com>
 
         * parse.y (source_end_java_method): Update call to
diff --git a/gcc/java/parse.y b/gcc/java/parse.y
index 2a6abf56c18ca596a3c7584a29cc1859c43b382c..a5064e18465afde11729515f2a01f540ba5c5db6 100644
--- a/gcc/java/parse.y
+++ b/gcc/java/parse.y
@@ -7474,7 +7474,7 @@ source_end_java_method (void)
   /* In unit-at-a-time mode, don't expand the method yet.  */
   if (DECL_SAVED_TREE (fndecl) && flag_unit_at_a_time)
     {
-      cgraph_finalize_function (fndecl);
+      cgraph_finalize_function (fndecl, false);
       current_function_decl = NULL_TREE;
       java_parser_context_restore_global ();
       return;