2016-07-11 Marek Polacek <pola...@redhat.com> PR c/7652 * builtins.c (expand_builtin): Handle BUILT_IN_FALLTHROUGH. * builtins.def: Add BUILT_IN_FALLTHROUGH. * common.opt (Wswitch-fallthrough): New option. * doc/extend.texi: Document __builtin_fallthrough. * doc/invoke.texi: Document -Wswitch-fallthrough. * gimple-low.c: Include "diagnostic-core.h" and "gimple-walk.h". (purge_builtin_fallthrough_r): New function. (purge_builtin_fallthrough): Likewise. (lower_stmt): Call purge_builtin_fallthrough. * gimplify.c (struct label_entry): New struct. (find_label_entry): New function. (last_stmt_in_scope): Likewise. (warn_switch_fallthrough_r): Likewise. (maybe_warn_switch_fallthrough): Likewise. (gimplify_switch_expr): Call maybe_warn_switch_fallthrough. (gimplify_label_expr): New function. (gimplify_case_label_expr): Set location. (gimplify_expr): Call gimplify_label_expr. * system.h (gcc_fallthrough): New macro.
* c-c++-common/Wswitch-fallthrough-1.c: New test. * c-c++-common/Wswitch-fallthrough-10.c: New test. * c-c++-common/Wswitch-fallthrough-11.c: New test. * c-c++-common/Wswitch-fallthrough-12.c: New test. * c-c++-common/Wswitch-fallthrough-2.c: New test. * c-c++-common/Wswitch-fallthrough-3.c: New test. * c-c++-common/Wswitch-fallthrough-4.c: New test. * c-c++-common/Wswitch-fallthrough-5.c: New test. * c-c++-common/Wswitch-fallthrough-6.c: New test. * c-c++-common/Wswitch-fallthrough-7.c: New test. * c-c++-common/Wswitch-fallthrough-8.c: New test. * c-c++-common/Wswitch-fallthrough-9.c: New test. * c-c++-common/builtin-fallthrough-1.c: New test. * c-c++-common/builtin-fallthrough-2.c: New test. diff --git gcc/gcc/builtins.c gcc/gcc/builtins.c index 1465c60..c462bc5 100644 --- gcc/gcc/builtins.c +++ gcc/gcc/builtins.c @@ -6885,6 +6889,11 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, folding. */ break; + case BUILT_IN_FALLTHROUGH: + /* We should have gotten rid of this during gimplification. */ + error ("%Kinvalid use of %<__builtin_fallthrough ()%>", exp); + return const0_rtx; + default: /* just do library call, if unknown builtin */ break; } diff --git gcc/gcc/builtins.def gcc/gcc/builtins.def index 33a7626..c75f022 100644 --- gcc/gcc/builtins.def +++ gcc/gcc/builtins.def @@ -851,6 +851,7 @@ DEF_GCC_BUILTIN (BUILT_IN_VA_ARG_PACK, "va_arg_pack", BT_FN_INT, ATTR_PUR DEF_GCC_BUILTIN (BUILT_IN_VA_ARG_PACK_LEN, "va_arg_pack_len", BT_FN_INT, ATTR_PURE_NOTHROW_LEAF_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN__EXIT, "_exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN__EXIT2, "_Exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LEAF_LIST) +DEF_GCC_BUILTIN (BUILT_IN_FALLTHROUGH, "fallthrough", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) /* Implementing nested functions. */ DEF_BUILTIN_STUB (BUILT_IN_INIT_TRAMPOLINE, "__builtin_init_trampoline") diff --git gcc/gcc/common.opt gcc/gcc/common.opt index a7c5125..741da8d 100644 --- gcc/gcc/common.opt +++ gcc/gcc/common.opt @@ -707,6 +707,10 @@ Wsuggest-final-methods Common Var(warn_suggest_final_methods) Warning Warn about C++ virtual methods where adding final keyword would improve code quality. +Wswitch-fallthrough +Common Var(warn_switch_fallthrough) Warning Init(1) +Warn when a switch case falls through. + Wswitch-unreachable Common Var(warn_switch_unreachable) Warning Init(1) Warn about statements between switch's controlling expression and the first diff --git gcc/gcc/doc/extend.texi gcc/gcc/doc/extend.texi index 5b9e617..5fc129d 100644 --- gcc/gcc/doc/extend.texi +++ gcc/gcc/doc/extend.texi @@ -11127,6 +11127,25 @@ if (__builtin_expect (ptr != NULL, 1)) when testing pointer or floating-point values. @end deftypefn +@deftypefn {Built-in Function} void __builtin_fallthrough (void) +When the @option{-Wswitch-fallthrough} command-line options is enabled, the +compiler warns when a switch case statement falls through. To suppress +this warning in a case where the fall through is desirable, it is possible +to use this function as in the below: + +@smallexample +switch (cond) + @{ + case 1: + bar (0); + /* FALLTHRU */ + __builtin_fallthrough (); + default: + @dots{} + @} +@end smallexample +@end deftypefn + @deftypefn {Built-in Function} void __builtin_trap (void) This function causes the program to exit abnormally. GCC implements this function by using a target-dependent mechanism (such as diff --git gcc/gcc/doc/invoke.texi gcc/gcc/doc/invoke.texi index ba44951..0244643 100644 --- gcc/gcc/doc/invoke.texi +++ gcc/gcc/doc/invoke.texi @@ -300,7 +300,7 @@ Objective-C and Objective-C++ Dialects}. -Wsuggest-final-types @gol -Wsuggest-final-methods -Wsuggest-override @gol -Wmissing-format-attribute -Wsubobject-linkage @gol -Wswitch -Wswitch-bool -Wswitch-default -Wswitch-enum @gol --Wswitch-unreachable -Wsync-nand @gol +-Wswitch-fallthrough -Wswitch-unreachable -Wsync-nand @gol -Wsystem-headers -Wtautological-compare -Wtrampolines -Wtrigraphs @gol -Wtype-limits -Wundef @gol -Wuninitialized -Wunknown-pragmas -Wunsafe-loop-optimizations @gol @@ -4194,6 +4194,69 @@ switch ((int) (a == 4)) @end smallexample This warning is enabled by default for C and C++ programs. +@item -Wswitch-fallthrough +@opindex Wswitch-fallthrough +@opindex Wno-switch-fallthrough +Warn when a switch case falls through. For example: + +@smallexample +@group +switch (cond) + @{ + case 1: + a = 1; + break; + case 2: + a = 2; + case 3: + a = 3; + break; + @} +@end group +@end smallexample + +This warning does not warn when the last statement of a case cannot +fall through, e.g. when there is a return statement of a function +declared with the noreturn attribute. @option{-Wswitch-fallthrough} +also takes into account control flow statements, such as ifs, and only +warns when appropriate. E.g.@: + +@smallexample +@group +switch (cond) + @{ + case 1: + if (i > 3) @{ + bar (5); + break; + @} else if (i < 1) @{ + bar (0); + @} else + return; + default: + @dots{} + @} +@end group +@end smallexample + +Since there are occasions where a switch case fall through is desirable, +GCC provides a built-in function, @samp{__builtin_fallthrough}, which can +be used to suppres this warning what would normally occur: + +@smallexample +@group +switch (cond) + @{ + case 1: + bar (0); + /* FALLTHRU */ + __builtin_fallthrough (); + default: + @dots{} + @} +@end group +@end smallexample + @item -Wswitch-unreachable @opindex Wswitch-unreachable @opindex Wno-switch-unreachable diff --git gcc/gcc/gimple-low.c gcc/gcc/gimple-low.c index 9ea17af..70c957b 100644 --- gcc/gcc/gimple-low.c +++ gcc/gcc/gimple-low.c @@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see #include "calls.h" #include "gimple-iterator.h" #include "gimple-low.h" +#include "diagnostic-core.h" +#include "gimple-walk.h" /* The differences between High GIMPLE and Low GIMPLE are the following: @@ -220,6 +222,56 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data) gsi_next (gsi); } +/* Callback for walk_gimple_seq. */ + +static tree +purge_builtin_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, + struct walk_stmt_info *) +{ + gimple *stmt = gsi_stmt (*gsi_p); + + *handled_ops_p = true; + switch (gimple_code (stmt)) + { + case GIMPLE_TRY: + case GIMPLE_BIND: + case GIMPLE_CATCH: + case GIMPLE_EH_FILTER: + case GIMPLE_TRANSACTION: + /* Walk the sub-statements. */ + *handled_ops_p = false; + break; + case GIMPLE_CALL: + if (gimple_call_builtin_p (stmt, BUILT_IN_FALLTHROUGH)) + { + location_t bfloc = gimple_location (stmt); + gsi_remove (gsi_p, true); + if (gsi_end_p (*gsi_p)) + return integer_zero_node; + else if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL + || (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_GOTO + && !gimple_has_location (gsi_stmt (*gsi_p)))) + /* This usage is OK. */; + else + warning_at (bfloc, 0, "%<__builtin_fallthrough ()%> not " + "preceding a label"); + } + break; + default: + break; + } + return NULL_TREE; +} + +/* Remove all __builtin_fallthrough calls in SEQ. */ + +static void +purge_builtin_fallthrough (gimple_seq *seq_p) +{ + struct walk_stmt_info wi; + memset (&wi, 0, sizeof (wi)); + walk_gimple_seq_mod (seq_p, purge_builtin_fallthrough_r, NULL, &wi); +} /* Lower statement GSI. DATA is passed through the recursion. We try to track the fallthruness of statements and get rid of unreachable return @@ -242,9 +294,13 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) /* Propagate fallthruness. */ return; + case GIMPLE_SWITCH: + /* Get rid of __builtin_fallthrough. If they occur outside a case + sequence, we will complain later. */ + purge_builtin_fallthrough (&gsi->ptr); + gcc_fallthrough (); case GIMPLE_COND: case GIMPLE_GOTO: - case GIMPLE_SWITCH: data->cannot_fallthru = true; gsi_next (gsi); return; diff --git gcc/gcc/gimplify.c gcc/gcc/gimplify.c index 47c4d25..3b01cb4 100644 --- gcc/gcc/gimplify.c +++ gcc/gcc/gimplify.c @@ -1626,6 +1627,254 @@ maybe_warn_switch_unreachable (gimple_seq seq) } } + +/* A label entry that pairs label and a location. */ +struct label_entry +{ + tree label; + location_t loc; +}; + +/* Find LABEL in vector of label entries VEC. */ + +static struct label_entry * +find_label_entry (const auto_vec <struct label_entry> *vec, tree label) +{ + unsigned int i; + struct label_entry *l; + + FOR_EACH_VEC_ELT (*vec, i, l) + if (l->label == label) + return l; + return NULL; +} + +/* Find the last statement in a scope STMT. */ + +static gimple * +last_stmt_in_scope (gimple *stmt) +{ + if (!stmt) + return NULL; + + switch (gimple_code (stmt)) + { + case GIMPLE_BIND: + { + gbind *bind = as_a <gbind *> (stmt); + return last_stmt_in_scope ( + gimple_seq_last_stmt (gimple_bind_body (bind))); + } + + case GIMPLE_TRY: + { + gtry *try_stmt = as_a <gtry *> (stmt); + return last_stmt_in_scope ( + gimple_seq_last_stmt (gimple_try_eval (try_stmt))); + } + + default: + return stmt; + } +} + +/* Callback for walk_gimple_seq. */ + +static tree +warn_switch_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, + struct walk_stmt_info *) +{ + gimple *stmt = gsi_stmt (*gsi_p); + + *handled_ops_p = true; + switch (gimple_code (stmt)) + { + case GIMPLE_TRY: + case GIMPLE_BIND: + case GIMPLE_CATCH: + case GIMPLE_EH_FILTER: + case GIMPLE_TRANSACTION: + /* Walk the sub-statements. */ + *handled_ops_p = false; + break; + + /* Find a sequence of form: + + GIMPLE_LABEL + [...] + <may fallthru stmt> + GIMPLE_LABEL + + and possibly warn. */ + case GIMPLE_LABEL: + { + /* Found a label. Skip all immediately following labels. */ + while (!gsi_end_p (*gsi_p) + && gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL) + gsi_next (gsi_p); + + /* There might be no more statements. */ + if (gsi_end_p (*gsi_p)) + return integer_zero_node; + + /* Next statements, if any, are non-label. */ + gimple *prev = NULL; + /* Vector of labels that fall through. */ + auto_vec <struct label_entry> labels; + + do + { + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_BIND + || gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_TRY) + { + /* Nested scope. Only look at the last statement of + the innermost scope. */ + location_t bind_loc = gimple_location (gsi_stmt (*gsi_p)); + gimple *last = last_stmt_in_scope (gsi_stmt (*gsi_p)); + if (last) + { + prev = last; + /* It might be a label without a location. Use the + location of the scope then. */ + if (!gimple_has_location (prev)) + gimple_set_location (prev, bind_loc); + } + gsi_next (gsi_p); + continue; + } + /* If's are tricky. */ + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_COND) + { + gcond *cond_stmt = as_a <gcond *> (gsi_stmt (*gsi_p)); + tree false_lab = gimple_cond_false_label (cond_stmt); + location_t if_loc = gimple_location (cond_stmt); + + /* If we have e.g. + if (i > 1) goto <D.2259>; else goto D; + we can't do much with the else-branch. */ + if (!DECL_ARTIFICIAL (false_lab)) + break; + + /* Go on until the false label, then one step back. */ + for (; !gsi_end_p (*gsi_p); gsi_next (gsi_p)) + { + stmt = gsi_stmt (*gsi_p); + if (gimple_code (stmt) == GIMPLE_LABEL + && gimple_label_label (as_a <glabel *> (stmt)) + == false_lab) + break; + } + + /* Not found? Oops. */ + if (gsi_end_p (*gsi_p)) + break; + + { + struct label_entry l = { false_lab, if_loc }; + labels.safe_push (l); + } + + /* Go to the last statement of the then branch. */ + gsi_prev (gsi_p); + + /* if (i != 0) goto <D.1759>; else goto <D.1760>; + <D.1759>: + <stmt>; + goto <D.1761>; + <D.1760>: + */ + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_GOTO + && !gimple_has_location (gsi_stmt (*gsi_p))) + { + /* Look at the statement before, it might be + __builtin_fallthrough, in which case don't + warn. */ + gsi_prev (gsi_p); + bool fallthru_before_dest + = gimple_call_builtin_p (gsi_stmt (*gsi_p), + BUILT_IN_FALLTHROUGH); + gsi_next (gsi_p); + tree goto_dest = gimple_goto_dest (gsi_stmt (*gsi_p)); + if (!fallthru_before_dest) + { + struct label_entry l = { goto_dest, if_loc }; + labels.safe_push (l); + } + } + /* And move back. */ + gsi_next (gsi_p); + } + /* Remember the last statement. Skip labels that are of no + interest to us. */ + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL) + { + tree label + = gimple_label_label (as_a <glabel *> (gsi_stmt (*gsi_p))); + if (find_label_entry (&labels, label)) + prev = gsi_stmt (*gsi_p); + } + else + prev = gsi_stmt (*gsi_p); + gsi_next (gsi_p); + } + while (!gsi_end_p (*gsi_p) + /* Stop if we find a case or a user-defined label. */ + && (gimple_code (gsi_stmt (*gsi_p)) != GIMPLE_LABEL + || !gimple_has_location (gsi_stmt (*gsi_p)))); + + /* There might be no more statements. */ + if (gsi_end_p (*gsi_p)) + return integer_zero_node; + + gimple *next = gsi_stmt (*gsi_p); + /* If what follows is a label, then we may have a fallthrough. */ + if (gimple_code (next) == GIMPLE_LABEL + && gimple_has_location (next) + && prev != NULL) + { + tree label; + struct label_entry *l; + if (gimple_code (prev) == GIMPLE_LABEL + && (label = gimple_label_label (as_a <glabel *> (prev))) + && (l = find_label_entry (&labels, label)) + && warning_at (l->loc, OPT_Wswitch_fallthrough, + "this statement may fall through")) + inform (gimple_location (next), "here"); + else if (!gimple_call_builtin_p (prev, BUILT_IN_FALLTHROUGH) + /* Try to be clever and don't warn when the statement + can't actually fall through. */ + && gimple_stmt_may_fallthru (prev) + && gimple_has_location (prev) + && warning_at (gimple_location (prev), + OPT_Wswitch_fallthrough, + "this statement may fall through")) + inform (gimple_location (next), "here"); + + /* So that next warn_switch_fallthrough_r will start looking for + a new sequence starting with this label. */ + gsi_prev (gsi_p); + } + } + break; + default: + break; + } + return NULL_TREE; +} + +/* Warn when a switch case falls through. */ + +static void +maybe_warn_switch_fallthrough (gimple_seq seq) +{ + if (!warn_switch_fallthrough || lang_GNU_Fortran ()) + return; + + struct walk_stmt_info wi; + memset (&wi, 0, sizeof (wi)); + walk_gimple_seq (seq, warn_switch_fallthrough_r, NULL, &wi); +} + /* Gimplify a SWITCH_EXPR, and collect the vector of labels it can branch to. */ @@ -1664,6 +1913,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq); maybe_warn_switch_unreachable (switch_body_seq); + maybe_warn_switch_fallthrough (switch_body_seq); labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels = saved_labels; @@ -1694,6 +1944,21 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) return GS_ALL_DONE; } +/* Gimplify the LABEL_EXPR pointed to by EXPR_P. */ + +static enum gimplify_status +gimplify_label_expr (tree *expr_p, gimple_seq *pre_p) +{ + gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) + == current_function_decl); + + glabel *label_stmt = gimple_build_label (LABEL_EXPR_LABEL (*expr_p)); + gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p)); + gimplify_seq_add_stmt (pre_p, label_stmt); + + return GS_ALL_DONE; +} + /* Gimplify the CASE_LABEL_EXPR pointed to by EXPR_P. */ static enum gimplify_status @@ -1711,6 +1976,7 @@ gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p) break; label_stmt = gimple_build_label (CASE_LABEL (*expr_p)); + gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p)); ctxp->case_labels.safe_push (*expr_p); gimplify_seq_add_stmt (pre_p, label_stmt); @@ -10668,11 +10954,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; case LABEL_EXPR: - ret = GS_ALL_DONE; - gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) - == current_function_decl); - gimplify_seq_add_stmt (pre_p, - gimple_build_label (LABEL_EXPR_LABEL (*expr_p))); + ret = gimplify_label_expr (expr_p, pre_p); break; case CASE_LABEL_EXPR: diff --git gcc/gcc/system.h gcc/gcc/system.h index 78a7da6..14e4a1e 100644 --- gcc/gcc/system.h +++ gcc/gcc/system.h @@ -746,6 +746,12 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__)) #endif +#if GCC_VERSION >= 7000 +# define gcc_fallthrough() __builtin_fallthrough () +#else +# define gcc_fallthrough() +#endif + #if GCC_VERSION >= 3001 #define STATIC_CONSTANT_P(X) (__builtin_constant_p (X) && (X)) #else diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-1.c index e69de29..dc77bcc 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-1.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-1.c @@ -0,0 +1,38 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ +/* Test taken from + <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0188r0.pdf>. */ + +extern void f (int); + +void +foo (int n) +{ + switch (n) + { + case 22: + case 33: + f (1); /* { dg-warning "statement may fall through" } */ + case 44: + f (2); + __builtin_fallthrough (); + case 55: + if (n > 10) + { + f (3); + break; + } + else + { + f (4); + __builtin_fallthrough (); + } + case 66: + f (5); + __builtin_fallthrough (); /* { dg-warning "not preceding" } */ + f (6); /* { dg-warning "statement may fall through" } */ + case 77: + f (7); + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-10.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-10.c index e69de29..47e8894 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-10.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-10.c @@ -0,0 +1,227 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void bar (int); + +void +f (int i) +{ + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) + { + bar (1); + __builtin_fallthrough (); + } + else + break; + case 2:; + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 10) + { + bar (3); + __builtin_fallthrough (); + } + else + break; + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) /* { dg-warning "statement may fall through" } */ + { + bar (1); + } + else + break; + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) + { + bar (1); + break; + } + else + break; + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) + { + bar (1); + break; + } + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __builtin_fallthrough (); + } + else if (i > 10) + { + bar (1); + break; + } + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __builtin_fallthrough (); + } + else if (i > 10) + { + bar (1); + __builtin_fallthrough (); + } + else + break; + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __builtin_fallthrough (); + } + else if (i > 10) + { + bar (1); + __builtin_fallthrough (); + } + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __builtin_fallthrough (); + } + else if (i > 10) /* { dg-warning "statement may fall through" } */ + { + bar (1); + bar (2); + } + else + __builtin_fallthrough (); + case 2:; + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + bar (0); + } + else if (i > 10) + { + bar (1); + } + else + { + bar (1); + __builtin_fallthrough (); + } + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __builtin_fallthrough (); + } + else if (i > 10) + { + bar (1); + break; + } + else + { + bar (1); + __builtin_fallthrough (); + } + case 2:; + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) /* { dg-warning "statement may fall through" } */ + { + bar (1); + } + else + { + bar (1); + __builtin_fallthrough (); + } + case 2:; + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-11.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-11.c index e69de29..a204e75 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-11.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-11.c @@ -0,0 +1,23 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough -O2" } */ + +/* Prevent false positive with optimizations. */ + +extern void g (int); + +void +f (int i) +{ + switch (i) + { + case 1: + if (i > 10) + g (0); + else + goto L; + break; +L: + case 2:; + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-12.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-12.c index e69de29..7861a37 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-12.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-12.c @@ -0,0 +1,26 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough -O2" } */ + +/* Don't let optimizations preclude the warning. */ + +extern void bar (int); + +void +f (int i) +{ + switch (i) + { + case 1: + if (i > 1) + bar (1); + else + goto D; + break; + case 2: + bar (2); /* { dg-warning "statement may fall through" } */ + D: + default: + bar (33); + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-2.c index e69de29..d8cd826 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-2.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-2.c @@ -0,0 +1,223 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void bar (int); + +/* Test if without else. */ + +void +f (int i) +{ + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + goto L1; + case 2: +L1: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + goto L2; +L2: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L3; + break; + case 2: +L3: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L4; + break; +L4: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + if (i > 9) + bar (1); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + if (i > 9) + bar (1); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + { int a; } + { + if (i) /* { dg-warning "statement may fall through" } */ + if (i > 9) + bar (1); + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) + bar (3); + bar (4); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) /* { dg-warning "statement may fall through" } */ + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) + bar (3); + bar (4); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) + bar (3); + break; + case 2: + __builtin_abort (); + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-3.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-3.c index e69de29..a4d62d9 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-3.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-3.c @@ -0,0 +1,543 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void bar (int); + +/* Test if with else. */ + +void +f (int i) +{ + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + bar (2); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + bar (2); + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + return; + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + bar (9); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + } + else + bar (2); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + { + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + } + else + { + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + return; + else + { + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + } + else + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L1; + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: +L1: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L2; + else + bar (2); /* { dg-warning "statement may fall through" } */ +L2: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + goto L3; + case 2: +L3: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + goto L4; +L4: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L5; + else + goto L5; +L5: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + bar (2); + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + return; + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + bar (9); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + } + else + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + { + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + } + else + { + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + { + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + } + else + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L6; + else + bar (2); + break; + case 2: +L6: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L7; + else + bar (2); + break; +L7: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + goto L8; + break; + case 2: +L8: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + goto L9; + break; +L9: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L10; + else + goto L10; + break; +L10: + case 2: + __builtin_abort (); + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-4.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-4.c index e69de29..7229cde 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-4.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-4.c @@ -0,0 +1,250 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void bar (int); + +/* Test if with more elses. */ + +void +f (int i) +{ + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (2); + else if (i > 15) + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (2); + else if (i > 15) + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (4); + else if (i > 15) + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (4); + else if (i > 15) + return; + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) /* { dg-warning "statement may fall through" } */ + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) /* { dg-warning "statement may fall through" } */ + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + return; + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + return; + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) /* { dg-warning "statement may fall through" } */ + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) + return; + else + bar (4); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) + return; + else + return; + case 2: + __builtin_abort (); + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-5.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-5.c index e69de29..d11a413 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-5.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-5.c @@ -0,0 +1,109 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void bar (int); +extern void die (void) __attribute__((noreturn)); + +/* Test may_fallthru-ness. */ + +void +f (int i) +{ + switch (i) + { + case 1: + bar (0); + __builtin_fallthrough (); + case 2:; + } + + switch (i) + { + case 1: + bar (0); + return; + case 2:; + } + + switch (i) + { + case 1: + bar (0); + break; + case 2:; + } + + switch (i) + { + case 1: + bar (0); + goto L1; +L1: + case 2:; + } + + switch (i) + { + case 1: + bar (0); + die (); + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + __builtin_fallthrough (); + } + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + return; + } + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + break; + } + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + goto L2; + } +L2: + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + die (); + } + case 2:; + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-6.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-6.c index e69de29..2e16218 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-6.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-6.c @@ -0,0 +1,284 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void bar (int); + +/* Test nested scopes. */ + +void +f (int i) +{ + switch (i) + { + case 1: + { + int j; + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 10; /* { dg-warning "statement may fall through" } */ + } + case 2:; + } + + switch (i) + { + case 1: + { + int k = 9; + k++; + { + int j = 10; + j++; /* { dg-warning "statement may fall through" } */ + } + } + case 2:; + } + + switch (i) + { + case 1: + { + int k = 9; + k++; + { + int j = 10; + j++; + { + bar (1); /* { dg-warning "statement may fall through" } */ + } + } + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + __builtin_fallthrough (); + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + { + int k = j + 5; + bar (k); + __builtin_fallthrough (); + } + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + return; + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + goto L1; + } +L1: + case 2:; + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 112 } */ + int j = 0; + bar (j); + if (j == 8) + return; /* { dg-warning "statement may fall through" "" { target c++ } 116 } */ + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + return; + } + case 2:; + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 138 } */ + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + return; /* { dg-warning "statement may fall through" "" { target c++ } 144 } */ + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + bar (2); /* { dg-warning "statement may fall through" } */ + } + case 2:; + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 166 } */ + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + bar (2); /* { dg-warning "statement may fall through" "" { target c++ } 172 } */ + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + } + break; + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + return; + } + break; + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + return; + } + break; + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + bar (2); + } + break; + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + bar (2); + } + break; + case 2:; + } + + switch (i) + { + case 1: + { + int j = 9; + while (1); + } + case 2:; + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 263 } */ + int j = 9; + switch (j); /* { dg-warning "statement may fall through" "" { target c++ } 265 } */ + } + case 2:; + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + bar (2); + __builtin_fallthrough (); + } + case 2:; + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-7.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-7.c index e69de29..f864669 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-7.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-7.c @@ -0,0 +1,114 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void bar (int); +extern int bar2 (void); +extern int *map; +void +f (int i) +{ + switch (i) + { + case 1: + bar (0); /* { dg-warning "statement may fall through" } */ + static int i = 10; + case 2:; + } + + switch (i) + { + case 1: + { + int a[i]; /* { dg-warning "statement may fall through" } */ + } + case 2:; + } + + switch (i) + { + case 1: + for (int j = 0; j < 10; j++) /* { dg-warning "statement may fall through" "" { target c } 31 } */ + map[j] = j; /* { dg-warning "statement may fall through" "" { target c++ } 32 } */ + case 2:; + } + + switch (i) + { + case 1: + do /* { dg-warning "statement may fall through" "" { target c++ } 39 } */ + bar (2); + while (--i); /* { dg-warning "statement may fall through" "" { target c } 41 } */ + case 2:; + } + + switch (i) + { + case 1: + { + switch (i + 2) + case 4: + bar (1); /* { dg-warning "statement may fall through" } */ + case 5: + return; + } + case 2:; + } + + switch (i) + { + case 1:; + case 2:; + } + + switch (i) + { + } + + switch (i) + { + case 1: + if (i & 1) /* { dg-warning "statement may fall through" } */ + { + bar (23); + break; + } + case 2:; + } + + switch (i) + { + case 1: + if (i > 9) /* { dg-warning "statement may fall through" } */ + { + bar (9); + if (i == 10) + { + bar (10); + break; + } + } + case 2:; + } + + int r; + switch (i) + { + case 1: + r = bar2 (); + if (r) /* { dg-warning "statement may fall through" } */ + break; + case 2:; + } + + switch (i) + { + case 1: + r = bar2 (); + if (r) + return; + if (!i) /* { dg-warning "statement may fall through" } */ + return; + case 2:; + } +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-8.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-8.c index e69de29..508303d 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-8.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-8.c @@ -0,0 +1,99 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +extern void grace (int); + +int +fn1 (int i) +{ + switch (i) + case 1: + if (i == 5) + grace (0); + else + goto done; +done:; +} + +int +fn2 (int i) +{ + switch (i) + { + case 1: + if (i == 5) /* { dg-warning "statement may fall through" } */ + grace (0); + else + goto done; + case 2: + --i; + } +done:; +} + +int +fn3 (int i) +{ + switch (i) + { + case 1: + if (i == 5) + goto done; + else + goto done; + } +done:; +} + +int +fn4 (int i) +{ + switch (i) + { + case 1: + if (i == 5) + { + grace (1); + goto done; + } + else + goto done; + case 2:; + } +done:; +} + +int +fn5 (int i) +{ + switch (i) + { + case 1: + if (i == 5) + { + grace (1); + goto done; + } + else + grace (4); /* { dg-warning "statement may fall through" } */ + case 2:; + } +done:; +} + +int +fn6 (int i) +{ + switch (i) + { + case 1: + if (i == 5) /* { dg-warning "statement may fall through" } */ + { + grace (1); + goto done; + } + case 2:; + } +done:; +} diff --git gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-9.c gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-9.c index e69de29..b241009 100644 --- gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-9.c +++ gcc/gcc/testsuite/c-c++-common/Wswitch-fallthrough-9.c @@ -0,0 +1,26 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-fallthrough" } */ + +/* Test we don't remove __builtin_fallthrough too early. */ + +extern void h (int); + +void +g (int i) +{ + switch (i) + { + case 1: + { + switch (i) + { + case 3: + h (7); + __builtin_fallthrough (); + case 4:; + } + } + case 2:; + } +} diff --git gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-1.c index e69de29..6424278 100644 --- gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-1.c +++ gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-1.c @@ -0,0 +1,44 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wno-switch-unreachable" } */ + +extern void g (int); +void +f1 (int i) +{ + switch (i) + { + __builtin_fallthrough (); /* { dg-warning "not preceding" } */ + g (3); + case 5: + g (5); + __builtin_fallthrough (); /* { dg-warning "not preceding" } */ + g (7); + break; + __builtin_fallthrough (); + case 4: + g (9); + __builtin_fallthrough (); + case 51: + { + int l; + __builtin_fallthrough (); + } + case 52: + __builtin_fallthrough (); + } +} + +void +f2 (int i) +{ + if (i) + __builtin_fallthrough (); /* { dg-error "invalid use" } */ +} + +void +f3 (int i) +{ + switch (i) + __builtin_fallthrough (); +} diff --git gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-2.c index e69de29..dd4be9f 100644 --- gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-2.c +++ gcc/gcc/testsuite/c-c++-common/builtin-fallthrough-2.c @@ -0,0 +1,16 @@ +/* PR c/7652 */ +/* { dg-do compile } */ + +extern void g (int); + +void +f (int i) +{ + switch (i) + { + case 5: + g (5); + __builtin_fallthrough (1); /* { dg-error "too many" } */ + default:; + } +}