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:
parent
ad62092738
commit
bb85334960
4 changed files with 144 additions and 41 deletions
|
@ -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
153
gcc/ipa.c
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
21
gcc/testsuite/g++.dg/torture/pr44206.C
Normal file
21
gcc/testsuite/g++.dg/torture/pr44206.C
Normal 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);
|
||||
}
|
Loading…
Add table
Reference in a new issue