------- 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