diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-10-06 06:01:27 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-10-06 06:01:27 +0000 |
commit | fbc1c83e2cee2521d6e0122f7a3b8572fac244e1 (patch) | |
tree | 2a84a351f2dd9e081499cea34c0929d359328dd0 /gcc | |
parent | 810ba5145dda3dbbf478746bd0167595b00ce903 (diff) | |
download | gcc-fbc1c83e2cee2521d6e0122f7a3b8572fac244e1.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@36750 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 20 | ||||
-rw-r--r-- | gcc/c-decl.c | 27 | ||||
-rw-r--r-- | gcc/c-tree.h | 4 | ||||
-rw-r--r-- | gcc/flags.h | 9 | ||||
-rw-r--r-- | gcc/flow.c | 44 | ||||
-rw-r--r-- | gcc/function.c | 9 | ||||
-rw-r--r-- | gcc/function.h | 5 | ||||
-rw-r--r-- | gcc/jump.c | 72 | ||||
-rw-r--r-- | gcc/output.h | 1 | ||||
-rw-r--r-- | gcc/toplev.c | 5 |
10 files changed, 89 insertions, 107 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 88c612020d4..a33743dfb18 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,25 @@ 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. (libgcc.mk): Pass SHLIB_MKMAP, SHLIB_MAPFILES. (libgcc.a, stmp-multilib): Pass NM_FOR_TARGET. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 940d4b18393..9dbaa284685 100644 --- a/gcc/c-decl.c +++ b/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 diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 5531731010e..b8adce15454 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -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; diff --git a/gcc/flags.h b/gcc/flags.h index 0a29c4b126d..7fec383bdd7 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -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; diff --git a/gcc/flow.c b/gcc/flow.c index b913c6ea8c7..52eed8d179c 100644 --- a/gcc/flow.c +++ b/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 diff --git a/gcc/function.c b/gcc/function.c index f5814109211..85a18bf0b87 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -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); diff --git a/gcc/function.h b/gcc/function.h index 3912d859790..f3124a7b71a 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -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. */ diff --git a/gcc/jump.c b/gcc/jump.c index 848094ce9da..8574f161526 100644 --- a/gcc/jump.c +++ b/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, diff --git a/gcc/output.h b/gcc/output.h index 2446de2f800..e5d2ae6b3ce 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -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. */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 6897d5fa2cf..4e7ec89b960 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.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); |