Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2012-04-17 Thread Jason Merrill

OK, thanks.

Jason


Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2012-04-17 Thread Tom de Vries
On 16/04/12 16:23, Jason Merrill wrote:
> On 04/14/2012 05:43 PM, Tom de Vries wrote:
>>  +  tree expr = NULL;
>>  +  append_to_statement_list (*block,&expr);
>>  +  *block = expr;

  Rather than doing this dance here, I think it would be better to enhance
  append_to_statement_list to handle the case of the list argument being a
  non-list.

>> Added return value to append_to_statement_list, so now it's:
>>
>> *block = append_to_statement_list (*block, NULL);
> 
> That's different from what I was suggesting; if the list argument is a 
> pointer to a non-list, we can build up a list for at at that time, so we 
> don't need the
> 
>> +  *block = append_to_statement_list (*block, NULL);
> 
> line at all; when we see
> 
>> +  append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
>> +block);
> 
> if *block isn't a STATEMENT_LIST we just make the necessary adjustments.
> 

I see. Patch adapted, bootstrapped and reg-tested on x86_64.

ok for trunk?

Thanks,
- Tom

> Jason

2012-04-17  Tom de Vries  

* tree-iterator.c (append_to_statement_list_1): Handle case that *list_p
is not a STMT_LIST.

* cp-gimplify.c (begin_bc_block): Add location parameter and use as
location argument to create_artificial_label.
(finish_bc_block): Change return type to void.  Remove body_seq
parameter, and add block parameter.  Append label to STMT_LIST and
return in block.
(gimplify_cp_loop, gimplify_for_stmt, gimplify_while_stmt)
(gimplify_do_stmt, gimplify_switch_stmt): Remove function.
(genericize_cp_loop, genericize_for_stmt, genericize_while_stmt)
(genericize_do_stmt, genericize_switch_stmt, genericize_continue_stmt)
(genericize_break_stmt, genericize_omp_for_stmt): New function.
(cp_gimplify_omp_for): Remove bc_continue processing.
(cp_gimplify_expr): Genericize VEC_INIT_EXPR.
(cp_gimplify_expr): Mark FOR_STMT, WHILE_STMT, DO_STMT, SWITCH_STMT,
CONTINUE_STMT, and BREAK_STMT as unreachable.
(cp_genericize_r): Genericize FOR_STMT, WHILE_STMT, DO_STMT,
SWITCH_STMT, CONTINUE_STMT, BREAK_STMT and OMP_FOR.
(cp_genericize_tree): New function, factored out of ...
(cp_genericize): ... this function.

* g++.dg/pr51264-4.C: New test.
Index: gcc/tree-iterator.c
===
--- gcc/tree-iterator.c (revision 185028)
+++ gcc/tree-iterator.c (working copy)
@@ -74,6 +74,13 @@ append_to_statement_list_1 (tree t, tree
 	}
   *list_p = list = alloc_stmt_list ();
 }
+  else if (TREE_CODE (list) != STATEMENT_LIST)
+{
+  tree first = list;
+  *list_p = list = alloc_stmt_list ();
+  i = tsi_last (list);
+  tsi_link_after (&i, first, TSI_CONTINUE_LINKING);
+}
 
   i = tsi_last (list);
   tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
Index: gcc/cp/cp-gimplify.c
===
--- gcc/cp/cp-gimplify.c (revision 185028)
+++ gcc/cp/cp-gimplify.c (working copy)
@@ -34,6 +34,11 @@ along with GCC; see the file COPYING3.
 #include "flags.h"
 #include "splay-tree.h"
 
+/* Forward declarations.  */
+
+static tree cp_genericize_r (tree *, int *, void *);
+static void cp_genericize_tree (tree*);
+
 /* Local declarations.  */
 
 enum bc_t { bc_break = 0, bc_continue = 1 };
@@ -45,37 +50,36 @@ static tree bc_label[2];
 /* Begin a scope which can be exited by a break or continue statement.  BC
indicates which.
 
-   Just creates a label and pushes it into the current context.  */
+   Just creates a label with location LOCATION and pushes it into the current
+   context.  */
 
 static tree
-begin_bc_block (enum bc_t bc)
+begin_bc_block (enum bc_t bc, location_t location)
 {
-  tree label = create_artificial_label (input_location);
+  tree label = create_artificial_label (location);
   DECL_CHAIN (label) = bc_label[bc];
   bc_label[bc] = label;
   return label;
 }
 
 /* Finish a scope which can be exited by a break or continue statement.
-   LABEL was returned from the most recent call to begin_bc_block.  BODY is
+   LABEL was returned from the most recent call to begin_bc_block.  BLOCK is
an expression for the contents of the scope.
 
If we saw a break (or continue) in the scope, append a LABEL_EXPR to
-   body.  Otherwise, just forget the label.  */
+   BLOCK.  Otherwise, just forget the label.  */
 
-static gimple_seq
-finish_bc_block (enum bc_t bc, tree label, gimple_seq body)
+static void
+finish_bc_block (tree *block, enum bc_t bc, tree label)
 {
   gcc_assert (label == bc_label[bc]);
 
   if (TREE_USED (label))
-{
-  gimple_seq_add_stmt (&body, gimple_build_label (label));
-}
+append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
+			  block);
 
   bc_label[bc] = DECL_CHAIN (label);
   DECL_CHAIN (label) = NULL_TREE;
- 

Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2012-04-16 Thread Jason Merrill

On 04/14/2012 05:43 PM, Tom de Vries wrote:

>>  +  tree expr = NULL;
>>  +  append_to_statement_list (*block,&expr);
>>  +  *block = expr;

>
>  Rather than doing this dance here, I think it would be better to enhance
>  append_to_statement_list to handle the case of the list argument being a
>  non-list.
>

Added return value to append_to_statement_list, so now it's:

*block = append_to_statement_list (*block, NULL);


That's different from what I was suggesting; if the list argument is a 
pointer to a non-list, we can build up a list for at at that time, so we 
don't need the



+  *block = append_to_statement_list (*block, NULL);


line at all; when we see


+  append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
+   block);


if *block isn't a STATEMENT_LIST we just make the necessary adjustments.

Jason


Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2012-04-14 Thread Tom de Vries
Jason,

On 18/02/12 09:33, Jason Merrill wrote:
> On 01/22/2012 03:38 AM, Tom de Vries wrote:
> 
> Sorry I didn't notice this patch until now; please CC me on C++ patches, 
> or at least mention C++ in the subject line.
> 

OK, will do.

>> +  tree expr = NULL;
>> +  append_to_statement_list (*block, &expr);
>> +  *block = expr;
> 
> Rather than doing this dance here, I think it would be better to enhance 
> append_to_statement_list to handle the case of the list argument being a 
> non-list.
> 

Added return value to append_to_statement_list, so now it's:

*block = append_to_statement_list (*block, NULL);

>> +  cp_walk_tree (&incr, cp_genericize_r, data, NULL);
>>
>> +  if (incr && EXPR_P (incr))
>> +SET_EXPR_LOCATION (incr, start_locus);
> 
> It might be better to set the location on incr before genericizing, so 
> that the location can trickle down.
> 

I see. I reordered the code.

>> + t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break));
>> + SET_EXPR_LOCATION (t, start_locus);
> 
> Here you can use build1_loc instead of two separate statements.
> 

Done.

>> -  /* If we use a LOOP_EXPR here, we have to feed the whole thing
>> -back through the main gimplifier to lower it.  Given that we
>> -have to gimplify the loop body NOW so that we can resolve
>> -break/continue stmts, seems easier to just expand to gotos.  */
> 
> Since we're now lowering the loop at genericize time rather than 
> gimplify, what's the rationale for not using LOOP_EXPR/EXIT_EXPR?  We 
> should still say something here.  I suppose the rationale is that the C 
> front end currently goes straight to gotos.
> 

I think we could indeed use LOOP_EXPR/EXIT_EXPR. I'm not sure what the gain
would be, since at least for C it would be a construct alive only between
genericize and gimplify. But I guess it makes sense from orthogonality point of
view.

Added a comment with todo.

>>   if (cond != error_mark_node)
>> {
>> - gimplify_expr (&cond, &exit_seq, NULL, is_gimple_val, 
>> fb_rvalue);
>> - stmt = gimple_build_cond (NE_EXPR, cond,
>> -   build_int_cst (TREE_TYPE (cond), 0),
>> -   gimple_label_label (top),
>> -   get_bc_label (bc_break));
>> - gimple_seq_add_stmt (&exit_seq, stmt);
>> + cond = build2 (NE_EXPR, boolean_type_node, cond,
>> +build_int_cst (TREE_TYPE (cond), 0));
> 
> I don't think we still need this extra comparison to 0, that seems like 
> a gimple-specific thing.
> 

OK, removed.

>>if (FOR_INIT_STMT (stmt))
>> +append_to_statement_list (FOR_INIT_STMT (stmt), &expr);
>>
>> +  genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt),
>> + FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, 
>> data);
> 
> The call to genericize_cp_loop will clear *walk_subtrees, which means we 
> don't genericize the FOR_INIT_STMT.
> 

I see. Added call to cp_generize_r.

>> +  tree jump = build_and_jump (&label);
> 
> Again, let's use build1_loc.
> 

Done.

>> +  *stmt_p = build_and_jump (&label);
>> +  SET_EXPR_LOCATION (*stmt_p, location);
> 
> And here.
> 

Done.

>> +  stmt = make_node (OMP_FOR);
> 
> Why make a new OMP_FOR rather than repurpose the one we already have? 
> We've already modified its operands.
> 

Done.

Bootstrapped and reg-tested on x86_64.

OK for trunk?

Thanks,
- Tom

> Jason

2012-04-14  Tom de Vries  

* tree-iterator.c (append_to_statement_list_1, append_to_statement_list)
(append_to_statement_list_force): Return resulting list.  Handle
list_p == NULL.
* tree-iterator.h (append_to_statement_list)
(append_to_statement_list_force): Add tree return type.

* cp-gimplify.c (begin_bc_block): Add location parameter and use as
location argument to create_artificial_label.
(finish_bc_block): Change return type to void.  Remove body_seq
parameter, and add block parameter.  Append label to STMT_LIST and
return in block.
(gimplify_cp_loop, gimplify_for_stmt, gimplify_while_stmt)
(gimplify_do_stmt, gimplify_switch_stmt): Remove function.
(genericize_cp_loop, genericize_for_stmt, genericize_while_stmt)
(genericize_do_stmt, genericize_switch_stmt, genericize_continue_stmt)
(genericize_break_stmt, genericize_omp_for_stmt): New function.
(cp_gimplify_omp_for): Remove bc_continue processing.
(cp_gimplify_expr): Genericize VEC_INIT_EXPR.
(cp_gimplify_expr): Mark FOR_STMT, WHILE_STMT, DO_STMT, SWITCH_STMT,
CONTINUE_STMT, and BREAK_STMT as unreachable.
(cp_genericize_r): Genericize FOR_STMT, WHILE_STMT, DO_STMT,
SWITCH_STMT, CONTINUE_STMT, BREAK_STMT and OMP_FOR.
(cp_genericize_tree): New function, factored out of ...
(cp_genericize): ... this

Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2012-02-18 Thread Jason Merrill

On 01/22/2012 03:38 AM, Tom de Vries wrote:

Sorry I didn't notice this patch until now; please CC me on C++ patches, 
or at least mention C++ in the subject line.



+  tree expr = NULL;
+  append_to_statement_list (*block, &expr);
+  *block = expr;


Rather than doing this dance here, I think it would be better to enhance 
append_to_statement_list to handle the case of the list argument being a 
non-list.



+  cp_walk_tree (&incr, cp_genericize_r, data, NULL);

+  if (incr && EXPR_P (incr))
+SET_EXPR_LOCATION (incr, start_locus);


It might be better to set the location on incr before genericizing, so 
that the location can trickle down.



+ t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break));
+ SET_EXPR_LOCATION (t, start_locus);


Here you can use build1_loc instead of two separate statements.


-  /* If we use a LOOP_EXPR here, we have to feed the whole thing
-back through the main gimplifier to lower it.  Given that we
-have to gimplify the loop body NOW so that we can resolve
-break/continue stmts, seems easier to just expand to gotos.  */


Since we're now lowering the loop at genericize time rather than 
gimplify, what's the rationale for not using LOOP_EXPR/EXIT_EXPR?  We 
should still say something here.  I suppose the rationale is that the C 
front end currently goes straight to gotos.



  if (cond != error_mark_node)
{
- gimplify_expr (&cond, &exit_seq, NULL, is_gimple_val, fb_rvalue);
- stmt = gimple_build_cond (NE_EXPR, cond,
-   build_int_cst (TREE_TYPE (cond), 0),
-   gimple_label_label (top),
-   get_bc_label (bc_break));
- gimple_seq_add_stmt (&exit_seq, stmt);
+ cond = build2 (NE_EXPR, boolean_type_node, cond,
+build_int_cst (TREE_TYPE (cond), 0));


I don't think we still need this extra comparison to 0, that seems like 
a gimple-specific thing.



   if (FOR_INIT_STMT (stmt))
+append_to_statement_list (FOR_INIT_STMT (stmt), &expr);

+  genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt),
+ FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, data);


The call to genericize_cp_loop will clear *walk_subtrees, which means we 
don't genericize the FOR_INIT_STMT.



+  tree jump = build_and_jump (&label);


Again, let's use build1_loc.


+  *stmt_p = build_and_jump (&label);
+  SET_EXPR_LOCATION (*stmt_p, location);


And here.


+  stmt = make_node (OMP_FOR);


Why make a new OMP_FOR rather than repurpose the one we already have? 
We've already modified its operands.


Jason


Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2012-01-22 Thread Tom de Vries
On 09/12/11 10:45, Richard Guenther wrote:
> On Fri, Dec 9, 2011 at 9:38 AM, Tom de Vries  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]
>> ...
>>

> 
> 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?

Richard,

I implement this approach in attached patch.

Bootstrapped and reg-tested on x86_64. OK for stage1? I would guess this patch
is too intrusive for stage4.

Furthermore, should I put PR c++/25973 in the log? The patch fixes the testcase
in comment 4, but doesn't seem related to the example listed in the description
field of the PR.

Thanks,
- Tom

2012-01-22  Tom de Vries  

* cp-gimplify.c (begin_bc_block): Add location parameter and use as
location argument to create_artificial_label.
(finish_bc_block): Change return type to void.  Remove body_seq
parameter, and add block parameter.  Append label to STMT_LIST and
return in block.
(gimplify_cp_loop, gimplify_for_stmt, gimplify_while_stmt)
(gimplify_do_stmt, gimplify_switch_stmt): Remove function.
(genericize_cp_loop, genericize_for_stmt, genericize_while_stmt)
(genericize_do_stmt, genericize_switch_stmt, genericize_continue_stmt)
(genericize_break_stmt, genericize_omp_for_stmt): New function.
(cp_gimplify_omp_for): Remove bc_continue processing.
(cp_gimplify_expr): Genericize VEC_INIT_EXPR.
(cp_gimplify_expr): Mark FOR_STMT, WHILE_STMT, DO_STMT, SWITCH_STMT,
CONTINUE_STMT, and BREAK_STMT as unreachable.
(cp_genericize_r): Genericize FOR_STMT, WHILE_STMT, DO_STMT,
SWITCH_STMT, CONTINUE_STMT, BREAK_STMT and OMP_FOR.
(cp_genericize_tree): New function, factored out of ...
(cp_genericize): ... this function.

* g++.dg/pr51264-4.C: New test.
Index: gcc/cp/cp-gimplify.c
===
--- gcc/cp/cp-gimplify.c (revision 183325)
+++ gcc/cp/cp-gimplify.c (working copy)
@@ -34,6 +34,11 @@ along with GCC; see the file COPYING3.
 #include "flags.h"
 #include "splay-tree.h"
 
+/* Forward declarations.  */
+
+static tree cp_genericize_r (tree *, int *, void *);
+static void cp_genericize_tree (tree*);
+
 /* Local declarations.  */
 
 enum bc_t { bc_break = 0, bc_continue = 1 };
@@ -45,37 +50,42 @@ static tree bc_label[2];
 /* Begin a scope which can be exited by a break or continue statement.  BC
indicates which.
 
-   Just creates a label and pushes it into the current context.  */
+   Just creates a label with location LOCATION and pushes it into the current
+   context.  */
 
 static tree
-begin_bc_block (enum bc_t bc)
+begin_bc_block (enum bc_t bc, location_t location)
 {
-  tree label = create_artificial_label (input_location);
+  tree label = create_artificial_label (location);
   DECL_CHAIN (label) = bc_label[bc];
   bc_label[bc] = label;
   return label;
 }
 
 /* Finish a scope which can be exited by a break or continue statement.
-   LABEL was returned from the most recent call to begin_bc_block.  BODY is
+   LABEL was returned from the most recent call to begin_bc_block.  BLOCK is
an expression for the contents of the scope.
 
If we saw a break (or continue) in the scope, append a LABEL_EXPR to
-   body.  Otherwise, just forget the label.  */
+   BLOCK.  Otherwise, just forget the label.  */
 
-static gimple_seq
-finish_bc_block (enum bc_t bc, tree label, gimple_seq body)
+static void
+finish_bc_block (tree *block, enum bc_t bc, tree label)
 {
   gcc_assert (label == bc_label[bc]);
 
   if (TREE_USED (label))
 {
-  gimple_seq_add_stmt (&body, gimple_build_label (label));
+  tree expr = NULL;
+  append_to_statement_list (*block, &expr);
+  *block = expr;
+
+  append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
+block);
 }
 
   bc_label[bc] = DECL_CHAIN (label);
   DECL_CHAIN (label) = NULL_TREE;
-  return body;
 }
 
 /* Get the LABEL_EXPR to represent a break or continue statement
@@ -183,173 +193,232 @@ genericize_if_stmt (tree *stmt_p)
evaluated before the loop body as in while and for loops, or after the
loop body as in do-while loops.  */
 
-static gimple_seq
-

Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2011-12-09 Thread Richard Guenther
On Fri, Dec 9, 2011 at 9:38 AM, Tom de Vries  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] Prevent 'control reaches end of non-void function' warning for DO_WHILE

2011-12-09 Thread Tom de Vries
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

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
==