diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 63fe40b5195..0cdd854f91e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +Sat Aug 14 00:54:57 1999 Geoffrey Keating + + * cse.c (cse_insn): Call never_reached_warning when a jump is + changed to be unconditional. + * flags.h: Declare warn_notreached. + * flow.c (delete_block): Call never_reached_warning when + a block is deleted. + * jump.c (delete_barrier_successors): Call never_reached_warning + when we delete everything after a BARRIER. + (never_reached_warning): New function. + * rtl.h: Declare never_reached_warning. + * toplev.c (warn_notreached): New variable. + (lang_independent_options): Set warn_notreached + when -Wunreachable-code. + (compile_file): We need line numbers for -Wunreachable-code. + Tue Aug 17 22:06:11 1999 Jan Hubicka * haifa-sched.c (insn_unit): Fix typo on out of range test. diff --git a/gcc/cse.c b/gcc/cse.c index 9eca723e442..f279cd152cc 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -7419,6 +7419,8 @@ cse_insn (insn, libcall_insn) not delete NOTEs except for NOTE_INSN_DELETED since later phases assume these notes are retained. */ + never_reached_warning (insn); + p = insn; while (NEXT_INSN (p) != 0 diff --git a/gcc/flags.h b/gcc/flags.h index 6f2f93fda75..9871fb88b78 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -79,6 +79,10 @@ extern int extra_warnings; extern int warn_unused; +/* Nonzero to warn about code which is never reached. */ + +extern int warn_notreached; + /* Nonzero means warn if inline function is too large. */ extern int warn_inline; diff --git a/gcc/flow.c b/gcc/flow.c index 1154188684d..c38d0b3638b 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -1682,6 +1682,8 @@ delete_block (b) insn = b->head; + never_reached_warning (insn); + if (GET_CODE (insn) == CODE_LABEL) { rtx x, *prev = &exception_handler_labels; diff --git a/gcc/gcc.texi b/gcc/gcc.texi index 7f8fdfb2bbd..3494de492a2 100644 --- a/gcc/gcc.texi +++ b/gcc/gcc.texi @@ -1919,13 +1919,6 @@ Warning about assigning a signed value to an unsigned variable. Such assignments must be very common; warning about them would cause more annoyance than good. -@item -Warning about unreachable code. - -It's very common to have unreachable code in machine-generated -programs. For example, this happens normally in some files of GNU C -itself. - @item Warning when a non-void function value is ignored. diff --git a/gcc/invoke.texi b/gcc/invoke.texi index b707cdb4fd6..7dadd3f8db9 100644 --- a/gcc/invoke.texi +++ b/gcc/invoke.texi @@ -132,8 +132,8 @@ in the following sections. -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wshadow -Wsign-compare -Wstrict-prototypes -Wswitch -Wtraditional --Wtrigraphs -Wundef -Wuninitialized -Wunused -Wwrite-strings --Wunknown-pragmas +-Wtrigraphs -Wundef -Wuninitialized -Wunknown-pragmas -Wunreachable-code +-Wunused -Wwrite-strings @end smallexample @item Debugging Options @@ -1766,6 +1766,27 @@ cases where multiple declaration is valid and changes nothing. @item -Wnested-externs Warn if an @code{extern} declaration is encountered within an function. +@item -Wunreachable-code +Warn if the compiler detects that code will never be executed. + +This option is intended to warn when the compiler detects that at +least a whole line of source code will never be executed, because +some condition is never satisfied or because it is after a +procedure that never returns. + +It is possible for this option to produce a warning even though there +are circumstances under which part of the affected line can be executed, +so care should be taken when removing apparently-unreachable code. + +For instance, when a function is inlined, a warning may mean that the +line is unreachable in only one inlined copy of the function. + +This option is not made part of @samp{-Wall} because in a debugging +version of a program there is often substantial code which checks +correct functioning of the program and is, hopefully, unreachable +because the program does work. Another common use of unreachable +code is to provide behaviour which is selectable at compile-time. + @item -Winline Warn if a function can not be inlined, and either it was declared as inline, or else the @samp{-finline-functions} option was given. diff --git a/gcc/jump.c b/gcc/jump.c index 9ff6bc99ee9..6e63322b611 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -2149,6 +2149,9 @@ delete_barrier_successors (f) if (GET_CODE (insn) == BARRIER) { insn = NEXT_INSN (insn); + + never_reached_warning (insn); + while (insn != 0 && GET_CODE (insn) != CODE_LABEL) { if (GET_CODE (insn) == NOTE @@ -4245,6 +4248,52 @@ delete_for_peephole (from, to) is also an unconditional jump in that case. */ } +/* We have determined that INSN is never reached, and are about to + delete it. Print a warning if the user asked for one. + + To try to make this warning more useful, this should only be called + once per basic block not reached, and it only warns when the basic + block contains more than one line from the current function, and + contains at least one operation. CSE and inlining can duplicate insns, + so it's possible to get spurious warnings from this. */ + +void +never_reached_warning (avoided_insn) + rtx avoided_insn; +{ + rtx insn; + rtx a_line_note = NULL; + int two_avoided_lines = 0; + int contains_insn = 0; + + if (! warn_notreached) + return; + + /* Scan forwards, looking at LINE_NUMBER notes, until + we hit a LABEL or we run out of insns. */ + + for (insn = avoided_insn; insn != NULL; insn = NEXT_INSN (insn)) + { + if (GET_CODE (insn) == CODE_LABEL) + break; + else if (GET_CODE (insn) == NOTE /* A line number note? */ + && NOTE_LINE_NUMBER (insn) >= 0) + { + if (a_line_note == NULL) + a_line_note = insn; + else + two_avoided_lines |= (NOTE_LINE_NUMBER (a_line_note) + != NOTE_LINE_NUMBER (insn)); + } + else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') + contains_insn = 1; + } + if (two_avoided_lines && contains_insn) + warning_with_file_and_line (NOTE_SOURCE_FILE (a_line_note), + NOTE_LINE_NUMBER (a_line_note), + "will never be executed"); +} + /* Invert the condition of the jump JUMP, and make it jump to label NLABEL instead of where it jumps now. */ diff --git a/gcc/rtl.h b/gcc/rtl.h index 705da5e2cdd..4f01212ff03 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1292,6 +1292,7 @@ extern int invert_exp PROTO ((rtx, rtx)); extern int can_reverse_comparison_p PROTO ((rtx, rtx)); extern void delete_for_peephole PROTO ((rtx, rtx)); extern int condjump_in_parallel_p PROTO ((rtx)); +extern void never_reached_warning PROTO ((rtx)); /* Flags for jump_optimize() */ #define JUMP_CROSS_JUMP 1 diff --git a/gcc/toplev.c b/gcc/toplev.c index 1f1c3f53395..5a727c65b94 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1195,6 +1195,10 @@ int warnings_are_errors = 0; int warn_unused; +/* Nonzero to warn about code which is never reached. */ + +int warn_notreached; + /* Nonzero to warn about variables used before they are initialized. */ int warn_uninitialized; @@ -1253,6 +1257,8 @@ lang_independent_options W_options[] = "Warn about returning structures, unions or arrays" }, {"cast-align", &warn_cast_align, 1, "Warn about pointer casts which increase alignment" }, + {"unreachable-code", &warn_notreached, 1, + "Warn about code that will never be executed" }, {"uninitialized", &warn_uninitialized, 1, "Warn about unitialized automatic variables"}, {"inline", &warn_inline, 1, @@ -2944,7 +2950,8 @@ compile_file (name) init_rtl (); init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL || debug_info_level == DINFO_LEVEL_VERBOSE - || flag_test_coverage); + || flag_test_coverage + || warn_notreached); init_regs (); init_decl_processing (); init_optabs ();