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:
parent
63c16fc50c
commit
b313a0fe15
@ -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.
|
||||
|
27
gcc/c-decl.c
27
gcc/c-decl.c
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
44
gcc/flow.c
44
gcc/flow.c
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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. */
|
||||
|
72
gcc/jump.c
72
gcc/jump.c
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user