re PR middle-end/44206 (ICE: Inline clone with address taken)

PR middle-end/44206
	* g++.dg/torture/pr44206.C: New.
	* ipa.c (cgraph_remove_unreachable_nodes): Cleanup; check
	existence of refrences before removing the function.

From-SVN: r165569
This commit is contained in:
Jan Hubicka 2010-10-17 01:47:08 +02:00 committed by Jan Hubicka
parent ad62092738
commit bb85334960
4 changed files with 144 additions and 41 deletions

View File

@ -1,3 +1,9 @@
2010-10-16 Jan Hubicka <jh@suse.cz>
PR middle-end/44206
* ipa.c (cgraph_remove_unreachable_nodes): Cleanup; check
existence of refrences before removing the function.
2010-10-16 Jan Hubicka <jh@suse.cz>
* cgraph.c (dump_cgraph_node): Dump same_comdat_group,

153
gcc/ipa.c
View File

@ -384,22 +384,31 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
}
if (!node->aux)
{
struct cgraph_edge *e;
bool found = false;
int i;
struct ipa_ref *ref;
node->global.inlined_to = NULL;
if (file)
fprintf (file, " %s", cgraph_node_name (node));
if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
cgraph_remove_node (node);
else
/* See if there is reachable caller. */
for (e = node->callers; e && !found; e = e->next_caller)
if (e->caller->reachable)
found = true;
for (i = 0; (ipa_ref_list_refering_iterate (&node->ref_list, i, ref)
&& !found); i++)
if (ref->refering_type == IPA_REF_CGRAPH
&& ipa_ref_refering_node (ref)->reachable)
found = true;
else if (ref->refering_type == IPA_REF_VARPOOL
&& ipa_ref_refering_varpool_node (ref)->needed)
found = true;
/* If so, we need to keep node in the callgraph. */
if (found || node->needed)
{
struct cgraph_edge *e;
/* See if there is reachable caller. */
for (e = node->callers; e; e = e->next_caller)
if (e->caller->reachable)
break;
/* If so, we need to keep node in the callgraph. */
if (e || node->needed)
if (node->analyzed)
{
struct cgraph_node *clone;
@ -419,10 +428,10 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
node->clone_of->clones = node->next_sibling_clone;
if (node->next_sibling_clone)
node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
#ifdef ENABLE_CHECKING
#ifdef ENABLE_CHECKING
if (node->clone_of)
node->former_clone_of = node->clone_of->decl;
#endif
#endif
node->clone_of = NULL;
node->next_sibling_clone = NULL;
node->prev_sibling_clone = NULL;
@ -430,13 +439,16 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
else
gcc_assert (!clone->in_other_partition);
node->analyzed = false;
changed = true;
cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->ref_list);
}
else
cgraph_remove_node (node);
}
changed = true;
else
{
cgraph_remove_node (node);
changed = true;
}
}
}
for (node = cgraph_nodes; node; node = node->next)
@ -581,6 +593,7 @@ ipa_discover_readonly_nonaddressable_vars (void)
static bool
cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool aliased)
{
struct cgraph_node *alias;
if (!node->local.finalized)
return false;
if (!DECL_COMDAT (node->decl)
@ -595,6 +608,23 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
/* If linker counts on us, we must preserve the function. */
if (cgraph_used_from_object_file_p (node))
return true;
if (DECL_PRESERVE_P (node->decl))
return true;
if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
return true;
/* See if we have linker information about symbol not being used or
if we need to make guess based on the declaration.
Even if the linker clams the symbol is unused, never bring internal
symbols that are declared by user as used or externally visible.
This is needed for i.e. references from asm statements. */
for (alias = node->same_body; alias; alias = alias->next)
if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY)
break;
if (!alias && node->resolution == LDPR_PREVAILING_DEF_IRONLY)
return false;
/* When doing link time optimizations, hidden symbols become local. */
if (in_lto_p
&& (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
@ -626,11 +656,70 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
return true;
}
}
if (DECL_PRESERVE_P (node->decl))
return true;
if (MAIN_NAME_P (DECL_NAME (node->decl)))
return true;
if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
return false;
}
/* Return true when variable VNODE should be considered externally visible. */
static bool
varpool_externally_visible_p (struct varpool_node *vnode, bool aliased)
{
struct varpool_node *alias;
if (!DECL_COMDAT (vnode->decl) && !TREE_PUBLIC (vnode->decl))
return false;
/* Do not even try to be smart about aliased nodes. Until we properly
represent everything by same body alias, these are just evil. */
if (aliased)
return true;
/* If linker counts on us, we must preserve the function. */
if (varpool_used_from_object_file_p (vnode))
return true;
if (DECL_PRESERVE_P (vnode->decl))
return true;
if (lookup_attribute ("externally_visible",
DECL_ATTRIBUTES (vnode->decl)))
return true;
/* See if we have linker information about symbol not being used or
if we need to make guess based on the declaration.
Even if the linker clams the symbol is unused, never bring internal
symbols that are declared by user as used or externally visible.
This is needed for i.e. references from asm statements. */
if (varpool_used_from_object_file_p (vnode))
return true;
for (alias = vnode->extra_name; alias; alias = alias->next)
if (alias->resolution != LDPR_PREVAILING_DEF_IRONLY)
break;
if (!alias && vnode->resolution == LDPR_PREVAILING_DEF_IRONLY)
return false;
/* When doing link time optimizations, hidden symbols become local. */
if (in_lto_p
&& (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN
|| DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL)
/* Be sure that node is defined in IR file, not in other object
file. In that case we don't set used_from_other_object_file. */
&& vnode->finalized)
;
else if (!flag_whole_program)
return true;
/* Do not attempt to privatize COMDATS by default.
This would break linking with C++ libraries sharing
inline definitions.
FIXME: We can do so for readonly vars with no address taken and
possibly also for vtables since no direct pointer comparsion is done.
It might be interesting to do so to reduce linking overhead. */
if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl))
return true;
return false;
}
@ -786,27 +875,9 @@ function_and_variable_visibility (bool whole_program)
if (!vnode->finalized)
continue;
if (vnode->needed
&& (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
&& (((!whole_program
/* We can privatize comdat readonly variables whose address is
not taken, but doing so is not going to bring us
optimization oppurtunities until we start reordering
datastructures. */
|| DECL_COMDAT (vnode->decl)
|| DECL_WEAK (vnode->decl))
/* When doing linktime optimizations, all hidden symbols will
become local. */
&& (!in_lto_p
|| (DECL_VISIBILITY (vnode->decl) != VISIBILITY_HIDDEN
&& DECL_VISIBILITY (vnode->decl) != VISIBILITY_INTERNAL)
/* We can get prevailing decision in other object file.
In this case we do not sed used_from_object_file. */
|| !vnode->finalized))
|| DECL_PRESERVE_P (vnode->decl)
|| varpool_used_from_object_file_p (vnode)
|| pointer_set_contains (aliased_vnodes, vnode)
|| lookup_attribute ("externally_visible",
DECL_ATTRIBUTES (vnode->decl))))
&& varpool_externally_visible_p
(vnode,
pointer_set_contains (aliased_vnodes, vnode)))
vnode->externally_visible = true;
else
vnode->externally_visible = false;

View File

@ -1,3 +1,8 @@
2010-10-16 Jan Hubicka <jh@suse.cz>
PR middle-end/44206
* g++.dg/torture/pr44206.C: New.
2010-10-16 Nicola Pero <nicola.pero@meta-innovation.com>
* objc.dg/gnu-api-2-class.m: New.

View File

@ -0,0 +1,21 @@
// { dg-do compile }
template<int> struct A
{
void foo(void(*)(A));
void bar(void(*f)(A)) { foo(f); foo(f); }
};
template<int N> inline void FOO(A<N> a)
{
a.foo(0);
}
extern template void FOO(A<0>);
void BAR()
{
A<0> a;
FOO(a);
a.bar(FOO);
}