Patchwork Prevent 'control reaches end of non-void function' warning for DO_WHILE

login
register
mail settings
Submitter Tom de Vries
Date Dec. 9, 2011, 8:38 a.m.
Message ID <4EE1C91F.2020906@mentor.com>
Download mbox | patch
Permalink /patch/130320/
State New
Headers show

Comments

Tom de Vries - Dec. 9, 2011, 8:38 a.m.
Jakub,

This patch fixes the problem reported in
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25973#c4 .

The test-case listed there is:
...
struct Block
{
  public:
    Block();
    ~Block();
};

bool func( bool bar )
{
  Block block;
  bool foo = false;

  if( !foo || bar )
    do { return true; } while( 0 );
  else
    do { return false; } while( 0 );
}
...

For O0, a spurious warning is generated:
...
$ gcc -O0 -Wreturn-type block.C -S:
block.C: In function ‘bool func(bool)’:
block.C:17:1: warning: control reaches end of non-void function [-Wreturn-type]
...

Basically the patch tries to handle DO_STMT in block_may_fallthru, but since
it's a cp-tree.def tree, it's done via a language hook.

Improving block_may_fallthru helps code in gimplify.c:shortcut_cond_expr() to
prevent the superfluous warning:
...
  /* We only emit the jump over the else clause if we have to--if the
     then clause may fall through.  Otherwise we can wind up with a
     useless jump and a useless label at the end of gimplified code,
     which will cause us to think that this conditional as a whole
     falls through even if it doesn't.  If we then inline a function
     which ends with such a condition, that can cause us to issue an
     inappropriate warning about control reaching the end of a
     non-void function.  */
  jump_over_else = block_may_fallthru (then_);
...

Bootstrapped and reg-tested on x86_64.

OK for next stage1?

Thanks,
- Tom
Richard Guenther - Dec. 9, 2011, 9:45 a.m.
On Fri, Dec 9, 2011 at 9:38 AM, Tom de Vries <Tom_deVries@mentor.com> wrote:
> Jakub,
>
> This patch fixes the problem reported in
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25973#c4 .
>
> The test-case listed there is:
> ...
> struct Block
> {
>  public:
>    Block();
>    ~Block();
> };
>
> bool func( bool bar )
> {
>  Block block;
>  bool foo = false;
>
>  if( !foo || bar )
>    do { return true; } while( 0 );
>  else
>    do { return false; } while( 0 );
> }
> ...
>
> For O0, a spurious warning is generated:
> ...
> $ gcc -O0 -Wreturn-type block.C -S:
> block.C: In function ‘bool func(bool)’:
> block.C:17:1: warning: control reaches end of non-void function [-Wreturn-type]
> ...
>
> Basically the patch tries to handle DO_STMT in block_may_fallthru, but since
> it's a cp-tree.def tree, it's done via a language hook.
>
> Improving block_may_fallthru helps code in gimplify.c:shortcut_cond_expr() to
> prevent the superfluous warning:
> ...
>  /* We only emit the jump over the else clause if we have to--if the
>     then clause may fall through.  Otherwise we can wind up with a
>     useless jump and a useless label at the end of gimplified code,
>     which will cause us to think that this conditional as a whole
>     falls through even if it doesn't.  If we then inline a function
>     which ends with such a condition, that can cause us to issue an
>     inappropriate warning about control reaching the end of a
>     non-void function.  */
>  jump_over_else = block_may_fallthru (then_);
> ...
>
> Bootstrapped and reg-tested on x86_64.
>
> OK for next stage1?

Hm.  I would prefer if the gimplifier is fed GENERIC, not
GENERIC plus FE specific codes ... (both C and C++ do
"genericization" passes, but they actually do not transform
all code to GENERIC).  Can you check if it's easy enough to
lower DO_STMT during cp_genericize?

Thanks,
Richard.

> Thanks,
> - Tom
>

Patch

Index: gcc/langhooks-def.h
===================================================================
--- gcc/langhooks-def.h (revision 181172)
+++ gcc/langhooks-def.h (working copy)
@@ -79,6 +79,8 @@  extern tree lhd_omp_assignment (tree, tr
 struct gimplify_omp_ctx;
 extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *,
 					       tree);
+extern bool lhd_tree_may_fallthru (const_tree);
+
 
 #define LANG_HOOKS_NAME			"GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct lang_identifier)
@@ -118,6 +120,7 @@  extern void lhd_omp_firstprivatize_type_
 #define LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS	NULL
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP	false
 #define LANG_HOOKS_DEEP_UNSHARING	false
+#define LANG_HOOKS_TREE_MAY_FALLTHRU lhd_tree_may_fallthru
 
 /* Attribute hooks.  */
 #define LANG_HOOKS_ATTRIBUTE_TABLE		NULL
@@ -309,7 +312,8 @@  extern void lhd_end_section (void);
   LANG_HOOKS_EH_RUNTIME_TYPE, \
   LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS, \
   LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
-  LANG_HOOKS_DEEP_UNSHARING \
+  LANG_HOOKS_DEEP_UNSHARING, \
+  LANG_HOOKS_TREE_MAY_FALLTHRU \
 }
 
 #endif /* GCC_LANG_HOOKS_DEF_H */
Index: gcc/langhooks.h
===================================================================
--- gcc/langhooks.h (revision 181172)
+++ gcc/langhooks.h (working copy)
@@ -473,6 +473,10 @@  struct lang_hooks
      gimplification.  */
   bool deep_unsharing;
 
+  /* Return false if we cannot continue executing the immediately
+     following tree.  */
+  bool (*tree_may_fallthru) (const_tree);
+
   /* Whenever you add entries here, make sure you adjust langhooks-def.h
      and langhooks.c accordingly.  */
 };
Index: gcc/langhooks.c
===================================================================
--- gcc/langhooks.c (revision 181172)
+++ gcc/langhooks.c (working copy)
@@ -657,3 +657,12 @@  lhd_end_section (void)
       saved_section = NULL;
     }
 }
+
+/* Return false if we cannot continue executing the tree immediately
+   following T.  */
+
+bool
+lhd_tree_may_fallthru (const_tree t ATTRIBUTE_UNUSED)
+{
+  return true;
+}
Index: gcc/gimple-low.c
===================================================================
--- gcc/gimple-low.c (revision 181172)
+++ gcc/gimple-low.c (working copy)
@@ -32,6 +32,7 @@  along with GCC; see the file COPYING3.
 #include "function.h"
 #include "diagnostic-core.h"
 #include "tree-pass.h"
+#include "langhooks.h"
 
 /* The differences between High GIMPLE and Low GIMPLE are the
    following:
@@ -680,8 +681,11 @@  block_may_fallthru (const_tree block)
     case CLEANUP_POINT_EXPR:
       return block_may_fallthru (TREE_OPERAND (stmt, 0));
 
-    default:
+    case ERROR_MARK:
       return true;
+
+    default:
+      return lang_hooks.tree_may_fallthru (stmt);
     }
 }
 
Index: gcc/cp/cp-objcp-common.c
===================================================================
--- gcc/cp/cp-objcp-common.c (revision 181172)
+++ gcc/cp/cp-objcp-common.c (working copy)
@@ -305,4 +305,21 @@  cp_common_init_ts (void)
   MARK_TS_TYPED (CTOR_INITIALIZER);
 }
 
+/* Return false if we cannot continue executing the tree immediately
+   following T.  */
+
+bool
+cp_tree_may_fallthru (const_tree t)
+{
+  switch (TREE_CODE (t))
+    {
+    case DO_STMT:
+      /* If DO_BODY doesn't fall thru, then DO_STMT doesn't either.  */
+      return block_may_fallthru (DO_BODY (t));
+    default:
+      break;
+    }
+  return true;
+}
+
 #include "gt-cp-cp-objcp-common.h"
Index: gcc/cp/cp-objcp-common.h
===================================================================
--- gcc/cp/cp-objcp-common.h (revision 181172)
+++ gcc/cp/cp-objcp-common.h (working copy)
@@ -29,6 +29,7 @@  extern tree objcp_tsubst_copy_and_build
 
 extern bool cp_function_decl_explicit_p (tree decl);
 extern void cp_common_init_ts (void);
+extern bool cp_tree_may_fallthru (const_tree);
 
 /* Lang hooks that are shared between C++ and ObjC++ are defined here.  Hooks
    specific to C++ or ObjC++ go in cp/cp-lang.c and objcp/objcp-lang.c,
@@ -154,4 +155,7 @@  extern void cp_common_init_ts (void);
 #undef LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS
 #define LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS cp_protect_cleanup_actions
 
+#undef LANG_HOOKS_TREE_MAY_FALLTHRU
+#define LANG_HOOKS_TREE_MAY_FALLTHRU cp_tree_may_fallthru
+
 #endif /* GCC_CP_OBJCP_COMMON */
Index: gcc/testsuite/g++.dg/pr51264-4.C
===================================================================
--- /dev/null (new file)
+++ gcc/testsuite/g++.dg/pr51264-4.C (revision 0)
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O0 -Werror -Wreturn-type" } */
+
+/* Test-case from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25973#c4.  */
+
+struct Block
+{
+  public:
+    Block();
+    ~Block();
+};
+
+bool func( bool bar )
+{
+  Block block;
+  bool foo = false;
+
+  if( !foo || bar )
+    do { return true; } while( 0 );
+  else
+    do { return false; } while( 0 );
+}