c-decl.c (warn_missing_noreturn): Remove.

* c-decl.c (warn_missing_noreturn): Remove.
        (c_expand_body): Don't set or check can_reach_end.
        * c-tree.h (warn_missing_noreturn): Move ...
        * flags.h: ... here.
        (can_reach_end): Remove.
        * flow.c (check_function_return_warnings): New.
        (make_edges): No edge to exit for noreturn sibcalls.
        * function.c (expand_function_end): Save the return value
        clobber instruction.
        (mark_function_status): Mark it.
        * function.h (struct function): Add x_clobber_return_insn.
        * jump.c (can_reach_end): Remove.
        (calculate_can_reach_end): Remove.
        (jump_optimize_1): Don't call it.
        * output.h (check_function_return_warnings): Declare.
        * toplev.c (warn_missing_noreturn): Move from c-decl.c
        (rest_of_compilation): Call check_function_return_warnings.

From-SVN: r36750
This commit is contained in:
Richard Henderson 2000-10-05 23:01:27 -07:00 committed by Richard Henderson
parent 63c16fc50c
commit b313a0fe15
10 changed files with 89 additions and 107 deletions

View File

@ -1,3 +1,23 @@
2000-10-05 Richard Henderson <rth@cygnus.com>
* c-decl.c (warn_missing_noreturn): Remove.
(c_expand_body): Don't set or check can_reach_end.
* c-tree.h (warn_missing_noreturn): Move ...
* flags.h: ... here.
(can_reach_end): Remove.
* flow.c (check_function_return_warnings): New.
(make_edges): No edge to exit for noreturn sibcalls.
* function.c (expand_function_end): Save the return value
clobber instruction.
(mark_function_status): Mark it.
* function.h (struct function): Add x_clobber_return_insn.
* jump.c (can_reach_end): Remove.
(calculate_can_reach_end): Remove.
(jump_optimize_1): Don't call it.
* output.h (check_function_return_warnings): Declare.
* toplev.c (warn_missing_noreturn): Move from c-decl.c
(rest_of_compilation): Call check_function_return_warnings.
2000-10-05 Richard Henderson <rth@cygnus.com>
* Makefile.in (NM_FOR_TARGET): New.

View File

@ -403,10 +403,6 @@ int warn_cast_qual;
int warn_bad_function_cast;
/* Warn about functions which might be candidates for attribute noreturn. */
int warn_missing_noreturn;
/* Warn about traditional constructs whose meanings changed in ANSI C. */
int warn_traditional;
@ -6760,9 +6756,6 @@ c_expand_body (fndecl, nested_p)
/* Generate rtl for function exit. */
expand_function_end (input_filename, lineno, 0);
/* So we can tell if jump_optimize sets it to 1. */
can_reach_end = 0;
/* If this is a nested function, protect the local variables in the stack
above us from being collected while we're compiling this function. */
if (nested_p)
@ -6775,25 +6768,11 @@ c_expand_body (fndecl, nested_p)
if (nested_p)
ggc_pop_context ();
current_function_returns_null |= can_reach_end;
if (warn_missing_noreturn
&& !TREE_THIS_VOLATILE (fndecl)
&& !current_function_returns_null
&& !current_function_returns_value)
warning ("function might be possible candidate for attribute `noreturn'");
if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
warning ("`noreturn' function does return");
else if (warn_return_type && can_reach_end
&& !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))))
/* If this function returns non-void and control can drop through,
complain. */
warning ("control reaches end of non-void function");
/* With just -W, complain only if function returns both with
and without a value. */
else if (extra_warnings
&& current_function_returns_value && current_function_returns_null)
if (extra_warnings
&& current_function_returns_value
&& current_function_returns_null)
warning ("this function may return with or without a value");
/* If requested, warn about function definitions where the function will

View File

@ -342,10 +342,6 @@ extern int warn_cast_qual;
extern int warn_bad_function_cast;
/* Warn about functions which might be candidates for attribute noreturn. */
extern int warn_missing_noreturn;
/* Warn about traditional constructs whose meanings changed in ANSI C. */
extern int warn_traditional;

View File

@ -132,6 +132,10 @@ extern int warn_switch;
extern int warn_return_type;
/* Warn about functions which might be candidates for attribute noreturn. */
extern int warn_missing_noreturn;
/* Nonzero means warn about pointer casts that increase the required
alignment of the target type (and might therefore lead to a crash
due to a misaligned access). */
@ -547,11 +551,6 @@ extern int flag_renumber_insns;
extern int frame_pointer_needed;
/* Set nonzero if jump_optimize finds that control falls through
at the end of the function. */
extern int can_reach_end;
/* Nonzero if GCC must add code to check memory access (used by Checker). */
extern int flag_check_memory_usage;

View File

@ -511,6 +511,43 @@ find_basic_blocks (f, nregs, file)
#endif
}
void
check_function_return_warnings ()
{
if (warn_missing_noreturn
&& !TREE_THIS_VOLATILE (cfun->decl)
&& EXIT_BLOCK_PTR->pred == NULL)
warning ("function might be possible candidate for attribute `noreturn'");
/* If we have a path to EXIT, then we do return. */
if (TREE_THIS_VOLATILE (cfun->decl)
&& EXIT_BLOCK_PTR->pred != NULL)
warning ("`noreturn' function does return");
/* If the clobber_return_insn appears in some basic block, then we
do reach the end without returning a value. */
else if (warn_return_type
&& cfun->x_clobber_return_insn != NULL
&& EXIT_BLOCK_PTR->pred != NULL)
{
int max_uid = get_max_uid ();
/* If clobber_return_insn was excised by jump1, then renumber_insns
can make max_uid smaller than the number still recorded in our rtx.
That's fine, since this is a quick way of verifying that the insn
is no longer in the chain. */
if (INSN_UID (cfun->x_clobber_return_insn) < max_uid)
{
/* Recompute insn->block mapping, since the initial mapping is
set before we delete unreachable blocks. */
compute_bb_for_insn (max_uid);
if (BLOCK_FOR_INSN (cfun->x_clobber_return_insn) != NULL)
warning ("control reaches end of non-void function");
}
}
}
/* Count the basic blocks of the function. */
static int
@ -1115,8 +1152,11 @@ make_edges (label_value_list)
wouldn't have created the sibling call in the first place. */
if (code == CALL_INSN && SIBLING_CALL_P (insn))
make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
{
if (! find_reg_note (insn, REG_NORETURN, NULL_RTX))
make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
}
else
/* If this is a CALL_INSN, then mark it as reaching the active EH

View File

@ -6658,12 +6658,20 @@ expand_function_end (filename, line, end_bindings)
if (return_label)
{
rtx before, after;
/* Before the return label, clobber the return registers so that
they are not propogated live to the rest of the function. This
can only happen with functions that drop through; if there had
been a return statement, there would have either been a return
rtx, or a jump to the return label. */
before = get_last_insn ();
clobber_return_register ();
after = get_last_insn ();
if (before != after)
cfun->x_clobber_return_insn = after;
emit_label (return_label);
}
@ -7429,6 +7437,7 @@ mark_function_status (p)
ggc_mark_tree (p->x_context_display);
ggc_mark_tree (p->x_trampoline_list);
ggc_mark_rtx (p->epilogue_delay_list);
ggc_mark_rtx (p->x_clobber_return_insn);
mark_temp_slot (p->x_temp_slots);

View File

@ -373,6 +373,11 @@ struct function
needed by inner routines. */
rtx x_arg_pointer_save_area;
/* If the function returns non-void, we will emit a clobber of the
return registers just in case the user fell off the end without
returning a proper value. This is that insn. */
rtx x_clobber_return_insn;
/* Offset to end of allocated area of stack frame.
If stack grows down, this is the address of the last stack slot allocated.
If stack grows up, this is the address for the next slot. */

View File

@ -95,10 +95,6 @@ static rtx *jump_chain;
static int max_jump_chain;
/* Set nonzero by jump_optimize if control can fall through
to the end of the function. */
int can_reach_end;
/* Indicates whether death notes are significant in cross jump analysis.
Normally they are not significant, because of A and B jump to C,
and R dies in A, it must die in B. But this might not be true after
@ -112,7 +108,6 @@ static void delete_barrier_successors PARAMS ((rtx));
static void mark_all_labels PARAMS ((rtx, int));
static rtx delete_unreferenced_labels PARAMS ((rtx));
static void delete_noop_moves PARAMS ((rtx));
static int calculate_can_reach_end PARAMS ((rtx, int));
static int duplicate_loop_exit_test PARAMS ((rtx));
static void find_cross_jump PARAMS ((rtx, rtx, int, rtx *, rtx *));
static void do_cross_jump PARAMS ((rtx, rtx, rtx));
@ -743,13 +738,6 @@ jump_optimize_1 (f, cross_jump, noop_moves, after_regscan,
}
}
/* CAN_REACH_END is persistent for each function. Once set it should
not be cleared. This is especially true for the case where we
delete the NOTE_FUNCTION_END note. CAN_REACH_END is cleared by
the front-end before compiling each function. */
if (! minimal && calculate_can_reach_end (last_insn, optimize != 0))
can_reach_end = 1;
end:
/* Clean up. */
free (jump_chain);
@ -1062,66 +1050,6 @@ delete_noop_moves (f)
}
}
/* See if there is still a NOTE_INSN_FUNCTION_END in this function.
If so indicate that this function can drop off the end by returning
1, else return 0.
CHECK_DELETED indicates whether we must check if the note being
searched for has the deleted flag set.
DELETE_FINAL_NOTE indicates whether we should delete the note
if we find it. */
static int
calculate_can_reach_end (last, delete_final_note)
rtx last;
int delete_final_note;
{
rtx insn = last;
int n_labels = 1;
while (insn != NULL_RTX)
{
int ok = 0;
/* One label can follow the end-note: the return label. */
if (GET_CODE (insn) == CODE_LABEL && n_labels-- > 0)
ok = 1;
/* Ordinary insns can follow it if returning a structure. */
else if (GET_CODE (insn) == INSN)
ok = 1;
/* If machine uses explicit RETURN insns, no epilogue,
then one of them follows the note. */
else if (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == RETURN)
ok = 1;
/* A barrier can follow the return insn. */
else if (GET_CODE (insn) == BARRIER)
ok = 1;
/* Other kinds of notes can follow also. */
else if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
ok = 1;
if (ok != 1)
break;
insn = PREV_INSN (insn);
}
/* See if we backed up to the appropriate type of note. */
if (insn != NULL_RTX
&& GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END)
{
if (delete_final_note)
delete_insn (insn);
return 1;
}
return 0;
}
/* LOOP_START is a NOTE_INSN_LOOP_BEG note that is followed by an unconditional
jump. Assume that this unconditional jump is to the exit test code. If
the code is sufficiently simple, make a copy of it before INSN,

View File

@ -136,6 +136,7 @@ extern void find_basic_blocks PARAMS ((rtx, int, FILE *));
extern void cleanup_cfg PARAMS ((rtx));
extern void free_basic_block_vars PARAMS ((int));
extern void set_block_num PARAMS ((rtx, int));
extern void check_function_return_warnings PARAMS ((void));
#endif
/* Functions in varasm.c. */

View File

@ -1405,6 +1405,10 @@ int warn_padded;
int warn_disabled_optimization;
/* Warn about functions which might be candidates for attribute noreturn. */
int warn_missing_noreturn;
/* Likewise for -W. */
lang_independent_options W_options[] =
@ -3209,6 +3213,7 @@ rest_of_compilation (decl)
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
cleanup_cfg (insns);
check_function_return_warnings ();
close_dump_file (DFI_cfg, print_rtl_with_bb, insns);