This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PR c++/27369 (externally_visible attribute ICE)


this is update of my earlier patch from January since the problem has turned
out to be a regression now.

at the present externally_visible on:
extern const char *mystr;	/* normally in a header */
const char *mystr __attribute__ ((externally_visible));
int
main (int argc, char **argv)
{
  mystr = argv[0];
  return (0);
}
is cowardly ignored.  This is because handle_externally_visible_attribute is
called before decl merging and it produce new cgraph node with
externally_visible flag that is never merged to real decl node.

externally_visible is in many ways symmetric to used attribute, so I looked on
how it is implemented, but found it somewhat sliperly to copy.
Used attribute is processed on cgraph_finalize_* machinery first, but since
it might be added retrospectivly, it is also processed by c frontend when merging decls
and finally it sets TREE_SYMBOL_REFERENCED flag that survive decl merging to
get the early used attributes right.  This is way too crazy and easy to break,
so I moved both attributes to new place - at the end of compilation the declarations
are travelled and we check whether the attributes are present.

Since this is miscompilation bug, I would like to see it solved in 4.1 too.
I wonder whether this scheme seems safe to others or if I should make less
intrusive approach?  (perhaps moving externally_visible only)

Bootstrapped/regtested i686-pc-gnu-linux, OK for mainline and possibly 4.1?

:ADDPATCH middle-end:

2006-07-23  Jan Hubicka  <jh@suse.cz>
	PR c/25795
	PR c++/27369
	* cgraph.c (cgraph_varpool_nodes): Export.
	(decide_is_variable_needed): Ignore "used" flag.
	(cgraph_varpool_nodes): Declare.
	(decide_is_function_needed): Likewise.
	(process_function_and_variable_attributes): New function.
	(cgraph_finalize_compilation_unit): Use it.
	* c-decl.c (finish_decl): Ignore used flag in non-unit-at-a-time.
	* c-common.c (handle_externally_visible_attribute): Don't register to cgraph early.
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 115677)
--- cgraph.c	(working copy)
*************** static GTY((param_is (struct cgraph_varp
*** 137,143 ****
  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;
  
  /* End of the varpool queue.  Needs to be QTYed to work with PCH.  */
  static GTY(()) struct cgraph_varpool_node *cgraph_varpool_last_needed_node;
--- 137,143 ----
  struct cgraph_varpool_node *cgraph_varpool_nodes_queue, *cgraph_varpool_first_unanalyzed_node;
  
  /* The linked list of 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;
*************** bool
*** 843,850 ****
  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)))
      return true;
  
    /* ??? If the assembler name is set by hand, it is possible to assemble
--- 843,851 ----
  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 (!flag_unit_at_a_time
!       && (node->externally_visible
!           || lookup_attribute ("used", DECL_ATTRIBUTES (decl))))
      return true;
  
    /* ??? If the assembler name is set by hand, it is possible to assemble
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 115677)
--- cgraph.h	(working copy)
*************** extern GTY(()) struct cgraph_node *cgrap
*** 249,254 ****
--- 249,255 ----
  
  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: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 115677)
--- cgraphunit.c	(working copy)
*************** decide_is_function_needed (struct cgraph
*** 198,205 ****
      }
  
    /* If the user told us it is used, then it must be so.  */
!   if (node->local.externally_visible
!       || lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
      return true;
  
    /* ??? If the assembler name is set by hand, it is possible to assemble
--- 198,207 ----
      }
  
    /* If the user told us it is used, then it must be so.  */
!   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
*************** cgraph_analyze_function (struct cgraph_n
*** 937,942 ****
--- 939,993 ----
    current_function_decl = NULL;
  }
  
+ /* Look for externally_visible and used attributes and mark cgraph nodes
+    accordingly.
+ 
+    This is not easilly doable earlier in handle_*_attribute because they might
+    be passed different copy of decl before merging.  We can't do that in
+    cgraph_finalize_function either because we want to allow defining the attributes
+    later, so we do that in separate pass at the end of unit.  */
+ 
+ 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)
*** 946,951 ****
--- 997,1003 ----
    /* 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 ();
  
*************** cgraph_finalize_compilation_unit (void)
*** 963,968 ****
--- 1015,1021 ----
      }
  
    timevar_push (TV_CGRAPH);
+   process_function_and_variable_attributes (first_analyzed, first_analyzed_var);
    cgraph_varpool_analyze_pending_decls ();
    if (cgraph_dump_file)
      {
*************** cgraph_finalize_compilation_unit (void)
*** 1047,1052 ****
--- 1100,1106 ----
        dump_cgraph (cgraph_dump_file);
      }
    first_analyzed = cgraph_nodes;
+   first_analyzed_var = cgraph_varpool_nodes;
    ggc_collect ();
    timevar_pop (TV_CGRAPH);
  }
Index: c-decl.c
===================================================================
*** c-decl.c	(revision 115677)
--- c-decl.c	(working copy)
*************** finish_decl (tree decl, tree init, tree 
*** 3554,3560 ****
      }
  
    /* If this was marked 'used', be sure it will be output.  */
!   if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
      mark_decl_referenced (decl);
  
    if (TREE_CODE (decl) == TYPE_DECL)
--- 3554,3560 ----
      }
  
    /* If this was marked 'used', be sure it will be output.  */
!   if (!flag_unit_at_a_time && lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
      mark_decl_referenced (decl);
  
    if (TREE_CODE (decl) == TYPE_DECL)
Index: c-common.c
===================================================================
*** c-common.c	(revision 115677)
--- c-common.c	(working copy)
*************** handle_externally_visible_attribute (tre
*** 4308,4327 ****
  	       "%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
      {
        warning (OPT_Wattributes, "%qE attribute ignored", name);
--- 4308,4316 ----
  	       "%qE attribute have effect only on public objects", name);
        *no_add_attrs = true;
      }
!   else if (TREE_CODE (node) == FUNCTION_DECL
! 	   || TREE_CODE (node) == VAR_DECL)
!     ;
    else
      {
        warning (OPT_Wattributes, "%qE attribute ignored", name);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]