On Wed, Nov 24, 2021 at 10:22 AM Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > This resurrects -Wunreachable-code and implements a warning for > trivially unreachable code as of CFG construction. Most problematic > with this is the C/C++ frontend added 'return 0;' stmt in main > which the patch handles for C++ like the C frontend already does > by using BUILTINS_LOCATION. > > Another problem for future enhancement is that after CFG construction > we no longer can point to the stmt making a stmt unreachable, so > this implementation tries to warn on the first unreachable > statement of a region. It might be possible to retain a pointer > to the stmt that triggered creation of a basic-block but I'm not > sure how reliable that would be. > > So this is really a simple attempt for now, triggered by myself > running into such a coding error. As always, the perfect is the > enemy of the good. > > It does not pass bootstrap (which enables -Wextra), because of the > situation in g++.dg/Wunreachable-code-5.C where the C++ frontend > prematurely elides conditions like if (! GATHER_STATISTICS) that > evaluate to true - oddly enough it does _not_ do this for > conditions evaluating to false ... (one of the > c-c++-common/Wunreachable-code-2.c cases). > > Richard.
There are several bugs about reviving -Wunreachable-code open, all for different aspects of it. Do we want to consider making it an umbrella flag that's split into multiple sub-options? Bug 46476, which you mentioned, was suggested to be -Wunreachable-code-return specifically: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=46476 Meanwhile, there's also bug 92479, for a warning to be named -Wunreachable-code-break: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92479 Then there's also bug 82100, which doesn't have a name suggested for it yet: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82100 I think having separate flags for the 3 of these that are all enabled by -Wunreachable-code as an umbrella would be good. Eric > > 2021-11-24 Richard Biener <rguent...@suse.de> > > PR middle-end/46476 > * common.opt (Wunreachable-code): No longer ignored, > add warn_unreachable_code variable, enable with -Wextra. > * doc/invoke.texi (Wunreachable-code): Document. > (Wextra): Amend. > * tree-cfg.c (build_gimple_cfg): Move case label grouping... > (execute_build_cfg): ... here after new -Wunreachable-code > warnings. > (warn_unreachable_code_post_cfg_build): New function. > (mark_forward_reachable_blocks): Likewise. > (reverse_guess_deadend): Likewise. > > gcc/cp/ > * decl.c (finish_function): Set input_location to > BUILTINS_LOCATION around the code building the return 0 > for main(). > > libgomp/ > * oacc-plugin.c (GOMP_PLUGIN_acc_default_dim): Remove spurious > return. > > gcc/testsuite/ > * c-c++-common/Wunreachable-code-1.c: New testcase. > * c-c++-common/Wunreachable-code-2.c: Likewise. > * c-c++-common/Wunreachable-code-3.c: Likewise. > * gcc.dg/Wunreachable-code-4.c: Likewise. > * g++.dg/Wunreachable-code-5.C: Likewise. > --- > gcc/common.opt | 4 +- > gcc/cp/decl.c | 9 +- > gcc/doc/invoke.texi | 9 +- > .../c-c++-common/Wunreachable-code-1.c | 8 ++ > .../c-c++-common/Wunreachable-code-2.c | 8 ++ > .../c-c++-common/Wunreachable-code-3.c | 35 ++++++ > gcc/testsuite/g++.dg/Wunreachable-code-5.C | 11 ++ > gcc/testsuite/gcc.dg/Wunreachable-code-4.c | 10 ++ > gcc/tree-cfg.c | 101 +++++++++++++++++- > libgomp/oacc-plugin.c | 1 - > 10 files changed, 186 insertions(+), 10 deletions(-) > create mode 100644 gcc/testsuite/c-c++-common/Wunreachable-code-1.c > create mode 100644 gcc/testsuite/c-c++-common/Wunreachable-code-2.c > create mode 100644 gcc/testsuite/c-c++-common/Wunreachable-code-3.c > create mode 100644 gcc/testsuite/g++.dg/Wunreachable-code-5.C > create mode 100644 gcc/testsuite/gcc.dg/Wunreachable-code-4.c > > diff --git a/gcc/common.opt b/gcc/common.opt > index 755e1a233b7..0a58cb8a668 100644 > --- a/gcc/common.opt > +++ b/gcc/common.opt > @@ -806,8 +806,8 @@ Common Var(warn_maybe_uninitialized) Warning > EnabledBy(Wuninitialized) > Warn about maybe uninitialized automatic variables. > > Wunreachable-code > -Common Ignore Warning > -Does nothing. Preserved for backward compatibility. > +Common Var(warn_unreachable_code) Warning EnabledBy(Wextra) > +Warn about trivially unreachable code. > > Wunused > Common Var(warn_unused) Init(0) Warning > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c > index 588094b1db6..26325e41efa 100644 > --- a/gcc/cp/decl.c > +++ b/gcc/cp/decl.c > @@ -17571,7 +17571,14 @@ finish_function (bool inline_p) > { > /* Make it so that `main' always returns 0 by default. */ > if (DECL_MAIN_P (current_function_decl)) > - finish_return_stmt (integer_zero_node); > + { > + /* Hack. We don't want the middle-end to warn that this return > + is unreachable, so we mark its location as special. */ > + auto saved_il = input_location; > + input_location = BUILTINS_LOCATION; > + finish_return_stmt (integer_zero_node); > + input_location = saved_il; > + } > > if (use_eh_spec_block (current_function_decl)) > finish_eh_spec_block (TYPE_RAISES_EXCEPTIONS > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index 36fe96b441b..62643e51915 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -267,7 +267,7 @@ in the following sections. > -Woverloaded-virtual -Wno-pmf-conversions -Wsign-promo @gol > -Wsized-deallocation -Wsuggest-final-methods @gol > -Wsuggest-final-types -Wsuggest-override @gol > --Wno-terminate -Wuseless-cast -Wno-vexing-parse @gol > +-Wno-terminate -Wunreachable-code -Wuseless-cast -Wno-vexing-parse @gol > -Wvirtual-inheritance @gol > -Wno-virtual-move-assign -Wvolatile -Wzero-as-null-pointer-constant} > > @@ -4357,6 +4357,12 @@ annotations. > Warn about overriding virtual functions that are not marked with the > @code{override} keyword. > > +@item -Wunreachable-code > +@opindex Wunreachable-code > +@opindex Wno-unreachable-code > +Warn about code that is trivially unreachable before optimizing. > +@option{-Wunreachable-code} is enabled by @option{-Wextra}. > + > @item -Wuseless-cast @r{(C++ and Objective-C++ only)} > @opindex Wuseless-cast > @opindex Wno-useless-cast > @@ -5713,6 +5719,7 @@ name is still supported, but the newer name is more > descriptive.) > -Wredundant-move @r{(only for C++)} @gol > -Wtype-limits @gol > -Wuninitialized @gol > +-Wunreachable-code @gol > -Wshift-negative-value @r{(in C++03 and in C99 and newer)} @gol > -Wunused-parameter @r{(only with} @option{-Wunused} @r{or} > @option{-Wall}@r{)} @gol > -Wunused-but-set-parameter @r{(only with} @option{-Wunused} @r{or} > @option{-Wall}@r{)}} > diff --git a/gcc/testsuite/c-c++-common/Wunreachable-code-1.c > b/gcc/testsuite/c-c++-common/Wunreachable-code-1.c > new file mode 100644 > index 00000000000..0ca6c00e7fb > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/Wunreachable-code-1.c > @@ -0,0 +1,8 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wunreachable-code" } */ > + > +int main() > +{ > + /* Avoid warning on the auto-added duplicate return 0. */ > + return 0; > +} > diff --git a/gcc/testsuite/c-c++-common/Wunreachable-code-2.c > b/gcc/testsuite/c-c++-common/Wunreachable-code-2.c > new file mode 100644 > index 00000000000..836d8c30cb2 > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/Wunreachable-code-2.c > @@ -0,0 +1,8 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wunreachable-code" } */ > + > +int main() > +{ > + return 0; > + return 0; /* { dg-warning "not reachable" } */ > +} > diff --git a/gcc/testsuite/c-c++-common/Wunreachable-code-3.c > b/gcc/testsuite/c-c++-common/Wunreachable-code-3.c > new file mode 100644 > index 00000000000..a01e4119c6f > --- /dev/null > +++ b/gcc/testsuite/c-c++-common/Wunreachable-code-3.c > @@ -0,0 +1,35 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wunreachable-code" } */ > + > +/* Unreachable region entry has a predecessor (backedge). */ > +void foo() > +{ > + return; > + for (int i = 0; i < 5; ++i) /* { dg-warning "not reachable" } */ > + ; > +} > + > +/* Unreachable region not backwards reachable from exit. */ > +void bar1() > +{ > + return; > + __builtin_abort (); /* { dg-warning "not reachable" } */ > +} > +void bar2() > +{ > + return; > + /* Here we end up with a BB without any statements and an edge > + to itself. A location might be obtainable from the edges > + goto_locus. */ > + for (;;); /* { dg-warning "not reachable" "" { xfail *-*-* } } */ > +} > + > +/* Unreachable code in if (0) block. */ > +void baz(int *p) > +{ > + if (0) > + { > + return; /* { dg-bogus "not reachable" } */ > + *p = 0; /* { dg-warning "not reachable" } */ > + } > +} > diff --git a/gcc/testsuite/g++.dg/Wunreachable-code-5.C > b/gcc/testsuite/g++.dg/Wunreachable-code-5.C > new file mode 100644 > index 00000000000..832cb6d865f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/Wunreachable-code-5.C > @@ -0,0 +1,11 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wunreachable-code" } */ > + > +void baz(); > +void bar2() > +{ > + if (! 0) > + return; > + /* The C++ frontend elides the if above. */ > + baz (); /* { dg-bogus "not reachable" "" { xfail *-*-* } } */ > +} > diff --git a/gcc/testsuite/gcc.dg/Wunreachable-code-4.c > b/gcc/testsuite/gcc.dg/Wunreachable-code-4.c > new file mode 100644 > index 00000000000..997ec08fb41 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/Wunreachable-code-4.c > @@ -0,0 +1,10 @@ > +/* { dg-do compile } */ > +/* { dg-options "-Wunreachable-code" } */ > + > +void baz(); > +void bar2() > +{ > + if (! 0) > + return; > + baz (); /* { dg-bogus "not reachable" } */ > +} > diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c > index 8ed8c69b5b1..5a9507d0e44 100644 > --- a/gcc/tree-cfg.c > +++ b/gcc/tree-cfg.c > @@ -239,11 +239,6 @@ build_gimple_cfg (gimple_seq seq) > /* To speed up statement iterator walks, we first purge dead labels. */ > cleanup_dead_labels (); > > - /* Group case nodes to reduce the number of edges. > - We do this after cleaning up dead labels because otherwise we miss > - a lot of obvious case merging opportunities. */ > - group_case_labels (); > - > /* Create the edges of the flowgraph. */ > discriminator_per_locus = new hash_table<locus_discrim_hasher> (13); > make_edges (); > @@ -362,6 +357,94 @@ replace_loop_annotate (void) > } > } > > +/* Mark BB and blocks forward reachable from it as BB_REACHABLE. */ > + > +static void > +mark_forward_reachable_blocks (basic_block bb) > +{ > + bb->flags |= BB_REACHABLE; > + edge_iterator ei; > + edge e; > + FOR_EACH_EDGE (e, ei, bb->succs) > + if (!(e->dest->flags & BB_REACHABLE)) > + mark_forward_reachable_blocks (e->dest); > +} > + > +/* Guess a reverse dead end from BB. */ > + > +static basic_block > +reverse_guess_deadend (basic_block bb) > +{ > + /* Quick and simple minded. */ > + if (EDGE_COUNT (bb->preds) == 0) > + return bb; > + > + /* DFS walk. */ > + auto_bb_flag visited (cfun); > + auto_bb_flag on_worklist (cfun); > + auto_vec<basic_block, 64> bbs_to_cleanup; > + auto_vec<basic_block, 64> worklist; > + worklist.quick_push (bb); > + bb->flags |= on_worklist; > + bbs_to_cleanup.safe_push (bb); > + while (!worklist.is_empty ()) > + { > + bb = worklist.pop (); > + bb->flags &= ~on_worklist; > + bb->flags |= visited; > + bool all_preds_visited = true; > + edge_iterator ei; > + edge e; > + FOR_EACH_EDGE (e, ei, bb->preds) > + if (!(e->src->flags & visited)) > + { > + if (!(e->src->flags & on_worklist)) > + { > + worklist.safe_push (e->src); > + e->src->flags |= on_worklist; > + bbs_to_cleanup.safe_push (e->src); > + } > + all_preds_visited = false; > + } > + /* Found one deadend. */ > + if (all_preds_visited) > + break; > + } > + for (auto bb2 : bbs_to_cleanup) > + bb2->flags &= ~(on_worklist|visited); > + return bb; > +} > + > +/* Warn about trivially unreachable code. */ > + > +static void > +warn_unreachable_code_post_cfg_build (void) > +{ > + find_unreachable_blocks (); > + basic_block bb; > + FOR_EACH_BB_FN (bb, cfun) > + { > + if ((bb->flags & BB_REACHABLE)) > + continue; > + /* Try to find the entry to the unreachable region. */ > + bb = reverse_guess_deadend (bb); > + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); > + gsi_next (&gsi)) > + { > + /* Suppress warnings on BUILTINS_LOCATION which is used by the > + C and C++ frontends to emit the artifical return in main. */ > + if (LOCATION_LOCUS (gimple_location (gsi_stmt (gsi))) > + > BUILTINS_LOCATION) > + warning_at (gimple_location (gsi_stmt (gsi)), > + OPT_Wunreachable_code, "statement is not reachable"); > + break; > + } > + /* Mark blocks reachable from here. And even better make > + sure to process entries to unreachable regions first. */ > + mark_forward_reachable_blocks (bb); > + } > +} > + > static unsigned int > execute_build_cfg (void) > { > @@ -374,6 +457,14 @@ execute_build_cfg (void) > fprintf (dump_file, "Scope blocks:\n"); > dump_scope_blocks (dump_file, dump_flags); > } > + > + if (warn_unreachable_code) > + warn_unreachable_code_post_cfg_build (); > + > + /* Group case nodes. We did this prior to materializing edges in > + build_gimple_cfg to reduce the number of edges, that interferes > + with the -Wunreachable-code diagnostics above. */ > + group_case_labels (); > cleanup_tree_cfg (); > > bb_to_omp_idx.release (); > diff --git a/libgomp/oacc-plugin.c b/libgomp/oacc-plugin.c > index e25b462eff0..98166fe5cd1 100644 > --- a/libgomp/oacc-plugin.c > +++ b/libgomp/oacc-plugin.c > @@ -62,7 +62,6 @@ GOMP_PLUGIN_acc_default_dim (unsigned int i) > if (i >= GOMP_DIM_MAX) > { > gomp_fatal ("invalid dimension argument: %d", i); > - return -1; > } > return goacc_default_dims[i]; > } > -- > 2.31.1