This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PR c++/27369 (externally_visible attribute ICE)
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org, mark at codesourcery dot com
- Date: Sun, 23 Jul 2006 12:13:23 +0200
- Subject: 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);