Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE
OK, thanks. Jason
Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE
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
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
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
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
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
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
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 ==