mirror of git://gcc.gnu.org/git/gcc.git
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>
|
2000-10-05 Richard Henderson <rth@cygnus.com>
|
||||||
|
|
||||||
* Makefile.in (NM_FOR_TARGET): New.
|
* 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;
|
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. */
|
/* Warn about traditional constructs whose meanings changed in ANSI C. */
|
||||||
|
|
||||||
int warn_traditional;
|
int warn_traditional;
|
||||||
|
|
@ -6760,9 +6756,6 @@ c_expand_body (fndecl, nested_p)
|
||||||
/* Generate rtl for function exit. */
|
/* Generate rtl for function exit. */
|
||||||
expand_function_end (input_filename, lineno, 0);
|
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
|
/* If this is a nested function, protect the local variables in the stack
|
||||||
above us from being collected while we're compiling this function. */
|
above us from being collected while we're compiling this function. */
|
||||||
if (nested_p)
|
if (nested_p)
|
||||||
|
|
@ -6775,25 +6768,11 @@ c_expand_body (fndecl, nested_p)
|
||||||
if (nested_p)
|
if (nested_p)
|
||||||
ggc_pop_context ();
|
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
|
/* With just -W, complain only if function returns both with
|
||||||
and without a value. */
|
and without a value. */
|
||||||
else if (extra_warnings
|
if (extra_warnings
|
||||||
&& current_function_returns_value && current_function_returns_null)
|
&& current_function_returns_value
|
||||||
|
&& current_function_returns_null)
|
||||||
warning ("this function may return with or without a value");
|
warning ("this function may return with or without a value");
|
||||||
|
|
||||||
/* If requested, warn about function definitions where the function will
|
/* 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;
|
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. */
|
/* Warn about traditional constructs whose meanings changed in ANSI C. */
|
||||||
|
|
||||||
extern int warn_traditional;
|
extern int warn_traditional;
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,10 @@ extern int warn_switch;
|
||||||
|
|
||||||
extern int warn_return_type;
|
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
|
/* Nonzero means warn about pointer casts that increase the required
|
||||||
alignment of the target type (and might therefore lead to a crash
|
alignment of the target type (and might therefore lead to a crash
|
||||||
due to a misaligned access). */
|
due to a misaligned access). */
|
||||||
|
|
@ -547,11 +551,6 @@ extern int flag_renumber_insns;
|
||||||
|
|
||||||
extern int frame_pointer_needed;
|
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). */
|
/* Nonzero if GCC must add code to check memory access (used by Checker). */
|
||||||
|
|
||||||
extern int flag_check_memory_usage;
|
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
|
#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. */
|
/* Count the basic blocks of the function. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
@ -1115,8 +1152,11 @@ make_edges (label_value_list)
|
||||||
wouldn't have created the sibling call in the first place. */
|
wouldn't have created the sibling call in the first place. */
|
||||||
|
|
||||||
if (code == CALL_INSN && SIBLING_CALL_P (insn))
|
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
|
else
|
||||||
|
|
||||||
/* If this is a CALL_INSN, then mark it as reaching the active EH
|
/* 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)
|
if (return_label)
|
||||||
{
|
{
|
||||||
|
rtx before, after;
|
||||||
|
|
||||||
/* Before the return label, clobber the return registers so that
|
/* Before the return label, clobber the return registers so that
|
||||||
they are not propogated live to the rest of the function. This
|
they are not propogated live to the rest of the function. This
|
||||||
can only happen with functions that drop through; if there had
|
can only happen with functions that drop through; if there had
|
||||||
been a return statement, there would have either been a return
|
been a return statement, there would have either been a return
|
||||||
rtx, or a jump to the return label. */
|
rtx, or a jump to the return label. */
|
||||||
|
|
||||||
|
before = get_last_insn ();
|
||||||
clobber_return_register ();
|
clobber_return_register ();
|
||||||
|
after = get_last_insn ();
|
||||||
|
|
||||||
|
if (before != after)
|
||||||
|
cfun->x_clobber_return_insn = after;
|
||||||
|
|
||||||
emit_label (return_label);
|
emit_label (return_label);
|
||||||
}
|
}
|
||||||
|
|
@ -7429,6 +7437,7 @@ mark_function_status (p)
|
||||||
ggc_mark_tree (p->x_context_display);
|
ggc_mark_tree (p->x_context_display);
|
||||||
ggc_mark_tree (p->x_trampoline_list);
|
ggc_mark_tree (p->x_trampoline_list);
|
||||||
ggc_mark_rtx (p->epilogue_delay_list);
|
ggc_mark_rtx (p->epilogue_delay_list);
|
||||||
|
ggc_mark_rtx (p->x_clobber_return_insn);
|
||||||
|
|
||||||
mark_temp_slot (p->x_temp_slots);
|
mark_temp_slot (p->x_temp_slots);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -373,6 +373,11 @@ struct function
|
||||||
needed by inner routines. */
|
needed by inner routines. */
|
||||||
rtx x_arg_pointer_save_area;
|
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.
|
/* 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 down, this is the address of the last stack slot allocated.
|
||||||
If stack grows up, this is the address for the next slot. */
|
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;
|
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.
|
/* Indicates whether death notes are significant in cross jump analysis.
|
||||||
Normally they are not significant, because of A and B jump to C,
|
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
|
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 void mark_all_labels PARAMS ((rtx, int));
|
||||||
static rtx delete_unreferenced_labels PARAMS ((rtx));
|
static rtx delete_unreferenced_labels PARAMS ((rtx));
|
||||||
static void delete_noop_moves 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 int duplicate_loop_exit_test PARAMS ((rtx));
|
||||||
static void find_cross_jump PARAMS ((rtx, rtx, int, rtx *, rtx *));
|
static void find_cross_jump PARAMS ((rtx, rtx, int, rtx *, rtx *));
|
||||||
static void do_cross_jump PARAMS ((rtx, 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:
|
end:
|
||||||
/* Clean up. */
|
/* Clean up. */
|
||||||
free (jump_chain);
|
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
|
/* 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
|
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,
|
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 cleanup_cfg PARAMS ((rtx));
|
||||||
extern void free_basic_block_vars PARAMS ((int));
|
extern void free_basic_block_vars PARAMS ((int));
|
||||||
extern void set_block_num PARAMS ((rtx, int));
|
extern void set_block_num PARAMS ((rtx, int));
|
||||||
|
extern void check_function_return_warnings PARAMS ((void));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Functions in varasm.c. */
|
/* Functions in varasm.c. */
|
||||||
|
|
|
||||||
|
|
@ -1405,6 +1405,10 @@ int warn_padded;
|
||||||
|
|
||||||
int warn_disabled_optimization;
|
int warn_disabled_optimization;
|
||||||
|
|
||||||
|
/* Warn about functions which might be candidates for attribute noreturn. */
|
||||||
|
|
||||||
|
int warn_missing_noreturn;
|
||||||
|
|
||||||
/* Likewise for -W. */
|
/* Likewise for -W. */
|
||||||
|
|
||||||
lang_independent_options W_options[] =
|
lang_independent_options W_options[] =
|
||||||
|
|
@ -3209,6 +3213,7 @@ rest_of_compilation (decl)
|
||||||
|
|
||||||
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
|
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
|
||||||
cleanup_cfg (insns);
|
cleanup_cfg (insns);
|
||||||
|
check_function_return_warnings ();
|
||||||
|
|
||||||
close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
|
close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue