aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/c-common.c17
-rw-r--r--gcc/c-decl.c2
-rw-r--r--gcc/cgraph.c11
-rw-r--r--gcc/cgraph.h1
-rw-r--r--gcc/cgraphunit.c74
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.dg/pr25795-1.c10
-rw-r--r--gcc/testsuite/gcc.dg/pr25795.c10
9 files changed, 122 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 995e399..d23808d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2006-07-23 Jan Hubicka <jh@suse.cz>
+
+ PR c/25795
+ PR c++/27369
+ * cgraph.c (cgraph_varpool_nodes): Export.
+ (decide_is_variable_needed): Ignored "used" attribute in
+ unit-at-a-time mode.
+ * cgraph.h (cgraph_varpool_nodes): Declare.
+ * cgraphunit.c (decide_is_function_needed): Ignored "used" attribute in
+ unit-at-a-time mode.
+
2006-07-23 Roger Sayle <roger@eyesopen.com>
PR target/28247
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 9c26061..71f8ce6 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -4308,20 +4308,9 @@ handle_externally_visible_attribute (tree *pnode, tree name,
"%qE attribute have effect only on public objects", name);
*no_add_attrs = true;
}
- else if (TREE_CODE (node) == FUNCTION_DECL)
- {
- struct cgraph_node *n = cgraph_node (node);
- n->local.externally_visible = true;
- if (n->local.finalized)
- cgraph_mark_needed_node (n);
- }
- else if (TREE_CODE (node) == VAR_DECL)
- {
- struct cgraph_varpool_node *n = cgraph_varpool_node (node);
- n->externally_visible = true;
- if (n->finalized)
- cgraph_varpool_mark_needed_node (n);
- }
+ else if (TREE_CODE (node) == FUNCTION_DECL
+ || TREE_CODE (node) == VAR_DECL)
+ ;
else
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 6ad6a69..b900e8a 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -3554,7 +3554,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
}
/* If this was marked 'used', be sure it will be output. */
- if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+ if (!flag_unit_at_a_time && lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
mark_decl_referenced (decl);
if (TREE_CODE (decl) == TYPE_DECL)
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 04ff094..5dd0afb 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -137,7 +137,7 @@ static GTY((param_is (struct cgraph_varpool_node))) htab_t cgraph_varpool_hash;
struct cgraph_varpool_node *cgraph_varpool_nodes_queue, *cgraph_varpool_first_unanalyzed_node;
/* The linked list of cgraph varpool nodes. */
-static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes;
+struct cgraph_varpool_node *cgraph_varpool_nodes;
/* End of the varpool queue. Needs to be QTYed to work with PCH. */
static GTY(()) struct cgraph_varpool_node *cgraph_varpool_last_needed_node;
@@ -843,8 +843,10 @@ bool
decide_is_variable_needed (struct cgraph_varpool_node *node, tree decl)
{
/* If the user told us it is used, then it must be so. */
- if (node->externally_visible
- || lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+ if (node->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
@@ -861,7 +863,8 @@ decide_is_variable_needed (struct cgraph_varpool_node *node, tree decl)
/* Externally visible variables must be output. The exception is
COMDAT variables that must be output only when they are needed. */
- if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
+ if (TREE_PUBLIC (decl) && !flag_whole_program && !DECL_COMDAT (decl)
+ && !DECL_EXTERNAL (decl))
return true;
/* When not reordering top level variables, we have to assume that
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 3a1665f..31ddfe3 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -249,6 +249,7 @@ extern GTY(()) struct cgraph_node *cgraph_expand_queue;
extern GTY(()) struct cgraph_varpool_node *cgraph_varpool_first_unanalyzed_node;
extern GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes_queue;
+extern GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes;
extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
extern GTY(()) int cgraph_order;
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index d02ead5..c0e4149 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -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
@@ -937,6 +939,71 @@ 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
@@ -946,6 +1013,7 @@ cgraph_finalize_compilation_unit (void)
/* 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;
finish_aliases_1 ();
@@ -963,6 +1031,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)
{
@@ -1047,6 +1116,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);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 310564c..8e92c9b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2006-07-24 Jan Hubicka <jh@suse.cz>
+
+ PR c/25795
+ PR c++/27369
+ * gcc.dg/pr25795.c: New test.
+ * gcc.dg/pr25795-1.c: New test.
+
2006-07-23 Roger Sayle <roger@eyesopen.com>
* gcc.dg/fold-cond-1.c: Increase test case portability by checking
diff --git a/gcc/testsuite/gcc.dg/pr25795-1.c b/gcc/testsuite/gcc.dg/pr25795-1.c
new file mode 100644
index 0000000..e568b25
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr25795-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fwhole-program" } */
+/* { dg-final { scan-assembler-not "mystr" } } */
+
+
+extern const char *mystr; /* normally in a header */
+const char *mystr;
+main()
+{
+}
diff --git a/gcc/testsuite/gcc.dg/pr25795.c b/gcc/testsuite/gcc.dg/pr25795.c
new file mode 100644
index 0000000..decbe54
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr25795.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fwhole-program" } */
+/* { dg-final { scan-assembler "mystr" } } */
+
+
+extern const char *mystr; /* normally in a header */
+const char *mystr __attribute__ ((externally_visible));
+main()
+{
+}