------- Comment #13 from hubicka at ucw dot cz  2006-07-21 15:13 -------
Subject: Re:  [4.1/4.2 Regression] tree check ICE when attribute
externally_visible used

> 
> 
> ------- Comment #12 from mmitchel at gcc dot gnu dot org  2006-07-21 08:38 
> -------
> I think that Comment #10 shows that handle_externally_visible should not be
> registering things with cgraph, as we shouldn't ever have anything pointing at
> a re-declaration.

Hi,
in January I made patch for similar problem that simply deffers handling
of externally visible and used attributes after compilation unit is
finalized.  I am going to update it for current tree and re-test.  Does
it look safe?

Hi,
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?

2006-01-19  Jan Hubicka  <[EMAIL PROTECTED]>
        * craph.c (cgraph_varpool_nodes): Export.
        (decide_is_variable_needed): Do not worry about "used" attribute.
        * cgraph.h (cgraph_varpool_nodes): Declare.
        * cgraphunit.c (decide_is_function_needed): Do not worry about "used"
attribute
        (process_function_and_variable_attributes): New function.
        (cgraph_finalize_compilation_unit): Call it.
        * c-decl.c (finish_decl): Do not worry about used attribute.
        * c-common.c (handle_externally_visible_attribute): Only validate.

Index: cgraph.c
===================================================================
*** cgraph.c    (revision 109820)
--- cgraph.c    (working copy)
*************** static GTY((param_is (struct cgraph_varp
*** 132,138 ****
  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;
--- 132,138 ----
  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
*** 838,845 ****
  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
--- 838,844 ----
  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)
      return true;

    /* ??? If the assembler name is set by hand, it is possible to assemble
Index: cgraph.h
===================================================================
*** cgraph.h    (revision 109820)
--- cgraph.h    (working copy)
*************** extern GTY(()) struct cgraph_node *cgrap
*** 242,247 ****
--- 242,248 ----

  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 109820)
--- 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,204 ----
      }

    /* If the user told us it is used, then it must be so.  */
!   if (node->local.externally_visible)
      return true;

    /* ??? If the assembler name is set by hand, it is possible to assemble
*************** cgraph_analyze_function (struct cgraph_n
*** 906,911 ****
--- 905,950 ----
    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 (void)
+ {
+   struct cgraph_node *node;
+   struct cgraph_varpool_node *vnode;
+ 
+   for (node = cgraph_nodes; node; node = node->next)
+     {
+       tree decl = node->decl;
+       if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+       mark_decl_referenced (decl);
+       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; vnode = vnode->next)
+     {
+       tree decl = vnode->decl;
+       if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
+       mark_decl_referenced (decl);
+       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)
*** 916,925 ****
--- 955,965 ----
       intermodule optimization.  */
    static struct cgraph_node *first_analyzed;

+   process_function_and_variable_attributes ();
    finish_aliases_1 ();

    if (!flag_unit_at_a_time)
      {
        cgraph_output_pending_asms ();
        cgraph_assemble_pending_functions ();
        return;
Index: c-decl.c
===================================================================
*** c-decl.c    (revision 109820)
--- c-decl.c    (working copy)
*************** finish_decl (tree decl, tree init, tree 
*** 3498,3507 ****
        }
      }

-   /* 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)
      {
        if (!DECL_FILE_SCOPE_P (decl)
--- 3498,3503 ----
Index: c-common.c
===================================================================
*** c-common.c  (revision 109820)
--- c-common.c  (working copy)
*************** handle_externally_visible_attribute (tre
*** 4274,4293 ****
               "%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);
--- 4274,4282 ----
               "%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);


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27369

Reply via email to