OSDN Git Service

2005-06-12 Thomas Koenig <Thomas.Koenig@online.de>
[pf3gnuchains/gcc-fork.git] / gcc / cgraphunit.c
index ee859f7..2f993f3 100644 (file)
@@ -339,6 +339,59 @@ cgraph_assemble_pending_functions (void)
 
   return output;
 }
+/* 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.
+
+   ??? It may make more sense to use one body for inlining and other
+   body for expanding the function but this is difficult to do.  */
+
+static void
+cgraph_reset_node (struct cgraph_node *node)
+{
+  /* If node->output is set, then this is a unit-at-a-time compilation
+     and we have already begun whole-unit analysis.  This is *not*
+     testing for whether we've already emitted the function.  That
+     case can be sort-of legitimately seen with real function 
+     redefinition errors.  I would argue that the front end should
+     never present us with such a case, but don't enforce that for now.  */
+  gcc_assert (!node->output);
+
+  /* Reset our data structures 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;
+  node->local.redefined_extern_inline = true;
+  node->local.finalized = false;
+
+  if (!flag_unit_at_a_time)
+    {
+      struct cgraph_node *n;
+
+      for (n = cgraph_nodes; n; n = n->next)
+       if (n->global.inlined_to == node)
+         cgraph_remove_node (n);
+    }
+
+  cgraph_node_remove_callees (node);
+
+  /* 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)
+    {
+      struct cgraph_node *n;
+
+      for (n = cgraph_nodes_queue; n; n = n->next_needed)
+       if (n == node)
+         break;
+      if (!n)
+       node->reachable = 0;
+    }
+}
 
 /* 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
@@ -351,56 +404,7 @@ 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.
-        
-        ??? It may make more sense to use one body for inlining and other
-        body for expanding the function but this is difficult to do.  */
-
-      /* If node->output is set, then this is a unit-at-a-time compilation
-        and we have already begun whole-unit analysis.  This is *not*
-        testing for whether we've already emitted the function.  That
-        case can be sort-of legitimately seen with real function 
-        redefinition errors.  I would argue that the front end should
-        never present us with such a case, but don't enforce that for now.  */
-      gcc_assert (!node->output);
-
-      /* Reset our data structures 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;
-      node->local.redefined_extern_inline = true;
-
-      if (!flag_unit_at_a_time)
-       {
-         struct cgraph_node *n;
-
-         for (n = cgraph_nodes; n; n = n->next)
-           if (n->global.inlined_to == node)
-             cgraph_remove_node (n);
-       }
-
-      cgraph_node_remove_callees (node);
-
-      /* 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)
-       {
-         struct cgraph_node *n;
-
-         for (n = cgraph_nodes_queue; n; n = n->next_needed)
-           if (n == node)
-             break;
-         if (!n)
-           node->reachable = 0;
-       }
-    }
+    cgraph_reset_node (node);
 
   notice_global_symbol (decl);
   node->decl = decl;
@@ -421,7 +425,7 @@ cgraph_finalize_function (tree decl, bool nested)
   if (decide_is_function_needed (node, decl))
     cgraph_mark_needed_node (node);
 
-  /* Since we reclaim unrechable nodes at the end of every language
+  /* Since we reclaim unreachable nodes at the end of every language
      level unit, we need to be conservative about possible entry points
      there.  */
   if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
@@ -539,26 +543,19 @@ cgraph_create_edges (struct cgraph_node *node, tree body)
          walk_tree (bsi_stmt_ptr (bsi), record_reference, node, visited_nodes);
       }
 
-  /* Walk over any private statics that may take addresses of functions.  */
-  if (TREE_CODE (DECL_INITIAL (body)) == BLOCK)
+  /* Look for initializers of constant variables and private statics.  */
+  for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list;
+       step;
+       step = TREE_CHAIN (step))
     {
-      for (step = BLOCK_VARS (DECL_INITIAL (body));
-          step;
-          step = TREE_CHAIN (step))
-       if (DECL_INITIAL (step))
-         walk_tree (&DECL_INITIAL (step), record_reference, node, visited_nodes);
+      tree decl = TREE_VALUE (step);
+      if (TREE_CODE (decl) == VAR_DECL
+         && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+         && flag_unit_at_a_time)
+       cgraph_varpool_finalize_decl (decl);
+      else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
+       walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
     }
-
-  /* Also look here for private statics.  */
-  if (DECL_STRUCT_FUNCTION (body))
-    for (step = DECL_STRUCT_FUNCTION (body)->unexpanded_var_list;
-        step;
-        step = TREE_CHAIN (step))
-      {
-       tree decl = TREE_VALUE (step);
-       if (DECL_INITIAL (decl) && TREE_STATIC (decl))
-         walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
-      }
     
   pointer_set_destroy (visited_nodes);
   visited_nodes = NULL;
@@ -739,6 +736,14 @@ cgraph_varpool_assemble_pending_decls (void)
       if (!TREE_ASM_WRITTEN (decl) && !node->alias && !DECL_EXTERNAL (decl))
        {
          assemble_variable (decl, 0, 1, 0);
+         /* Local static variables are never seen by check_global_declarations
+            so we need to output debug info by hand.  */
+         if (decl_function_context (decl) && errorcount == 0 && sorrycount == 0)
+           {
+             timevar_push (TV_SYMOUT);
+             (*debug_hooks->global_decl) (decl);
+             timevar_pop (TV_SYMOUT);
+           }
          changed = true;
        }
       node->next_needed = NULL;
@@ -837,7 +842,10 @@ cgraph_finalize_compilation_unit (void)
         weak alias attribute to kill its body. See
         gcc.c-torture/compile/20011119-1.c  */
       if (!DECL_SAVED_TREE (decl))
-       continue;
+       {
+         cgraph_reset_node (node);
+         continue;
+       }
 
       gcc_assert (!node->analyzed && node->reachable);
       gcc_assert (DECL_SAVED_TREE (decl));
@@ -870,14 +878,20 @@ cgraph_finalize_compilation_unit (void)
     {
       tree decl = node->decl;
 
+      if (node->local.finalized && !DECL_SAVED_TREE (decl))
+        cgraph_reset_node (node);
+
       if (!node->reachable && DECL_SAVED_TREE (decl))
        {
          if (cgraph_dump_file)
            fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
          cgraph_remove_node (node);
+         continue;
        }
       else
        node->next_needed = NULL;
+      gcc_assert (!node->local.finalized || DECL_SAVED_TREE (decl));
+      gcc_assert (node->analyzed == node->local.finalized);
     }
   if (cgraph_dump_file)
     {
@@ -1048,6 +1062,7 @@ cgraph_function_and_variable_visibility (void)
        node->local.externally_visible = 1;
       node->local.local = (!node->needed
                           && node->analyzed
+                          && !DECL_EXTERNAL (node->decl)
                           && !node->local.externally_visible);
     }
   for (vnode = cgraph_varpool_nodes_queue; vnode; vnode = vnode->next_needed)