summaryrefslogtreecommitdiff
path: root/gcc/cgraph.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-21 09:05:07 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-21 09:05:07 +0000
commitace7bf06484d2ef5ad7282097f908c23e7a2af7a (patch)
treedd1fa989c4b9cbacc321b6ccd5f44964b611f58f /gcc/cgraph.c
parent0fa03311f520ae07591fac64e637ff0804408ab1 (diff)
downloadgcc-ace7bf06484d2ef5ad7282097f908c23e7a2af7a.tar.gz
PR ipa/70018
* cgraph.c (cgraph_set_nothrow_flag_1): Rename to ... (set_nothrow_flag_1): ... this; handle interposition correctly; recurse on aliases and thunks. (cgraph_node::set_nothrow_flag): New. * ipa-pure-const.c (ignore_edge_for_nothrow): Ignore calls to functions compiled with non-call exceptions that binds to current def. (propagate_nothrow): Be safe WRT interposition. * cgraph.h (set_nothrow_flag): Update prototype. * g++.dg/ipa/nothrow-1.C: New testcase. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@235318 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r--gcc/cgraph.c63
1 files changed, 50 insertions, 13 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index d8cb5269510..d93a93988f1 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -2358,27 +2358,65 @@ cgraph_node::make_local (void)
/* Worker to set nothrow flag. */
-static bool
-cgraph_set_nothrow_flag_1 (cgraph_node *node, void *data)
+static void
+set_nothrow_flag_1 (cgraph_node *node, bool nothrow, bool non_call,
+ bool *changed)
{
cgraph_edge *e;
- TREE_NOTHROW (node->decl) = data != NULL;
-
- if (data != NULL)
- for (e = node->callers; e; e = e->next_caller)
- e->can_throw_external = false;
- return false;
+ if (nothrow && !TREE_NOTHROW (node->decl))
+ {
+ /* With non-call exceptions we can't say for sure if other function body
+ was not possibly optimized to stil throw. */
+ if (!non_call || node->binds_to_current_def_p ())
+ {
+ TREE_NOTHROW (node->decl) = true;
+ *changed = true;
+ for (e = node->callers; e; e = e->next_caller)
+ e->can_throw_external = false;
+ }
+ }
+ else if (!nothrow && TREE_NOTHROW (node->decl))
+ {
+ TREE_NOTHROW (node->decl) = false;
+ *changed = true;
+ }
+ ipa_ref *ref;
+ FOR_EACH_ALIAS (node, ref)
+ {
+ cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
+ if (!nothrow || alias->get_availability () > AVAIL_INTERPOSABLE)
+ set_nothrow_flag_1 (alias, nothrow, non_call, changed);
+ }
+ for (cgraph_edge *e = node->callers; e; e = e->next_caller)
+ if (e->caller->thunk.thunk_p
+ && (!nothrow || e->caller->get_availability () > AVAIL_INTERPOSABLE))
+ set_nothrow_flag_1 (e->caller, nothrow, non_call, changed);
}
/* Set TREE_NOTHROW on NODE's decl and on aliases of NODE
if any to NOTHROW. */
-void
+bool
cgraph_node::set_nothrow_flag (bool nothrow)
{
- call_for_symbol_thunks_and_aliases (cgraph_set_nothrow_flag_1,
- (void *)(size_t)nothrow, nothrow == true);
+ bool changed = false;
+ bool non_call = opt_for_fn (decl, flag_non_call_exceptions);
+
+ if (!nothrow || get_availability () > AVAIL_INTERPOSABLE)
+ set_nothrow_flag_1 (this, nothrow, non_call, &changed);
+ else
+ {
+ ipa_ref *ref;
+
+ FOR_EACH_ALIAS (this, ref)
+ {
+ cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
+ if (!nothrow || alias->get_availability () > AVAIL_INTERPOSABLE)
+ set_nothrow_flag_1 (alias, nothrow, non_call, &changed);
+ }
+ }
+ return changed;
}
/* Worker to set_const_flag. */
@@ -2517,8 +2555,7 @@ cgraph_node::set_const_flag (bool set_const, bool looping)
/* Info used by set_pure_flag_1. */
-struct
-set_pure_flag_info
+struct set_pure_flag_info
{
bool pure;
bool looping;