diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7c07cc430f8becbe0bd7f2be6bfe9558d1d935e9..b97af9a6f31740acc55156767e1d39e9f2f73b79 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2005-01-20 Ian Lance Taylor <ian@airs.com> + + PR tree-optimization/13000 + * tree-inline.c: Include "tree-flow.h". + (expand_call_inline): If warn_return_type, warn if non-void inline + function falls through. + * tree-cfg.c (execute_warn_function_return): Don't warn about + control reaching end if TREE_NO_WARNING is set. Set + TREE_NO_WARNING. + * gimple-low.c (block_may_fallthru): Don't assume that SWITCH_EXPR + has been lowered. + * gimplify.c (shortcut_cond_expr): Don't emit a jump over the else + branch if we don't need one. + * c-typeck.c: Include "tree-flow.h" + (c_finish_bc_stmt): Don't add a goto if the current statement + list doesn't fall through to the current point. + 2005-01-21 Roger Sayle <roger@eyesopen.com> PR rtl-optimization/576 diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 186cb62bd2a01c841c88be71e845ec1f2026fda7..a4e4bc9df26efb1c08e7f3b8f7d8902d4dc2d6c9 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -43,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "target.h" #include "tree-iterator.h" #include "tree-gimple.h" +#include "tree-flow.h" /* Possible cases of implicit bad conversions. Used to select diagnostic messages in convert_for_assignment. */ @@ -6762,10 +6763,23 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body, tree c_finish_bc_stmt (tree *label_p, bool is_break) { + bool skip; tree label = *label_p; + /* In switch statements break is sometimes stylistically used after + a return statement. This can lead to spurious warnings about + control reaching the end of a non-void function when it is + inlined. Note that we are calling block_may_fallthru with + language specific tree nodes; this works because + block_may_fallthru returns true when given something it does not + understand. */ + skip = !block_may_fallthru (cur_stmt_list); + if (!label) - *label_p = label = create_artificial_label (); + { + if (!skip) + *label_p = label = create_artificial_label (); + } else if (TREE_CODE (label) != LABEL_DECL) { if (is_break) @@ -6775,6 +6789,9 @@ c_finish_bc_stmt (tree *label_p, bool is_break) return NULL_TREE; } + if (skip) + return NULL_TREE; + return add_stmt (build1 (GOTO_EXPR, void_type_node, label)); } diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index eb495288eee539726190a584e80d751094c6e5a6..17ba0393c25bda78f8de13e00f740f3e60d995bd 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -278,11 +278,17 @@ block_may_fallthru (tree block) case GOTO_EXPR: case RETURN_EXPR: case RESX_EXPR: - case SWITCH_EXPR: /* Easy cases. If the last statement of the block implies control transfer, then we can't fall through. */ return false; + case SWITCH_EXPR: + /* If SWITCH_LABELS is set, this is lowered, and represents a + branch to a selected label and hence can not fall through. + Otherwise SWITCH_BODY is set, and the switch can fall + through. */ + return SWITCH_LABELS (stmt) != NULL_TREE; + case COND_EXPR: if (block_may_fallthru (COND_EXPR_THEN (stmt))) return true; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 12822c4705565772aa4dcffdb2cdc7ebf75989b4..60d35724aaffd9df1a0af3c3aa8f0603bc3ea34e 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1911,7 +1911,7 @@ shortcut_cond_expr (tree expr) tree true_label, false_label, end_label, t; tree *true_label_p; tree *false_label_p; - bool emit_end, emit_false; + bool emit_end, emit_false, jump_over_else; bool then_se = then_ && TREE_SIDE_EFFECTS (then_); bool else_se = else_ && TREE_SIDE_EFFECTS (else_); @@ -2013,6 +2013,16 @@ shortcut_cond_expr (tree expr) emit_end = (end_label == NULL_TREE); emit_false = (false_label == NULL_TREE); + /* 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_); + pred = shortcut_cond_r (pred, true_label_p, false_label_p); expr = NULL; @@ -2021,8 +2031,11 @@ shortcut_cond_expr (tree expr) append_to_statement_list (then_, &expr); if (else_se) { - t = build_and_jump (&end_label); - append_to_statement_list (t, &expr); + if (jump_over_else) + { + t = build_and_jump (&end_label); + append_to_statement_list (t, &expr); + } if (emit_false) { t = build1 (LABEL_EXPR, void_type_node, false_label); diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 483b2dd81bd8107f7ec9fed19de284b3e297b2e5..93dfc343f8289255f3a42a9326e5ef35e22442e8 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -5677,6 +5677,7 @@ execute_warn_function_return (void) /* If we see "return;" in some basic block, then we do reach the end without returning a value. */ else if (warn_return_type + && !TREE_NO_WARNING (cfun->decl) && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0 && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl)))) { @@ -5697,6 +5698,7 @@ execute_warn_function_return (void) locus = &cfun->function_end_locus; warning ("%Hcontrol reaches end of non-void function", locus); #endif + TREE_NO_WARNING (cfun->decl) = 1; break; } } diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 247c6873e4d465fced01fc87d263e8ea0458e299..b46276a4e4ce5190f93e12352b78672615bde117 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA. */ #include "cgraph.h" #include "intl.h" #include "tree-mudflap.h" +#include "tree-flow.h" #include "function.h" #include "diagnostic.h" #include "debug.h" @@ -1607,9 +1608,22 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) function itself. */ { struct cgraph_node *old_node = id->current_node; + tree copy; id->current_node = edge->callee; - append_to_statement_list (copy_body (id), &BIND_EXPR_BODY (expr)); + copy = copy_body (id); + + if (warn_return_type + && !TREE_NO_WARNING (fn) + && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn))) + && block_may_fallthru (copy)) + { + warning ("control may reach end of non-void function %qD being inlined", + fn); + TREE_NO_WARNING (fn) = 1; + } + + append_to_statement_list (copy, &BIND_EXPR_BODY (expr)); id->current_node = old_node; } inlined_body = &BIND_EXPR_BODY (expr);