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; 
+}
+

Reply via email to