}
/* 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
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)
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 ();
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);
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 ();
}
timevar_push (TV_CGRAPH);
+ process_function_and_variable_attributes (first_analyzed, first_analyzed_var);
cgraph_varpool_analyze_pending_decls ();
if (cgraph_dump_file)
{
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);
dump_cgraph (cgraph_dump_file);
}
first_analyzed = cgraph_nodes;
+ first_analyzed_var = cgraph_varpool_nodes;
ggc_collect ();
timevar_pop (TV_CGRAPH);
}
void
cgraph_optimize (void)
{
+ if (errorcount || sorrycount)
+ return;
+
#ifdef ENABLE_CHECKING
verify_cgraph ();
#endif
/* 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;