@@ -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;
}
@@ -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")
@@ -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
@@ -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
@@ -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
@@ -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;
@@ -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:
@@ -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
@@ -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);
+ }
+}
@@ -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:;
+ }
+}
@@ -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:;
+ }
+}
@@ -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);
+ }
+}
@@ -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 ();
+ }
+}
@@ -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 ();
+ }
+}
@@ -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 ();
+ }
+}
@@ -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:;
+ }
+}
@@ -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:;
+ }
+}
@@ -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:;
+ }
+}
@@ -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:;
+}
@@ -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:;
+ }
+}
@@ -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 ();
+}
@@ -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:;
+ }
+}