re PR c/25795 (Proccessing the attribute externally_visible too early)
authorJan Hubicka <jh@suse.cz>
Mon, 24 Jul 2006 00:16:16 +0000 (02:16 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 24 Jul 2006 00:16:16 +0000 (00:16 +0000)
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.

* gcc.dg/pr25795.c: New test.
* gcc.dg/pr25795-1.c: New test.

From-SVN: r115693

gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/cgraph.c
gcc/cgraph.h
gcc/cgraphunit.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr25795-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr25795.c [new file with mode: 0644]

index 995e399933493e57743a73949f7befc0926e83f6..d23808d345c38627a9d78f4591e61ae794a56ae4 100644 (file)
@@ -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
index 9c260615fd710ce7ca791589b1f78c47229e30c9..71f8ce689fd5a085f14a6e6b03742c7c48cd4929 100644 (file)
@@ -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);
index 6ad6a695d08964e071d5c3d35a26061dc235b6da..b900e8a8d5d1399ced1ce17bf8eeeb9568615403 100644 (file)
@@ -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)
index 04ff09452cdd2ae53b0faf9dd5833e665c8236df..5dd0afb24cbb98175e0ebcd0507a4085090148e3 100644 (file)
@@ -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
index 3a1665f90a3eb9347bd0da527bc51f8419b9388a..31ddfe37d0ae3c874c1c40c00cdc07e744fcaf7e 100644 (file)
@@ -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;
 
index d02ead5fcff1167908979e85d037e5aac02483e4..c0e41495ac9eb84b1ace10e80f65b680860e718c 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
@@ -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);
 }
index 310564c6e7994437f9f83aef13c6b03f01de7ad1..8e92c9bcb66afb979d86cad39b309c806d8df571 100644 (file)
@@ -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 (file)
index 0000000..e568b25
--- /dev/null
@@ -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 (file)
index 0000000..decbe54
--- /dev/null
@@ -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()
+{
+}