OSDN Git Service

PR c++/28250
[pf3gnuchains/gcc-fork.git] / gcc / cgraphunit.c
index 8a4d0ec..2568502 100644 (file)
@@ -198,8 +198,10 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
     }
 
   /* If the user told us it is used, then it must be so.  */
-  if (node->local.externally_visible
-      || lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+  if (node->local.externally_visible)
+    return true;
+
+  if (!flag_unit_at_a_time && lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
     return true;
 
   /* ??? If the assembler name is set by hand, it is possible to assemble
@@ -219,10 +221,10 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
      COMDAT functions that must be output only when they are needed.
 
      When not optimizing, also output the static functions. (see
-     PR25962), but don't do so for always_inline functions, functions
+     PR24561), but don't do so for always_inline functions, functions
      declared inline and nested functions.  These was optimized out
      in the original implementation and it is unclear whether we want
-     to change the behaviour here.  */
+     to change the behavior here.  */
   if (((TREE_PUBLIC (decl)
        || (!optimize && !node->local.disregard_inline_limits
            && !DECL_DECLARED_INLINE_P (decl)
@@ -281,6 +283,10 @@ cgraph_varpool_analyze_pending_decls (void)
 
       cgraph_varpool_first_unanalyzed_node = cgraph_varpool_first_unanalyzed_node->next_needed;
 
+      /* Compute the alignment early so function body expanders are
+        already informed about increased alignment.  */
+      align_variable (decl, 0);
+
       if (DECL_INITIAL (decl))
        {
          visited_nodes = pointer_set_create ();
@@ -413,11 +419,14 @@ cgraph_reset_node (struct cgraph_node *node)
 
   if (!flag_unit_at_a_time)
     {
-      struct cgraph_node *n;
+      struct cgraph_node *n, *next;
 
-      for (n = cgraph_nodes; n; n = n->next)
-       if (n->global.inlined_to == node)
-         cgraph_remove_node (n);
+      for (n = cgraph_nodes; n; n = next)
+       {
+         next = n->next;
+         if (n->global.inlined_to == node)
+           cgraph_remove_node (n);
+       }
     }
 
   cgraph_node_remove_callees (node);
@@ -933,15 +942,84 @@ cgraph_analyze_function (struct cgraph_node *node)
   current_function_decl = NULL;
 }
 
+/* Look for externally_visible and used attributes and mark cgraph nodes
+   accordingly.
+
+   We cannot mark the nodes at the point the attributes are processed (in
+   handle_*_attribute) because the copy of the declarations available at that
+   point may not be canonical.  For example, in:
+
+    void f();
+    void f() __attribute__((used));
+
+   the declaration we see in handle_used_attribute will be the second
+   declaration -- but the front end will subsequently merge that declaration
+   with the original declaration and discard the second declaration.
+
+   Furthermore, we can't mark these nodes in cgraph_finalize_function because:
+
+    void f() {}
+    void f() __attribute__((externally_visible));
+
+   is valid.
+
+   So, we walk the nodes at the end of the translation unit, applying the
+   attributes at that point.  */
+
+static void
+process_function_and_variable_attributes (struct cgraph_node *first,
+                                          struct cgraph_varpool_node *first_var)
+{
+  struct cgraph_node *node;
+  struct cgraph_varpool_node *vnode;
+
+  for (node = cgraph_nodes; node != first; node = node->next)
+    {
+      tree decl = node->decl;
+      if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+       {
+         mark_decl_referenced (decl);
+         if (node->local.finalized)
+            cgraph_mark_needed_node (node);
+       }
+      if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
+       {
+         if (node->local.finalized)
+           cgraph_mark_needed_node (node);
+         node->externally_visible = true;
+       }
+    }
+  for (vnode = cgraph_varpool_nodes; vnode != first_var; vnode = vnode->next)
+    {
+      tree decl = vnode->decl;
+      if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+       {
+         mark_decl_referenced (decl);
+         if (vnode->finalized)
+           cgraph_varpool_mark_needed_node (vnode);
+       }
+      if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
+       {
+         if (vnode->finalized)
+           cgraph_varpool_mark_needed_node (vnode);
+         vnode->externally_visible = true;
+       }
+    }
+}
+
 /* Analyze the whole compilation unit once it is parsed completely.  */
 
 void
 cgraph_finalize_compilation_unit (void)
 {
-  struct cgraph_node *node;
+  struct cgraph_node *node, *next;
   /* Keep track of already processed nodes when called multiple times for
      intermodule optimization.  */
   static struct cgraph_node *first_analyzed;
+  static struct cgraph_varpool_node *first_analyzed_var;
+
+  if (errorcount || sorrycount)
+    return;
 
   finish_aliases_1 ();
 
@@ -959,6 +1037,7 @@ cgraph_finalize_compilation_unit (void)
     }
 
   timevar_push (TV_CGRAPH);
+  process_function_and_variable_attributes (first_analyzed, first_analyzed_var);
   cgraph_varpool_analyze_pending_decls ();
   if (cgraph_dump_file)
     {
@@ -1018,9 +1097,10 @@ cgraph_finalize_compilation_unit (void)
   if (cgraph_dump_file)
     fprintf (cgraph_dump_file, "\nReclaiming functions:");
 
-  for (node = cgraph_nodes; node != first_analyzed; node = node->next)
+  for (node = cgraph_nodes; node != first_analyzed; node = next)
     {
       tree decl = node->decl;
+      next = node->next;
 
       if (node->local.finalized && !DECL_SAVED_TREE (decl))
        cgraph_reset_node (node);
@@ -1043,6 +1123,7 @@ cgraph_finalize_compilation_unit (void)
       dump_cgraph (cgraph_dump_file);
     }
   first_analyzed = cgraph_nodes;
+  first_analyzed_var = cgraph_varpool_nodes;
   ggc_collect ();
   timevar_pop (TV_CGRAPH);
 }
@@ -1388,6 +1469,9 @@ ipa_passes (void)
 void
 cgraph_optimize (void)
 {
+  if (errorcount || sorrycount)
+    return;
+
 #ifdef ENABLE_CHECKING
   verify_cgraph ();
 #endif
@@ -1462,7 +1546,6 @@ cgraph_optimize (void)
   /* Double check that all inline clones are gone and that all
      function bodies have been released from memory.  */
   if (flag_unit_at_a_time
-      && !dump_enabled_p (TDI_tree_all)
       && !(sorrycount || errorcount))
     {
       struct cgraph_node *node;