re PR tree-optimization/13000 ([unit-at-a-time] Using -O2 cannot detect missing return statement in a function)
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. From-SVN: r94024
This commit is contained in:
parent
d284eb28eb
commit
089efaa4a1
@ -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>
|
2005-01-21 Roger Sayle <roger@eyesopen.com>
|
||||||
|
|
||||||
PR rtl-optimization/576
|
PR rtl-optimization/576
|
||||||
|
@ -43,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "tree-iterator.h"
|
#include "tree-iterator.h"
|
||||||
#include "tree-gimple.h"
|
#include "tree-gimple.h"
|
||||||
|
#include "tree-flow.h"
|
||||||
|
|
||||||
/* Possible cases of implicit bad conversions. Used to select
|
/* Possible cases of implicit bad conversions. Used to select
|
||||||
diagnostic messages in convert_for_assignment. */
|
diagnostic messages in convert_for_assignment. */
|
||||||
@ -6762,10 +6763,23 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
|
|||||||
tree
|
tree
|
||||||
c_finish_bc_stmt (tree *label_p, bool is_break)
|
c_finish_bc_stmt (tree *label_p, bool is_break)
|
||||||
{
|
{
|
||||||
|
bool skip;
|
||||||
tree label = *label_p;
|
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)
|
if (!label)
|
||||||
*label_p = label = create_artificial_label ();
|
{
|
||||||
|
if (!skip)
|
||||||
|
*label_p = label = create_artificial_label ();
|
||||||
|
}
|
||||||
else if (TREE_CODE (label) != LABEL_DECL)
|
else if (TREE_CODE (label) != LABEL_DECL)
|
||||||
{
|
{
|
||||||
if (is_break)
|
if (is_break)
|
||||||
@ -6775,6 +6789,9 @@ c_finish_bc_stmt (tree *label_p, bool is_break)
|
|||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
return NULL_TREE;
|
||||||
|
|
||||||
return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
|
return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,11 +278,17 @@ block_may_fallthru (tree block)
|
|||||||
case GOTO_EXPR:
|
case GOTO_EXPR:
|
||||||
case RETURN_EXPR:
|
case RETURN_EXPR:
|
||||||
case RESX_EXPR:
|
case RESX_EXPR:
|
||||||
case SWITCH_EXPR:
|
|
||||||
/* Easy cases. If the last statement of the block implies
|
/* Easy cases. If the last statement of the block implies
|
||||||
control transfer, then we can't fall through. */
|
control transfer, then we can't fall through. */
|
||||||
return false;
|
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:
|
case COND_EXPR:
|
||||||
if (block_may_fallthru (COND_EXPR_THEN (stmt)))
|
if (block_may_fallthru (COND_EXPR_THEN (stmt)))
|
||||||
return true;
|
return true;
|
||||||
|
@ -1911,7 +1911,7 @@ shortcut_cond_expr (tree expr)
|
|||||||
tree true_label, false_label, end_label, t;
|
tree true_label, false_label, end_label, t;
|
||||||
tree *true_label_p;
|
tree *true_label_p;
|
||||||
tree *false_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 then_se = then_ && TREE_SIDE_EFFECTS (then_);
|
||||||
bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
|
bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
|
||||||
|
|
||||||
@ -2013,6 +2013,16 @@ shortcut_cond_expr (tree expr)
|
|||||||
emit_end = (end_label == NULL_TREE);
|
emit_end = (end_label == NULL_TREE);
|
||||||
emit_false = (false_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);
|
pred = shortcut_cond_r (pred, true_label_p, false_label_p);
|
||||||
|
|
||||||
expr = NULL;
|
expr = NULL;
|
||||||
@ -2021,8 +2031,11 @@ shortcut_cond_expr (tree expr)
|
|||||||
append_to_statement_list (then_, &expr);
|
append_to_statement_list (then_, &expr);
|
||||||
if (else_se)
|
if (else_se)
|
||||||
{
|
{
|
||||||
t = build_and_jump (&end_label);
|
if (jump_over_else)
|
||||||
append_to_statement_list (t, &expr);
|
{
|
||||||
|
t = build_and_jump (&end_label);
|
||||||
|
append_to_statement_list (t, &expr);
|
||||||
|
}
|
||||||
if (emit_false)
|
if (emit_false)
|
||||||
{
|
{
|
||||||
t = build1 (LABEL_EXPR, void_type_node, false_label);
|
t = build1 (LABEL_EXPR, void_type_node, false_label);
|
||||||
|
@ -5677,6 +5677,7 @@ execute_warn_function_return (void)
|
|||||||
/* If we see "return;" in some basic block, then we do reach the end
|
/* If we see "return;" in some basic block, then we do reach the end
|
||||||
without returning a value. */
|
without returning a value. */
|
||||||
else if (warn_return_type
|
else if (warn_return_type
|
||||||
|
&& !TREE_NO_WARNING (cfun->decl)
|
||||||
&& EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0
|
&& EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0
|
||||||
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl))))
|
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl))))
|
||||||
{
|
{
|
||||||
@ -5697,6 +5698,7 @@ execute_warn_function_return (void)
|
|||||||
locus = &cfun->function_end_locus;
|
locus = &cfun->function_end_locus;
|
||||||
warning ("%Hcontrol reaches end of non-void function", locus);
|
warning ("%Hcontrol reaches end of non-void function", locus);
|
||||||
#endif
|
#endif
|
||||||
|
TREE_NO_WARNING (cfun->decl) = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA. */
|
|||||||
#include "cgraph.h"
|
#include "cgraph.h"
|
||||||
#include "intl.h"
|
#include "intl.h"
|
||||||
#include "tree-mudflap.h"
|
#include "tree-mudflap.h"
|
||||||
|
#include "tree-flow.h"
|
||||||
#include "function.h"
|
#include "function.h"
|
||||||
#include "diagnostic.h"
|
#include "diagnostic.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -1607,9 +1608,22 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
|
|||||||
function itself. */
|
function itself. */
|
||||||
{
|
{
|
||||||
struct cgraph_node *old_node = id->current_node;
|
struct cgraph_node *old_node = id->current_node;
|
||||||
|
tree copy;
|
||||||
|
|
||||||
id->current_node = edge->callee;
|
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;
|
id->current_node = old_node;
|
||||||
}
|
}
|
||||||
inlined_body = &BIND_EXPR_BODY (expr);
|
inlined_body = &BIND_EXPR_BODY (expr);
|
||||||
|
Loading…
Reference in New Issue
Block a user