Hi, The attached patch emits warnings for functions found to be pure or const by the ipa-pure-const pass. It does not warn for functions with unused return values that have been declared as pure or const by the user since this is already handled in C and C++ FE's. I have split it into parts to individually address fallouts observed during bootstrap+test. I still have to add more test-cases. Apart from that does the patch look OK ?
Thanks, Prathamesh
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index a9570e4..3b8e774 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -226,6 +226,34 @@ warn_function_noreturn (tree decl) true, warned_about, "noreturn"); } +/* Emit diagnostic if the callers don't use return value. + Only to be called for pure/const function */ + +static void +warn_function_unused_ret (struct cgraph_node *node) +{ + tree decl = node->decl; + int flags = flags_from_decl_or_type (decl); + + if (flags & ECF_NORETURN) + return; + + if (!(flags & (ECF_CONST | ECF_PURE)) + || (flags & ECF_LOOPING_CONST_OR_PURE)) + return; + + for (cgraph_edge *e = node->callers; e; e = e->next_caller) + { + gcall *g = e->call_stmt; + if (g + && !VOID_TYPE_P (gimple_call_return_type (g)) + && gimple_call_lhs (g) == NULL) + warning_at (gimple_location (g), OPT_Wunused_value, + "Call from %s to %s has no effect", + e->caller->name (), e->callee->name ()); + } +} + /* Return true if we have a function state for NODE. */ static inline bool @@ -1475,6 +1503,8 @@ propagate_pure_const (void) /* Inline clones share declaration with their offline copies; do not modify their declarations since the offline copy may be different. */ + bool warn_unused_ret = false; + if (!w->global.inlined_to) switch (this_state) { @@ -1482,6 +1512,7 @@ propagate_pure_const (void) if (!TREE_READONLY (w->decl)) { warn_function_const (w->decl, !this_looping); + warn_unused_ret = true; if (dump_file) fprintf (dump_file, "Function found to be %sconst: %s\n", this_looping ? "looping " : "", @@ -1496,6 +1527,8 @@ propagate_pure_const (void) NULL, true); if (w->set_const_flag (true, this_looping)) { + if (warn_unused_ret) + warn_function_unused_ret (w); if (dump_file) fprintf (dump_file, "Declaration updated to be %sconst: %s\n", @@ -1509,6 +1542,7 @@ propagate_pure_const (void) if (!DECL_PURE_P (w->decl)) { warn_function_pure (w->decl, !this_looping); + warn_unused_ret = true; if (dump_file) fprintf (dump_file, "Function found to be %spure: %s\n", this_looping ? "looping " : "", @@ -1521,6 +1555,8 @@ propagate_pure_const (void) NULL, true); if (w->set_pure_flag (true, this_looping)) { + if (warn_unused_ret) + warn_function_unused_ret (w); if (dump_file) fprintf (dump_file, "Declaration updated to be %spure: %s\n", @@ -1808,11 +1844,14 @@ pass_local_pure_const::execute (function *fun) changed = true; } + bool warn_unused_ret = false; + switch (l->pure_const_state) { case IPA_CONST: if (!TREE_READONLY (current_function_decl)) { + warn_unused_ret = true; warn_function_const (current_function_decl, !l->looping); if (dump_file) fprintf (dump_file, "Function found to be %sconst: %s\n", @@ -1828,6 +1867,8 @@ pass_local_pure_const::execute (function *fun) } if (!skip && node->set_const_flag (true, l->looping)) { + if (warn_unused_ret) + warn_function_unused_ret (cgraph_node::get_create (current_function_decl)); if (dump_file) fprintf (dump_file, "Declaration updated to be %sconst: %s\n", l->looping ? "looping " : "", @@ -1840,6 +1881,7 @@ pass_local_pure_const::execute (function *fun) if (!DECL_PURE_P (current_function_decl)) { warn_function_pure (current_function_decl, !l->looping); + warn_unused_ret = true; if (dump_file) fprintf (dump_file, "Function found to be %spure: %s\n", l->looping ? "looping " : "", @@ -1854,6 +1896,8 @@ pass_local_pure_const::execute (function *fun) } if (!skip && node->set_pure_flag (true, l->looping)) { + if (warn_unused_ret) + warn_function_unused_ret (cgraph_node::get_create (current_function_decl)); if (dump_file) fprintf (dump_file, "Declaration updated to be %spure: %s\n", l->looping ? "looping " : "", diff --git a/gcc/testsuite/gcc.dg/Wunused-value-4.c b/gcc/testsuite/gcc.dg/Wunused-value-4.c new file mode 100644 index 0000000..1f5463c --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wunused-value-4.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wunused-value" } */ + +__attribute__((noinline, no_icf)) +int f() +{ + return 1; +} + +__attribute__((noinline, no_icf, const)) +int g() +{ + return 1; +} + +int foo (void) +{ + f (); /* { dg-warning "Call from foo to f has no effect" } */ + int k = f (); /* { dg-bogus "Call from foo to f has no effect" } */ + g (); /* { dg-warning "statement with no effect" } */ + return k; +} +