Implement -Wimplicit-fallthrough.

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>

From-SVN: r240485
This commit is contained in:
Marek Polacek 2016-09-26 09:42:50 +00:00 committed by Marek Polacek
parent 392fa55c79
commit 81fea426da
83 changed files with 4005 additions and 46 deletions

View File

@ -1,3 +1,59 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* Makefile.in (insn-attrtab.o-warn, insn-dfatab.o-warn,
insn-latencytab.o-warn, insn-output.o-warn, insn-emit.o-warn): Add
-Wno-switch-fallthrough.
* builtins.c (expand_builtin_int_roundingfn_2): Add gcc_fallthrough.
(expand_builtin): Likewise.
* config/rs6000/rs6000.c (rs6000_builtin_vectorized_libmass): Likewise.
* convert.c (convert_to_real_1): Likewise.
(convert_to_integer_1): Likewise.
* final.c (output_alternate_entry_point): Likewise.
* genattrtab.c (make_canonical): Likewise.
(write_test_expr): Likewise.
* genpreds.c (validate_exp): Likewise.
* gimple-ssa-strength-reduction.c
(find_candidates_dom_walker::before_dom_children): Likewise.
* godump.c (go_format_type): Likewise.
* reload1.c (elimination_effects): Likewise.
* resource.c (mark_referenced_resources): Likewise.
(mark_set_resources): Likewise.
* tree-ssa-loop-ivopts.c (find_deriving_biv_for_expr): Likewise.
* varasm.c (output_addressed_constants): Likewise.
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* common.opt (Wimplicit-fallthrough): New option.
* doc/extend.texi: Document statement attributes and the fallthrough
attribute.
* doc/invoke.texi: Document -Wimplicit-fallthrough.
* gimple.h (gimple_call_internal_p): New function.
* gimplify.c (struct gimplify_ctx): Add in_switch_expr.
(struct label_entry): New struct.
(find_label_entry): New function.
(case_label_p): New function.
(collect_fallthrough_labels): New function.
(last_stmt_in_scope): New function.
(should_warn_for_implicit_fallthrough): New function.
(warn_implicit_fallthrough_r): New function.
(maybe_warn_implicit_fallthrough): New function.
(expand_FALLTHROUGH_r): New function.
(expand_FALLTHROUGH): New function.
(gimplify_switch_expr): Call maybe_warn_implicit_fallthrough and
expand_FALLTHROUGH for the innermost GIMPLE_SWITCH.
(gimplify_label_expr): New function.
(gimplify_case_label_expr): Set location.
(gimplify_expr): Call gimplify_label_expr.
* internal-fn.c (expand_FALLTHROUGH): New function.
* internal-fn.def (FALLTHROUGH): New internal function.
* langhooks.c (lang_GNU_OBJC): New function.
* langhooks.h (lang_GNU_OBJC): Declare.
* system.h (gcc_fallthrough): Define.
* tree-core.h: Add FALLTHROUGH_LABEL_P comment.
* tree.h (FALLTHROUGH_LABEL_P): Define.
2016-09-26 Richard Biener <rguenther@suse.de>
* dwarf2out.c (stripattributes): Remove unused function.

View File

@ -218,6 +218,11 @@ libgcov-merge-tool.o-warn = -Wno-error
gimple-match.o-warn = -Wno-unused
generic-match.o-warn = -Wno-unused
dfp.o-warn = -Wno-strict-aliasing
insn-attrtab.o-warn = -Wno-implicit-fallthrough
insn-dfatab.o-warn = -Wno-implicit-fallthrough
insn-latencytab.o-warn = -Wno-implicit-fallthrough
insn-output.o-warn = -Wno-implicit-fallthrough
insn-emit.o-warn = -Wno-implicit-fallthrough
# All warnings have to be shut off in stage1 if the compiler used then
# isn't gcc; configure determines that. WARN_CFLAGS will be either

View File

@ -2586,7 +2586,7 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target)
{
CASE_FLT_FN (BUILT_IN_IRINT):
fallback_fn = BUILT_IN_LRINT;
/* FALLTHRU */
gcc_fallthrough ();
CASE_FLT_FN (BUILT_IN_LRINT):
CASE_FLT_FN (BUILT_IN_LLRINT):
builtin_optab = lrint_optab;
@ -2594,7 +2594,7 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target)
CASE_FLT_FN (BUILT_IN_IROUND):
fallback_fn = BUILT_IN_LROUND;
/* FALLTHRU */
gcc_fallthrough ();
CASE_FLT_FN (BUILT_IN_LROUND):
CASE_FLT_FN (BUILT_IN_LLROUND):
builtin_optab = lround_optab;
@ -5901,6 +5901,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
CASE_FLT_FN (BUILT_IN_ILOGB):
if (! flag_unsafe_math_optimizations)
break;
gcc_fallthrough ();
CASE_FLT_FN (BUILT_IN_ISINF):
CASE_FLT_FN (BUILT_IN_FINITE):
case BUILT_IN_ISFINITE:

View File

@ -1,3 +1,11 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* c-common.c (c_common_attribute_table): Add fallthrough attribute.
(handle_fallthrough_attribute): New function.
(attribute_fallthrough_p): New function.
* c-common.h (attribute_fallthrough_p): Declare.
2016-09-24 Marek Polacek <polacek@redhat.com>
PR c/77490

View File

@ -396,6 +396,7 @@ static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *);
static tree handle_bnd_variable_size_attribute (tree *, tree, tree, int, bool *);
static tree handle_bnd_legacy (tree *, tree, tree, int, bool *);
static tree handle_bnd_instrument (tree *, tree, tree, int, bool *);
static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
@ -847,6 +848,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_bnd_legacy, false },
{ "bnd_instrument", 0, 0, true, false, false,
handle_bnd_instrument, false },
{ "fallthrough", 0, 0, false, false, false,
handle_fallthrough_attribute, false },
{ NULL, 0, 0, false, false, false, NULL, false }
};
@ -9855,6 +9858,45 @@ handle_designated_init_attribute (tree *node, tree name, tree, int,
return NULL_TREE;
}
/* Handle a "fallthrough" attribute; arguments as in struct
attribute_spec.handler. */
static tree
handle_fallthrough_attribute (tree *, tree name, tree, int,
bool *no_add_attrs)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
return NULL_TREE;
}
/* Check whether ATTR is a valid attribute fallthrough. */
bool
attribute_fallthrough_p (tree attr)
{
tree t = lookup_attribute ("fallthrough", attr);
if (t == NULL_TREE)
return false;
/* This attribute shall appear at most once in each attribute-list. */
if (lookup_attribute ("fallthrough", TREE_CHAIN (t)))
warning (OPT_Wattributes, "%<fallthrough%> attribute specified multiple "
"times");
/* No attribute-argument-clause shall be present. */
else if (TREE_VALUE (t) != NULL_TREE)
warning (OPT_Wattributes, "%<fallthrough%> attribute specified with "
"a parameter");
/* Warn if other attributes are found. */
for (t = attr; t != NULL_TREE; t = TREE_CHAIN (t))
{
tree name = get_attribute_name (t);
if (!is_attribute_p ("fallthrough", name))
warning (OPT_Wattributes, "%qE attribute ignored", name);
}
return true;
}
/* Check for valid arguments being passed to a function with FNTYPE.
There are NARGS arguments in the array ARGARRAY. LOC should be used for

View File

@ -805,6 +805,7 @@ extern void check_function_arguments_recurse (void (*)
extern bool check_builtin_function_arguments (location_t, vec<location_t>,
tree, int, tree *);
extern void check_function_format (tree, int, tree *);
extern bool attribute_fallthrough_p (tree);
extern tree handle_unused_attribute (tree *, tree, tree, int, bool *);
extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);

View File

@ -1,3 +1,19 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* c-decl.c (pop_scope): Add gcc_fallthrough.
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* c-parser.c (struct c_token): Add flags field.
(c_lex_one_token): Pass it to c_lex_with_flags.
(c_parser_declaration_or_fndef): Turn __attribute__((fallthrough));
into IFN_FALLTHROUGH.
(c_parser_label): Set FALLTHROUGH_LABEL_P on labels. Handle
attribute fallthrough after a case label or default label.
(c_parser_statement_after_labels): Handle RID_ATTRIBUTE.
2016-09-24 Marek Polacek <polacek@redhat.com>
PR c/77490

View File

@ -1328,7 +1328,7 @@ pop_scope (void)
set_type_context (TREE_TYPE (p), context);
}
/* Fall through. */
gcc_fallthrough ();
/* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have
already been put there by store_parm_decls. Unused-
parameter warnings are handled by function.c.

View File

@ -193,6 +193,8 @@ struct GTY (()) c_token {
location_t location;
/* The value associated with this token, if any. */
tree value;
/* Token flags. */
unsigned char flags;
source_range get_range () const
{
@ -270,7 +272,8 @@ c_lex_one_token (c_parser *parser, c_token *token)
{
timevar_push (TV_LEX);
token->type = c_lex_with_flags (&token->value, &token->location, NULL,
token->type = c_lex_with_flags (&token->value, &token->location,
&token->flags,
(parser->lex_untranslated_string
? C_LEX_STRING_NO_TRANSLATE : 0));
token->id_kind = C_ID_NONE;
@ -1288,7 +1291,8 @@ static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
bool, bool, tree *, vec<c_token>,
struct oacc_routine_data * = NULL);
struct oacc_routine_data * = NULL,
bool * = NULL);
static void c_parser_static_assert_declaration_no_semi (c_parser *);
static void c_parser_static_assert_declaration (c_parser *);
static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
@ -1591,6 +1595,8 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
attributes; otherwise they may not.
OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed
declaration when parsing an Objective-C foreach statement.
FALLTHRU_ATTR_P is used to signal whether this function parsed
"__attribute__((fallthrough));".
declaration:
declaration-specifiers init-declarator-list[opt] ;
@ -1618,6 +1624,8 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
declaration-specifiers declarator declaration-list[opt]
compound-statement
attribute ;
Objective-C:
attributes objc-class-definition
attributes objc-category-definition
@ -1652,7 +1660,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool nested, bool start_attr_ok,
tree *objc_foreach_object_declaration,
vec<c_token> omp_declare_simd_clauses,
struct oacc_routine_data *oacc_routine_data)
struct oacc_routine_data *oacc_routine_data,
bool *fallthru_attr_p)
{
struct c_declspecs *specs;
tree prefix_attrs;
@ -1749,6 +1758,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
{
if (auto_type_p)
error_at (here, "%<__auto_type%> in empty declaration");
else if (specs->typespec_kind == ctsk_none
&& attribute_fallthrough_p (specs->attrs))
{
if (fallthru_attr_p != NULL)
*fallthru_attr_p = true;
tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH,
void_type_node, 0);
add_stmt (fn);
}
else if (empty_ok)
shadow_tag (specs);
else
@ -1851,7 +1869,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
break;
}
}
else if (attribute_fallthrough_p (specs->attrs))
warning_at (here, OPT_Wattributes,
"%<fallthrough%> attribute not followed by %<;%>");
pending_xref_error ();
prefix_attrs = specs->attrs;
all_prefix_attrs = prefix_attrs;
@ -4841,12 +4862,14 @@ c_parser_compound_statement_nostart (c_parser *parser)
{
last_label = false;
mark_valid_location_for_stdc_pragma (false);
bool fallthru_attr_p = false;
c_parser_declaration_or_fndef (parser, true, true, true, true,
true, NULL, vNULL);
if (last_stmt)
true, NULL, vNULL, NULL,
&fallthru_attr_p);
if (last_stmt && !fallthru_attr_p)
pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
"ISO C90 forbids mixed declarations and code");
last_stmt = false;
last_stmt = fallthru_attr_p;
}
else if (!last_label
&& c_parser_next_token_is_keyword (parser, RID_EXTENSION))
@ -4963,6 +4986,11 @@ c_parser_label (c_parser *parser)
{
location_t loc1 = c_parser_peek_token (parser)->location;
tree label = NULL_TREE;
/* Remember whether this case or a user-defined label is allowed to fall
through to. */
bool fallthrough_p = c_parser_peek_token (parser)->flags & PREV_FALLTHROUGH;
if (c_parser_next_token_is_keyword (parser, RID_CASE))
{
tree exp1, exp2;
@ -5009,6 +5037,33 @@ c_parser_label (c_parser *parser)
}
if (label)
{
if (TREE_CODE (label) == LABEL_EXPR)
FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p;
else
FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p;
/* Allow '__attribute__((fallthrough));'. */
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
{
location_t loc = c_parser_peek_token (parser)->location;
tree attrs = c_parser_attributes (parser);
if (attribute_fallthrough_p (attrs))
{
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
tree fn = build_call_expr_internal_loc (loc,
IFN_FALLTHROUGH,
void_type_node, 0);
add_stmt (fn);
}
else
warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute "
"not followed by %<;%>");
}
else if (attrs != NULL_TREE)
warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
" can be applied to a null statement");
}
if (c_parser_next_tokens_start_declaration (parser))
{
error_at (c_parser_peek_token (parser)->location,
@ -5062,6 +5117,9 @@ c_parser_label (c_parser *parser)
jump-statement:
goto * expression ;
expression-statement:
attributes ;
Objective-C:
statement:
@ -5323,6 +5381,31 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
gcc_assert (c_dialect_objc ());
c_parser_objc_synchronized_statement (parser);
break;
case RID_ATTRIBUTE:
{
/* Allow '__attribute__((fallthrough));'. */
tree attrs = c_parser_attributes (parser);
if (attribute_fallthrough_p (attrs))
{
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
tree fn = build_call_expr_internal_loc (loc,
IFN_FALLTHROUGH,
void_type_node, 0);
add_stmt (fn);
/* Eat the ';'. */
c_parser_consume_token (parser);
}
else
warning_at (loc, OPT_Wattributes,
"%<fallthrough%> attribute not followed "
"by %<;%>");
}
else if (attrs != NULL_TREE)
warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
" can be applied to a null statement");
break;
}
default:
goto expr_stmt;
}

View File

@ -601,6 +601,10 @@ Whsa
Common Var(warn_hsa) Init(1) Warning
Warn when a function cannot be expanded to HSAIL.
Wimplicit-fallthrough
Common Var(warn_implicit_fallthrough) Warning EnabledBy(Wextra)
Warn when a switch case falls through.
Winline
Common Var(warn_inline) Warning
Warn when an inlined function cannot be inlined.

View File

@ -5489,7 +5489,7 @@ rs6000_builtin_vectorized_libmass (combined_fn fn, tree type_out,
CASE_CFN_HYPOT:
CASE_CFN_POW:
n_args = 2;
/* fall through */
gcc_fallthrough ();
CASE_CFN_ACOS:
CASE_CFN_ACOSH:

View File

@ -164,6 +164,7 @@ convert_to_real_1 (tree type, tree expr, bool fold_p)
-fmath-errno. */
if (flag_errno_math)
break;
gcc_fallthrough ();
CASE_MATHFN (ACOS)
CASE_MATHFN (ACOSH)
CASE_MATHFN (ASIN)
@ -184,6 +185,7 @@ convert_to_real_1 (tree type, tree expr, bool fold_p)
/* The above functions are not safe to do this conversion. */
if (!flag_unsafe_math_optimizations)
break;
gcc_fallthrough ();
CASE_MATHFN (SQRT)
CASE_MATHFN (FABS)
CASE_MATHFN (LOGB)
@ -516,7 +518,7 @@ convert_to_integer_1 (tree type, tree expr, bool dofold)
/* Only convert nearbyint* if we can ignore math exceptions. */
if (flag_trapping_math)
break;
/* ... Fall through ... */
gcc_fallthrough ();
CASE_FLT_FN (BUILT_IN_RINT):
/* Only convert in ISO C99 mode and with -fno-math-errno. */
if (!targetm.libc_has_function (function_c99_misc) || flag_errno_math)

View File

@ -1,3 +1,33 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* parser.c (cp_parser_storage_class_specifier_opt): Add
gcc_fallthrough.
(cp_parser_skip_to_end_of_template_parameter_list): Likewise.
(cp_parser_cache_defarg): Likewise.
(cp_parser_omp_for_cond): Likewise.
* semantics.c (finish_decltype_type): Likewise.
* typeck.c (structural_comptypes): Likewise.
(cp_build_binary_op): Likewise.
(cp_build_modify_expr): Likewise.
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* constexpr.c (cxx_eval_internal_function): Handle IFN_FALLTHROUGH.
(potential_constant_expression_1): Likewise.
* constraint.cc (function_concept_check_p): Check fn for null.
* parser.c (cp_parser_expression_statement): Handle attribute
fallthrough.
(cp_parser_statement): Likewise.
(cp_parser_label_for_labeled_statement): Set FALLTHROUGH_LABEL_P on
labels.
(cp_parser_std_attribute): Handle fallthrough attribute.
(cp_parser_check_std_attribute): Add %< %> quotes.
* pt.c (tsubst_copy_and_build): Handle internal functions.
(instantiation_dependent_scope_ref_p): Return if the expression is
null.
2016-09-24 Marek Polacek <polacek@redhat.com>
PR c/77490

View File

@ -1303,6 +1303,7 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
case IFN_UBSAN_NULL:
case IFN_UBSAN_BOUNDS:
case IFN_UBSAN_VPTR:
case IFN_FALLTHROUGH:
return void_node;
case IFN_ADD_OVERFLOW:
@ -4826,6 +4827,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
case IFN_UBSAN_NULL:
case IFN_UBSAN_BOUNDS:
case IFN_UBSAN_VPTR:
case IFN_FALLTHROUGH:
return true;
case IFN_ADD_OVERFLOW:

View File

@ -116,7 +116,8 @@ function_concept_check_p (tree t)
{
gcc_assert (TREE_CODE (t) == CALL_EXPR);
tree fn = CALL_EXPR_FN (t);
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR
if (fn != NULL_TREE
&& TREE_CODE (fn) == TEMPLATE_ID_EXPR
&& TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD)
{
tree f1 = get_first_fn (fn);

View File

@ -10585,14 +10585,31 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
}
/* Look for an expression-statement instead. */
statement = cp_parser_expression_statement (parser, in_statement_expr);
/* Handle [[fallthrough]];. */
if (attribute_fallthrough_p (std_attrs))
{
/* The next token after the fallthrough attribute is ';'. */
if (statement == NULL_TREE)
{
/* Turn [[fallthrough]]; into FALLTHROUGH ();. */
statement = build_call_expr_internal_loc (statement_location,
IFN_FALLTHROUGH,
void_type_node, 0);
finish_expr_stmt (statement);
}
else
warning_at (statement_location, OPT_Wattributes,
"%<fallthrough%> attribute not followed by %<;%>");
std_attrs = NULL_TREE;
}
}
/* Set the line number for the statement. */
if (statement && STATEMENT_CODE_P (TREE_CODE (statement)))
SET_EXPR_LOCATION (statement, statement_location);
/* Note that for now, we don't do anything with c++11 statements
parsed at this level. */
/* Allow "[[fallthrough]];", but warn otherwise. */
if (std_attrs != NULL_TREE)
warning_at (attrs_location,
OPT_Wattributes,
@ -10628,6 +10645,10 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
return;
}
/* Remember whether this case or a user-defined label is allowed to fall
through to. */
bool fallthrough_p = token->flags & PREV_FALLTHROUGH;
parser->colon_corrects_to_scope_p = false;
switch (token->keyword)
{
@ -10659,7 +10680,11 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
expr_hi = NULL_TREE;
if (parser->in_switch_statement_p)
finish_case_label (token->location, expr, expr_hi);
{
tree l = finish_case_label (token->location, expr, expr_hi);
if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
}
else
error_at (token->location,
"case label %qE not within a switch statement",
@ -10672,7 +10697,11 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
cp_lexer_consume_token (parser->lexer);
if (parser->in_switch_statement_p)
finish_case_label (token->location, NULL_TREE, NULL_TREE);
{
tree l = finish_case_label (token->location, NULL_TREE, NULL_TREE);
if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
}
else
error_at (token->location, "case label not within a switch statement");
break;
@ -10680,6 +10709,8 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
default:
/* Anything else must be an ordinary label. */
label = finish_label_stmt (cp_parser_identifier (parser));
if (label && TREE_CODE (label) == LABEL_DECL)
FALLTHROUGH_LABEL_P (label) = fallthrough_p;
break;
}
@ -10728,6 +10759,10 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
{
tree statement = NULL_TREE;
cp_token *token = cp_lexer_peek_token (parser->lexer);
location_t loc = token->location;
/* There might be attribute fallthrough. */
tree attr = cp_parser_gnu_attributes_opt (parser);
/* If the next token is a ';', then there is no expression
statement. */
@ -10742,6 +10777,25 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
}
}
/* Handle [[fallthrough]];. */
if (attribute_fallthrough_p (attr))
{
/* The next token after the fallthrough attribute is ';'. */
if (statement == NULL_TREE)
/* Turn [[fallthrough]]; into FALLTHROUGH ();. */
statement = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
void_type_node, 0);
else
warning_at (loc, OPT_Wattributes,
"%<fallthrough%> attribute not followed by %<;%>");
attr = NULL_TREE;
}
/* Allow "[[fallthrough]];", but warn otherwise. */
if (attr != NULL_TREE)
warning_at (loc, OPT_Wattributes,
"attributes at the beginning of statement are ignored");
/* Give a helpful message for "A<T>::type t;" and the like. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
&& !cp_parser_uncommitted_to_tentative_parse_p (parser))
@ -12980,6 +13034,7 @@ cp_parser_storage_class_specifier_opt (cp_parser* parser)
if (cxx_dialect != cxx98)
return NULL_TREE;
/* Fall through for C++98. */
gcc_fallthrough ();
case RID_REGISTER:
case RID_STATIC:
@ -24116,7 +24171,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
if (is_attribute_p ("noreturn", attr_id))
TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
/* C++14 deprecated attribute is equivalent to GNU's. */
else if (cxx_dialect >= cxx11 && is_attribute_p ("deprecated", attr_id))
else if (is_attribute_p ("deprecated", attr_id))
{
if (cxx_dialect == cxx11)
pedwarn (token->location, OPT_Wpedantic,
@ -24124,6 +24179,15 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
" use %<gnu::deprecated%>");
TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
}
/* C++17 fallthrough attribute is equivalent to GNU's. */
else if (is_attribute_p ("fallthrough", attr_id))
{
if (cxx_dialect < cxx1z)
pedwarn (token->location, OPT_Wpedantic,
"%<fallthrough%> is a C++17 feature;"
" use %<gnu::fallthrough%>");
TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
}
/* Transactional Memory TS optimize_for_synchronized attribute is
equivalent to GNU transaction_callable. */
else if (is_attribute_p ("optimize_for_synchronized", attr_id))
@ -24182,11 +24246,11 @@ cp_parser_check_std_attribute (tree attributes, tree attribute)
tree name = get_attribute_name (attribute);
if (is_attribute_p ("noreturn", name)
&& lookup_attribute ("noreturn", attributes))
error ("attribute noreturn can appear at most once "
error ("attribute %<noreturn%> can appear at most once "
"in an attribute-list");
else if (is_attribute_p ("deprecated", name)
&& lookup_attribute ("deprecated", attributes))
error ("attribute deprecated can appear at most once "
error ("attribute %<deprecated%> can appear at most once "
"in an attribute-list");
}
}
@ -27303,6 +27367,7 @@ cp_parser_skip_to_end_of_template_parameter_list (cp_parser* parser)
}
/* Fall through for C++0x, so we handle the second `>' in
the `>>'. */
gcc_fallthrough ();
case CPP_GREATER:
if (!nesting_depth && level-- == 0)
@ -27760,6 +27825,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
/* Fall through for C++0x, which treats the `>>'
operator like two `>' tokens in certain
cases. */
gcc_fallthrough ();
case CPP_GREATER:
if (depth == 0)
@ -33402,6 +33468,7 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code)
if (code == CILK_SIMD || code == CILK_FOR)
break;
/* Fall through: OpenMP disallows NE_EXPR. */
gcc_fallthrough ();
default:
return error_mark_node;
}

View File

@ -16556,7 +16556,16 @@ tsubst_copy_and_build (tree t,
tree ret;
function = CALL_EXPR_FN (t);
/* When we parsed the expression, we determined whether or
if (function == NULL_TREE)
{
/* If you hit this assert, it means that you're trying to tsubst
an internal function with arguments. This isn't yet supported,
so you need to build another internal call with the tsubsted
arguments after the arguments have been tsubsted down below. */
gcc_assert (call_expr_nargs (t) == 0);
RETURN (t);
}
/* When we parsed the expression, we determined whether or
not Koenig lookup should be performed. */
koenig_p = KOENIG_LOOKUP_P (t);
if (TREE_CODE (function) == SCOPE_REF)
@ -22787,7 +22796,7 @@ instantiation_dependent_scope_ref_p (tree t)
bool
value_dependent_expression_p (tree expression)
{
if (!processing_template_decl)
if (!processing_template_decl || expression == NULL_TREE)
return false;
/* A name declared with a dependent type. */

View File

@ -8894,6 +8894,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
break;
}
/* Fall through for fields that aren't bitfields. */
gcc_fallthrough ();
case FUNCTION_DECL:
case VAR_DECL:

View File

@ -1306,6 +1306,7 @@ structural_comptypes (tree t1, tree t2, int strict)
if (TYPE_REF_IS_RVALUE (t1) != TYPE_REF_IS_RVALUE (t2))
return false;
/* fall through to checks for pointer types */
gcc_fallthrough ();
case POINTER_TYPE:
if (TYPE_MODE (t1) != TYPE_MODE (t2)
@ -4265,6 +4266,7 @@ cp_build_binary_op (location_t location,
}
/* The pointer - int case is just like pointer + int; fall
through. */
gcc_fallthrough ();
case PLUS_EXPR:
if ((code0 == POINTER_TYPE || code1 == POINTER_TYPE)
&& (code0 == INTEGER_TYPE || code1 == INTEGER_TYPE))
@ -7554,7 +7556,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
TREE_OPERAND (lhs, 1)),
TREE_OPERAND (lhs, 0),
TREE_OPERAND (lhs, 1));
/* Fall through. */
gcc_fallthrough ();
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:

View File

@ -60,6 +60,7 @@ extensions, accepted by GCC in C90 mode and in C++.
* Type Attributes:: Specifying attributes of types.
* Label Attributes:: Specifying attributes on labels.
* Enumerator Attributes:: Specifying attributes on enumerators.
* Statement Attributes:: Specifying attributes on statements.
* Attribute Syntax:: Formal syntax for attributes.
* Function Prototypes:: Prototype declarations and old-style definitions.
* C++ Comments:: C++ comments are recognized.
@ -2261,6 +2262,7 @@ GCC also supports attributes on
variable declarations (@pxref{Variable Attributes}),
labels (@pxref{Label Attributes}),
enumerators (@pxref{Enumerator Attributes}),
statements (@pxref{Statement Attributes}),
and types (@pxref{Type Attributes}).
There is some overlap between the purposes of attributes and pragmas
@ -5558,8 +5560,8 @@ attributes are currently defined generically for variables.
Other attributes are defined for variables on particular target
systems. Other attributes are available for functions
(@pxref{Function Attributes}), labels (@pxref{Label Attributes}),
enumerators (@pxref{Enumerator Attributes}), and for types
(@pxref{Type Attributes}).
enumerators (@pxref{Enumerator Attributes}), statements
(@pxref{Statement Attributes}), and for types (@pxref{Type Attributes}).
Other front ends might define more attributes
(@pxref{C++ Extensions,,Extensions to the C++ Language}).
@ -6340,7 +6342,8 @@ attributes of types. Some type attributes apply only to @code{struct}
and @code{union} types, while others can apply to any type defined
via a @code{typedef} declaration. Other attributes are defined for
functions (@pxref{Function Attributes}), labels (@pxref{Label
Attributes}), enumerators (@pxref{Enumerator Attributes}), and for
Attributes}), enumerators (@pxref{Enumerator Attributes}),
statements (@pxref{Statement Attributes}), and for
variables (@pxref{Variable Attributes}).
The @code{__attribute__} keyword is followed by an attribute specification
@ -6850,7 +6853,8 @@ GCC allows attributes to be set on C labels. @xref{Attribute Syntax}, for
details of the exact syntax for using attributes. Other attributes are
available for functions (@pxref{Function Attributes}), variables
(@pxref{Variable Attributes}), enumerators (@pxref{Enumerator Attributes}),
and for types (@pxref{Type Attributes}).
statements (@pxref{Statement Attributes}), and for types
(@pxref{Type Attributes}).
This example uses the @code{cold} label attribute to indicate the
@code{ErrorHandling} branch is unlikely to be taken and that the
@ -6903,8 +6907,8 @@ with computed goto or @code{asm goto}.
GCC allows attributes to be set on enumerators. @xref{Attribute Syntax}, for
details of the exact syntax for using attributes. Other attributes are
available for functions (@pxref{Function Attributes}), variables
(@pxref{Variable Attributes}), labels (@pxref{Label Attributes}),
and for types (@pxref{Type Attributes}).
(@pxref{Variable Attributes}), labels (@pxref{Label Attributes}), statements
(@pxref{Statement Attributes}), and for types (@pxref{Type Attributes}).
This example uses the @code{deprecated} enumerator attribute to indicate the
@code{oldval} enumerator is deprecated:
@ -6935,6 +6939,46 @@ do instead. Note that the warnings only occurs for uses.
@end table
@node Statement Attributes
@section Statement Attributes
@cindex Statement Attributes
GCC allows attributes to be set on null statements. @xref{Attribute Syntax},
for details of the exact syntax for using attributes. Other attributes are
available for functions (@pxref{Function Attributes}), variables
(@pxref{Variable Attributes}), labels (@pxref{Label Attributes}), enumerators
(@pxref{Enumerator Attributes}), and for types (@pxref{Type Attributes}).
This example uses the @code{fallthrough} statement attribute to indicate that
the @option{-Wimplicit-fallthrough} warning should not be emitted:
@smallexample
switch (cond)
@{
case 1:
bar (1);
__attribute__((fallthrough));
case 2:
@dots{}
@}
@end smallexample
@table @code
@item fallthrough
@cindex @code{fallthrough} statement attribute
The @code{fallthrough} attribute with a null statement serves as a
fallthrough statement. It hints to the compiler that a statement
that falls through to another case label, or user-defined label
in a switch statement is intentional and thus the
@option{-Wimplicit-fallthrough} warning must not trigger. The
fallthrough attribute may appear at most once in each attribute
list, and may not be mixed with other attributes. It can only
be used in a switch statement (the compiler will issue an error
otherwise), after a preceding statement and before a logically
succeeding case label, or user-defined label.
@end table
@node Attribute Syntax
@section Attribute Syntax
@cindex attribute syntax
@ -6962,6 +7006,8 @@ and enumerated types.
applying to labels.
@xref{Enumerator Attributes}, for details of the semantics of attributes
applying to enumerators.
@xref{Statement Attributes}, for details of the semantics of attributes
applying to statements.
An @dfn{attribute specifier} is of the form
@code{__attribute__ ((@var{attribute-list}))}. An @dfn{attribute list}
@ -7027,6 +7073,10 @@ present. The optional attribute in the enumerator appertains to the
enumeration constant. It is not possible to place the attribute after
the constant expression, if present.
@subsubheading Statement Attributes
In GNU C, an attribute specifier list may appear as part of a null
statement. The attribute goes before the semicolon.
@subsubheading Type Attributes
An attribute specifier list may appear as part of a @code{struct},

View File

@ -273,7 +273,8 @@ Objective-C and Objective-C++ Dialects}.
-Wformat-security -Wformat-signedness -Wformat-y2k -Wframe-address @gol
-Wframe-larger-than=@var{len} -Wno-free-nonheap-object -Wjump-misses-init @gol
-Wignored-qualifiers -Wignored-attributes -Wincompatible-pointer-types @gol
-Wimplicit -Wimplicit-function-declaration -Wimplicit-int @gol
-Wimplicit -Wimplicit-fallthrough -Wimplicit-function-declaration @gol
-Wimplicit-int @gol
-Winit-self -Winline -Wno-int-conversion -Wint-in-bool-context @gol
-Wno-int-to-pointer-cast -Winvalid-memory-model -Wno-invalid-offsetof @gol
-Winvalid-pch -Wlarger-than=@var{len} @gol
@ -3719,6 +3720,7 @@ name is still supported, but the newer name is more descriptive.)
@gccoptlist{-Wclobbered @gol
-Wempty-body @gol
-Wignored-qualifiers @gol
-Wimplicit-fallthrough @gol
-Wmissing-field-initializers @gol
-Wmissing-parameter-type @r{(C only)} @gol
-Wold-style-declaration @r{(C only)} @gol
@ -4087,6 +4089,93 @@ enabled by default and it is made into an error by
Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
This warning is enabled by @option{-Wall}.
@item -Wimplicit-fallthrough
@opindex Wimplicit-fallthrough
@opindex Wno-implicit-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 or a call to function
declared with the noreturn attribute. @option{-Wimplicit-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 an attribute, @code{__attribute__ ((fallthrough))}, that is
to be used along with a null statement to suppress this warning that
would normally occur:
@smallexample
@group
switch (cond)
@{
case 1:
bar (0);
__attribute__ ((fallthrough));
default:
@dots{}
@}
@end group
@end smallexample
C++17 provides a standard way to suppress the @option{-Wimplicit-fallthrough}
warning using @code{[[fallthrough]];} instead of the GNU attribute. In C++11
or C++14 users can use @code{[[gnu::fallthrough]];}, which is a GNU extension.
Instead of the these attributes, it is also possible to add a "falls through"
comment to silence the warning. GCC accepts a wide range of such comments,
for example all of "Falls through.", "fallthru", "FALLS-THROUGH" work. This
comment needs to consist of two words merely, optionally followed by periods
or whitespaces.
@smallexample
@group
switch (cond)
@{
case 1:
bar (0);
/* FALLTHRU */
default:
@dots{}
@}
@end group
@end smallexample
This warning is enabled by @option{-Wextra}.
@item -Wignored-qualifiers @r{(C and C++ only)}
@opindex Wignored-qualifiers
@opindex Wno-ignored-qualifiers

View File

@ -2096,9 +2096,11 @@ output_alternate_entry_point (FILE *file, rtx_insn *insn)
case LABEL_WEAK_ENTRY:
#ifdef ASM_WEAKEN_LABEL
ASM_WEAKEN_LABEL (file, name);
gcc_fallthrough ();
#endif
case LABEL_GLOBAL_ENTRY:
targetm.asm_out.globalize_label (file, name);
gcc_fallthrough ();
case LABEL_STATIC_ENTRY:
#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");

View File

@ -1,3 +1,15 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* arith.c (eval_intrinsic): Add gcc_fallthrough.
* frontend-passes.c (optimize_op): Likewise.
(gfc_expr_walker): Likewise.
* parse.c (next_fixed): Likewise.
* primary.c (match_variable): Likewise.
* trans-array.c: Likewise.
* trans-expr.c (flatten_array_ctors_without_strlen): Likewise.
* trans-io.c (transfer_expr): Likewise.
2016-09-25 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/77429

View File

@ -1521,7 +1521,7 @@ eval_intrinsic (gfc_intrinsic_op op,
break;
}
/* Fall through */
gcc_fallthrough ();
/* Numeric binary */
case INTRINSIC_PLUS:
case INTRINSIC_MINUS:

View File

@ -1481,7 +1481,7 @@ optimize_op (gfc_expr *e)
case INTRINSIC_LT:
changed = optimize_comparison (e, op);
/* Fall through */
gcc_fallthrough ();
/* Look at array constructors. */
case INTRINSIC_PLUS:
case INTRINSIC_MINUS:
@ -3349,6 +3349,7 @@ gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data)
/* Fall through to the variable case in order to walk the
reference. */
gcc_fallthrough ();
case EXPR_SUBSTRING:
case EXPR_VARIABLE:

View File

@ -1261,7 +1261,7 @@ next_fixed (void)
return decode_oacc_directive ();
}
}
/* FALLTHROUGH */
gcc_fallthrough ();
/* Comments have already been skipped by the time we get
here so don't bother checking for them. */

View File

@ -3572,6 +3572,7 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag)
break;
/* Fall through to error */
gcc_fallthrough ();
default:
gfc_error ("%qs at %C is not a variable", sym->name);

View File

@ -4032,6 +4032,7 @@ done:
continue;
}
/* Otherwise fall through GFC_SS_FUNCTION. */
gcc_fallthrough ();
}
case GFC_ISYM_LCOBOUND:
case GFC_ISYM_UCOBOUND:

View File

@ -2208,6 +2208,7 @@ flatten_array_ctors_without_strlen (gfc_expr* e)
}
/* Otherwise, fall through to handle constructor elements. */
gcc_fallthrough ();
case EXPR_STRUCTURE:
for (c = gfc_constructor_first (e->value.constructor);
c; c = gfc_constructor_next (c))

View File

@ -2384,6 +2384,7 @@ transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr,
}
/* If a CLASS object gets through to here, fall through and ICE. */
}
gcc_fallthrough ();
default:
gfc_internal_error ("Bad IO basetype (%d)", ts->type);
}

View File

@ -1219,6 +1219,7 @@ make_canonical (file_location loc, struct attr_desc *attr, rtx exp)
exp = newexp;
/* Fall through to COND case since this is now a COND. */
gcc_fallthrough ();
case COND:
{
@ -3615,6 +3616,7 @@ write_test_expr (FILE *outf, rtx exp, unsigned int attrs_cached, int flags,
}
/* Otherwise, fall through to normal unary operator. */
gcc_fallthrough ();
/* Unary operators. */
case ABS: case NEG:

View File

@ -74,7 +74,7 @@ validate_exp (rtx exp, const char *name, file_location loc)
}
}
}
/* fall through */
gcc_fallthrough ();
/* These need no special checking. */
case MATCH_OPERAND:

View File

@ -1690,7 +1690,7 @@ find_candidates_dom_walker::before_dom_children (basic_block bb)
case POINTER_PLUS_EXPR:
case MINUS_EXPR:
rhs2 = gimple_assign_rhs2 (gs);
/* Fall-through. */
gcc_fallthrough ();
CASE_CONVERT:
case MODIFY_EXPR:

View File

@ -2921,6 +2921,16 @@ gimple_call_internal_unique_p (const gimple *gs)
return gimple_call_internal_unique_p (gc);
}
/* Return true if GS is an internal function FN. */
static inline bool
gimple_call_internal_p (const gimple *gs, internal_fn fn)
{
return (is_gimple_call (gs)
&& gimple_call_internal_p (gs)
&& gimple_call_internal_fn (gs) == fn);
}
/* If CTRL_ALTERING_P is true, mark GIMPLE_CALL S to be a stmt
that could alter control flow. */

View File

@ -160,6 +160,7 @@ struct gimplify_ctx
unsigned in_cleanup_point_expr : 1;
unsigned keep_stack : 1;
unsigned save_stack : 1;
unsigned in_switch_expr : 1;
};
struct gimplify_omp_ctx
@ -1626,6 +1627,430 @@ 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;
}
/* Return true if LABEL, a LABEL_DECL, represents a case label
in a vector of labels CASES. */
static bool
case_label_p (const vec<tree> *cases, tree label)
{
unsigned int i;
tree l;
FOR_EACH_VEC_ELT (*cases, i, l)
if (CASE_LABEL (l) == label)
return true;
return false;
}
/* 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);
stmt = gimple_seq_last_stmt (gimple_bind_body (bind));
return last_stmt_in_scope (stmt);
}
case GIMPLE_TRY:
{
gtry *try_stmt = as_a <gtry *> (stmt);
stmt = gimple_seq_last_stmt (gimple_try_eval (try_stmt));
gimple *last_eval = last_stmt_in_scope (stmt);
if (gimple_stmt_may_fallthru (last_eval)
&& gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY)
{
stmt = gimple_seq_last_stmt (gimple_try_cleanup (try_stmt));
return last_stmt_in_scope (stmt);
}
else
return last_eval;
}
default:
return stmt;
}
}
/* Collect interesting labels in LABELS and return the statement preceding
another case label, or a user-defined label. */
static gimple *
collect_fallthrough_labels (gimple_stmt_iterator *gsi_p,
auto_vec <struct label_entry> *labels)
{
gimple *prev = NULL;
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;
}
/* Ifs 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))
{
gimple *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
attribute fallthrough, in which case don't warn. */
gsi_prev (gsi_p);
bool fallthru_before_dest
= gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_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))));
return prev;
}
/* Return true if the switch fallthough warning should occur. LABEL is
the label statement that we're falling through to. */
static bool
should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label)
{
gimple_stmt_iterator gsi = *gsi_p;
/* Don't warn for a non-case label followed by a statement:
case 0:
foo ();
label:
bar ();
as these are likely intentional. */
if (!case_label_p (&gimplify_ctxp->case_labels, label))
{
gsi_next (&gsi);
if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
return false;
}
/* Don't warn for terminated branches, i.e. when the subsequent case labels
immediately breaks. */
gsi = *gsi_p;
/* Skip all immediately following labels. */
while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
gsi_next (&gsi);
/* { ... something; default:; } */
if (gsi_end_p (gsi)
/* { ... something; default: break; } or
{ ... something; default: goto L; } */
|| gimple_code (gsi_stmt (gsi)) == GIMPLE_GOTO
/* { ... something; default: return; } */
|| gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN)
return false;
return true;
}
/* Callback for walk_gimple_seq. */
static tree
warn_implicit_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;
/* Vector of labels that fall through. */
auto_vec <struct label_entry> labels;
gimple *prev = collect_fallthrough_labels (gsi_p, &labels);
/* There might be no more statements. */
if (gsi_end_p (*gsi_p))
return integer_zero_node;
gimple *next = gsi_stmt (*gsi_p);
tree label;
/* If what follows is a label, then we may have a fallthrough. */
if (gimple_code (next) == GIMPLE_LABEL
&& gimple_has_location (next)
&& (label = gimple_label_label (as_a <glabel *> (next)))
&& !FALLTHROUGH_LABEL_P (label)
&& prev != NULL)
{
struct label_entry *l;
bool warned_p = false;
if (!should_warn_for_implicit_fallthrough (gsi_p, label))
/* Quiet. */;
else if (gimple_code (prev) == GIMPLE_LABEL
&& (label = gimple_label_label (as_a <glabel *> (prev)))
&& (l = find_label_entry (&labels, label)))
warned_p = warning_at (l->loc, OPT_Wimplicit_fallthrough,
"this statement may fall through");
else if (!gimple_call_internal_p (prev, IFN_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))
warned_p = warning_at (gimple_location (prev),
OPT_Wimplicit_fallthrough,
"this statement may fall through");
if (warned_p)
inform (gimple_location (next), "here");
/* Mark this label as processed so as to prevent multiple
warnings in nested switches. */
FALLTHROUGH_LABEL_P (label) = true;
/* So that next warn_implicit_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_implicit_fallthrough (gimple_seq seq)
{
if (!warn_implicit_fallthrough)
return;
/* This warning is meant for C/C++/ObjC/ObjC++ only. */
if (!(lang_GNU_C ()
|| lang_GNU_CXX ()
|| lang_GNU_OBJC ()))
return;
struct walk_stmt_info wi;
memset (&wi, 0, sizeof (wi));
walk_gimple_seq (seq, warn_implicit_fallthrough_r, NULL, &wi);
}
/* Callback for walk_gimple_seq. */
static tree
expand_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_internal_p (stmt, IFN_FALLTHROUGH))
{
gsi_remove (gsi_p, true);
if (gsi_end_p (*gsi_p))
return integer_zero_node;
bool found = false;
location_t loc = gimple_location (stmt);
gimple_stmt_iterator gsi2 = *gsi_p;
stmt = gsi_stmt (gsi2);
if (gimple_code (stmt) == GIMPLE_GOTO && !gimple_has_location (stmt))
{
/* Go on until the artificial label. */
tree goto_dest = gimple_goto_dest (stmt);
for (; !gsi_end_p (gsi2); gsi_next (&gsi2))
{
if (gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL
&& gimple_label_label (as_a <glabel *> (gsi_stmt (gsi2)))
== goto_dest)
break;
}
/* Not found? Stop. */
if (gsi_end_p (gsi2))
break;
/* Look one past it. */
gsi_next (&gsi2);
}
/* We're looking for a case label or default label here. */
while (!gsi_end_p (gsi2))
{
stmt = gsi_stmt (gsi2);
if (gimple_code (stmt) == GIMPLE_LABEL)
{
tree label = gimple_label_label (as_a <glabel *> (stmt));
if (gimple_has_location (stmt) && DECL_ARTIFICIAL (label))
{
found = true;
break;
}
}
else
/* Something other than a label. That's not expected. */
break;
gsi_next (&gsi2);
}
if (!found)
warning_at (loc, 0, "attribute %<fallthrough%> not preceding "
"a case label or default label");
}
break;
default:
break;
}
return NULL_TREE;
}
/* Expand all FALLTHROUGH () calls in SEQ. */
static void
expand_FALLTHROUGH (gimple_seq *seq_p)
{
struct walk_stmt_info wi;
memset (&wi, 0, sizeof (wi));
walk_gimple_seq_mod (seq_p, expand_FALLTHROUGH_r, NULL, &wi);
}
/* Gimplify a SWITCH_EXPR, and collect the vector of labels it can
branch to. */
@ -1660,10 +2085,17 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
labels. Save all the things from the switch body to append after. */
saved_labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels.create (8);
bool old_in_switch_expr = gimplify_ctxp->in_switch_expr;
gimplify_ctxp->in_switch_expr = true;
gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq);
gimplify_ctxp->in_switch_expr = old_in_switch_expr;
maybe_warn_switch_unreachable (switch_body_seq);
maybe_warn_implicit_fallthrough (switch_body_seq);
/* Only do this for the outermost GIMPLE_SWITCH. */
if (!gimplify_ctxp->in_switch_expr)
expand_FALLTHROUGH (&switch_body_seq);
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
@ -1694,6 +2126,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 +2158,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);
@ -10777,11 +11225,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:

View File

@ -893,6 +893,7 @@ go_format_type (struct godump_container *container, tree type,
case UNION_TYPE:
is_union = true;
/* Fall through to RECORD_TYPE case. */
gcc_fallthrough ();
case RECORD_TYPE:
{
unsigned int prev_field_end;

View File

@ -244,6 +244,15 @@ expand_TSAN_FUNC_EXIT (internal_fn, gcall *)
gcc_unreachable ();
}
/* This should get expanded in the lower pass. */
static void
expand_FALLTHROUGH (internal_fn, gcall *call)
{
error_at (gimple_location (call),
"invalid use of attribute %<fallthrough%>");
}
/* Helper function for expand_addsub_overflow. Return 1
if ARG interpreted as signed in its precision is known to be always
positive or 2 if ARG is known to be always negative, or 3 if ARG may

View File

@ -195,6 +195,9 @@ DEF_INTERNAL_FN (ATOMIC_BIT_TEST_AND_COMPLEMENT, ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (ATOMIC_BIT_TEST_AND_RESET, ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (ATOMIC_COMPARE_EXCHANGE, ECF_LEAF | ECF_NOTHROW, NULL)
/* To implement [[fallthrough]]. */
DEF_INTERNAL_FN (FALLTHROUGH, ECF_LEAF | ECF_NOTHROW, NULL)
#undef DEF_INTERNAL_INT_FN
#undef DEF_INTERNAL_FLT_FN
#undef DEF_INTERNAL_OPTAB_FN

View File

@ -725,3 +725,12 @@ lang_GNU_Fortran (void)
{
return strncmp (lang_hooks.name, "GNU Fortran", 11) == 0;
}
/* Returns true if the current lang_hooks represents the GNU Objective-C
frontend. */
bool
lang_GNU_OBJC (void)
{
return strncmp (lang_hooks.name, "GNU Objective-C", 15) == 0;
}

View File

@ -546,5 +546,6 @@ extern tree add_builtin_type (const char *name, tree type);
extern bool lang_GNU_C (void);
extern bool lang_GNU_CXX (void);
extern bool lang_GNU_Fortran (void);
extern bool lang_GNU_OBJC (void);
#endif /* GCC_LANG_HOOKS_H */

View File

@ -3022,6 +3022,7 @@ elimination_effects (rtx x, machine_mode mem_mode)
break;
/* Fall through to generic unary operation case. */
gcc_fallthrough ();
case STRICT_LOW_PART:
case NEG: case NOT:
case SIGN_EXTEND: case ZERO_EXTEND:

View File

@ -364,6 +364,7 @@ mark_referenced_resources (rtx x, struct resources *res,
}
/* ... fall through to other INSN processing ... */
gcc_fallthrough ();
case INSN:
case JUMP_INSN:
@ -674,6 +675,7 @@ mark_set_resources (rtx x, struct resources *res, int in_dest,
}
/* ... and also what its RTL says it modifies, if anything. */
gcc_fallthrough ();
case JUMP_INSN:
case INSN:

View File

@ -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() __attribute__((fallthrough))
#else
# define gcc_fallthrough()
#endif
#if GCC_VERSION >= 3001
#define STATIC_CONSTANT_P(X) (__builtin_constant_p (X) && (X))
#else

View File

@ -1,3 +1,37 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* c-c++-common/Wimplicit-fallthrough-1.c: New test.
* c-c++-common/Wimplicit-fallthrough-10.c: New test.
* c-c++-common/Wimplicit-fallthrough-11.c: New test.
* c-c++-common/Wimplicit-fallthrough-12.c: New test.
* c-c++-common/Wimplicit-fallthrough-13.c: New test.
* c-c++-common/Wimplicit-fallthrough-14.c: New test.
* c-c++-common/Wimplicit-fallthrough-15.c: New test.
* c-c++-common/Wimplicit-fallthrough-16.c: New test.
* c-c++-common/Wimplicit-fallthrough-17.c: New test.
* c-c++-common/Wimplicit-fallthrough-18.c: New test.
* c-c++-common/Wimplicit-fallthrough-19.c: New test.
* c-c++-common/Wimplicit-fallthrough-20.c: New test.
* c-c++-common/Wimplicit-fallthrough-21.c: New test.
* c-c++-common/Wimplicit-fallthrough-2.c: New test.
* c-c++-common/Wimplicit-fallthrough-3.c: New test.
* c-c++-common/Wimplicit-fallthrough-4.c: New test.
* c-c++-common/Wimplicit-fallthrough-5.c: New test.
* c-c++-common/Wimplicit-fallthrough-6.c: New test.
* c-c++-common/Wimplicit-fallthrough-7.c: New test.
* c-c++-common/Wimplicit-fallthrough-8.c: New test.
* c-c++-common/Wimplicit-fallthrough-9.c: New test.
* c-c++-common/attr-fallthrough-1.c: New test.
* c-c++-common/attr-fallthrough-2.c: New test.
* g++.dg/cpp0x/fallthrough1.C: New test.
* g++.dg/cpp0x/fallthrough2.C: New test.
* g++.dg/cpp1z/fallthrough1.C: New test.
* g++.dg/warn/Wunused-label-1.C: Turn dg-error into dg-warning.
* gcc.dg/Wimplicit-fallthrough-1.c: New test.
* obj-c++.dg/Wimplicit-fallthrough-1.mm: New test.
* objc.dg/Wimplicit-fallthrough-1.m: New test.
2016-09-25 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/77429

View File

@ -0,0 +1,38 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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);
__attribute__((fallthrough));
case 55:
if (n > 10)
{
f (3);
break;
}
else
{
f (4);
__attribute__((fallthrough));
}
case 66:
f (5);
__attribute__((fallthrough)); /* { dg-warning "not preceding" } */
f (6); /* { dg-warning "statement may fall through" } */
case 77:
f (7);
}
}

View File

@ -0,0 +1,239 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
extern void bar (int);
void
f (int i)
{
switch (i)
{
case 1:
if (i)
{
bar (0);
break;
}
else if (i > 10)
{
bar (1);
__attribute__((fallthrough));
}
else
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
if (i) /* { dg-warning "statement may fall through" } */
bar (2);
else if (i > 10)
{
bar (3);
__attribute__((fallthrough));
}
else
break;
case 2:
bar (4);
}
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:
bar (99);
}
switch (i)
{
case 1:
if (i)
{
bar (0);
break;
}
else if (i > 10)
{
bar (1);
break;
}
else
break;
case 2:
bar (99);
}
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:
bar (99);
}
switch (i)
{
case 1:
if (i)
{
bar (0);
__attribute__((fallthrough));
}
else if (i > 10)
{
bar (1);
break;
}
else
bar (2); /* { dg-warning "statement may fall through" } */
case 2:
bar (99);
}
switch (i)
{
case 1:
if (i)
{
bar (0);
__attribute__((fallthrough));
}
else if (i > 10)
{
bar (1);
__attribute__((fallthrough));
}
else
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
if (i)
{
bar (0);
__attribute__((fallthrough));
}
else if (i > 10)
{
bar (1);
__attribute__((fallthrough));
}
else
bar (2); /* { dg-warning "statement may fall through" } */
case 2:
bar (99);
}
switch (i)
{
case 1:
if (i)
{
bar (0);
__attribute__((fallthrough));
}
else if (i > 10) /* { dg-warning "statement may fall through" } */
{
bar (1);
bar (2);
}
else
__attribute__((fallthrough));
case 2:
bar (99);
}
switch (i)
{
case 1:
if (i) /* { dg-warning "statement may fall through" } */
{
bar (0);
}
else if (i > 10)
{
bar (1);
}
else
{
bar (1);
__attribute__((fallthrough));
}
case 2:
bar (99);
}
switch (i)
{
case 1:
if (i)
{
bar (0);
__attribute__((fallthrough));
}
else if (i > 10)
{
bar (1);
break;
}
else
{
bar (1);
__attribute__((fallthrough));
}
case 2:
bar (99);
}
switch (i)
{
case 1:
if (i)
{
bar (0);
break;
}
else if (i > 10) /* { dg-warning "statement may fall through" } */
{
bar (1);
}
else
{
bar (1);
__attribute__((fallthrough));
}
case 2:
bar (99);
}
}

View File

@ -0,0 +1,23 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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:;
}
}

View File

@ -0,0 +1,26 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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);
}
}

View File

@ -0,0 +1,63 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* As per <http://security.coverity.com/blog/2013/Sep/gimme-a-break.html>, don't
warn for terminated branches (fall through to break / end of the switch). */
extern void bar (int);
void
f (int i)
{
switch (i)
{
case 1:
bar (1);
default:
return;
}
switch (i)
{
case 1:
bar (1);
default:
goto X;
}
X:
switch (i)
{
case 1:
bar (1);
default:
break;
}
switch (i)
{
case 1:
bar (1);
case 2:
case 3:
default:
break;
}
switch (i)
{
case 1:
bar (1);
default:;
}
switch (i)
{
case 1:
bar (1);
case 2:
case 3:
default:;
}
}

View File

@ -0,0 +1,162 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* Test various falls through comments. */
extern void bar (int);
void
fn (int i)
{
switch (i)
{
case -1:
bar (-1);
/*-fallthrough*/
case 0:
bar (0);
/*@fallthrough@*/
case 1:
bar (1);
/* FALL THRU */
case 2:
bar (2);
/* FALLTHRU */
case 3:
bar (3);
/* FALLS THRU */
case 4:
bar (4);
/* FALL-THRU */
case 5:
bar (5);
/* FALL THROUGH */
case 6:
bar (6);
/* FALLTHROUGH */
case 7:
bar (7);
/* FALLS THROUGH */
case 8:
bar (8);
/* FALL-THROUGH */
case 9:
bar (9);
/*FALLTHRU*/
case 10:
bar (10);
/* FALLTHRU.*/
case 11:
bar (11);
/* FALLTHROUGH. */
case 12:
bar (12);
/* Fall thru */
case 13:
bar (13);
/* Falls thru */
case 14:
bar (14);
/* Fall-thru */
case 15:
bar (15);
/* Fall Thru */
case 16:
bar (16);
/* Falls Thru */
case 17:
bar (17);
/* Fall-Thru */
case 18:
bar (18);
/* Fall through */
case 19:
bar (19);
/* Falls through */
case 20:
bar (20);
/* Fall-through */
case 21:
bar (21);
/* Fall Through */
case 22:
bar (22);
/* Falls Through */
case 23:
bar (23);
/* Fall-Through */
case 24:
bar (24);
/* Falls through. */
case 25:
bar (25);
/* Falls through. */
case 26:
bar (26);
/* fall thru */
case 27:
bar (27);
/* falls thru */
case 28:
bar (28);
/* fall-thru */
case 29:
bar (29);
/* fall thru */
case 30:
bar (30);
/* falls thru */
case 31:
bar (31);
/* fall-thru */
case 32:
bar (32);
/* fall through */
case 33:
bar (33);
/* falls through */
case 34:
bar (34);
/* fall-through */
default:
bar (99);
}
switch (i)
{
case 0:
i++;
/*@fallthrough@*/
L:
default:
bar (6);
}
{
__label__ L2;
switch (i)
{
case 0:
i++;
/*@fallthrough@*/
L2:
default:
bar (6);
}
}
/* Don't generate false -Wswitch-unreachable warning. */
switch (i)
{
/*FALLTHROUGH*/
case 0:
i++;
}
if (i)
{
/* fall through */
L1:;
}
}

View File

@ -0,0 +1,31 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* Another nested switch. Check that we don't warn here. */
void
f (int i)
{
int j = 0;
switch (i)
{
case 0:
case 1:
j = 10;
__attribute__((fallthrough));
case 2:
j += 10;
break;
case 3:
switch (i)
{
case 5:
j += 2;
__attribute__((fallthrough));
case 6:
j += 4;
break;
}
}
}

View File

@ -0,0 +1,32 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* Another nested switch, and with an initialization on top. Check that
we do warn here. */
void
f (int i)
{
switch (i)
{
case 1:
{
int t = 3;
switch (i)
{
case 3:
if (i > 5)
--i;
i += 10; /* { dg-warning "statement may fall through" } */
case 4:
t /= 5;
break;
}
break;
}
case 2:
--i;
break;
}
}

View File

@ -0,0 +1,29 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* Another nested switch, and with an initialization on top. Check that
we do not warn here as the case 3 falls through to break. */
void
f (int i)
{
switch (i)
{
case 1:
{
int t = 3;
switch (i)
{
case 3:
i += 10;
case 4:
break;
}
break;
}
case 2:
--i;
break;
}
}

View File

@ -0,0 +1,42 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* Testing some loops. */
int f (void);
int
g (int i)
{
switch (i)
{
case 0:
for (;;)
{
if (f ()) /* { dg-warning "statement may fall through" "fall through" { xfail *-*-* } } */
break;
}
case 1:
return 1;
}
return 0;
}
int
h (int i)
{
switch (i)
{
case 0:
do
{
if (f ()) /* { dg-warning "statement may fall through" } */
break;
}
while (0);
case 1:
return 1;
}
return 0;
}

View File

@ -0,0 +1,85 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* Testing non-case labels. */
int foo (int);
void
f1 (int i)
{
switch (i)
{
case 0:
foo (1);
L1:
foo (2);
}
switch (i)
{
case 0:
foo (1); /* { dg-warning "statement may fall through" } */
L2:
case 2:
foo (2);
}
switch (i)
{
case 0:
foo (1); /* { dg-warning "statement may fall through" } */
case 2:
L3:
foo (2);
}
switch (i)
{
case 0:
foo (1); /* { dg-warning "statement may fall through" } */
L4:
case 2:
L5:
foo (2);
}
switch (i)
{
case 0:
switch (i)
{
case 1:
foo (2);
L6:
foo (3);
}
}
switch (i)
{
case 0:
switch (i)
{
case 1:
foo (2); /* { dg-warning "statement may fall through" } */
L7:
case 2:
foo (3);
}
}
switch (i)
{
case 0:
switch (i)
{
case 1:
foo (2); /* { dg-warning "statement may fall through" } */
case 2:
L8:
foo (3);
}
}
}

View File

@ -0,0 +1,223 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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 ();
}
}

View File

@ -0,0 +1,41 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
int
f (int i)
{
switch (i)
{
case -1:
__attribute__((fallthrough));
default:
__attribute__((fallthrough));
case 1:
return 6;
case 2 ... 4:
__attribute__((fallthrough));
case 5:
return 7;
}
return 0;
}
int
g (int i)
{
switch (i)
{
case -1:
__attribute__((used)); /* { dg-warning "ignored|only attribute" } */
default:
__attribute__((used)); /* { dg-warning "ignored|only attribute" } */
case 1:
return 6;
case 2 ... 4:
__attribute__((used)); /* { dg-warning "ignored|only attribute" } */
case 5:
return 7;
}
return 0;
}

View File

@ -0,0 +1,25 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
int
f (int i)
{
switch (i)
{
case 0:
i++;
__attribute__((fallthrough));
lab1:
case 1:
i++;
__attribute__((fallthrough)); /* { dg-warning "not preceding" } */
lab2:
--i;
break;
case 3:
i++;
break;
}
return 0;
}

View File

@ -0,0 +1,543 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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 ();
}
}

View File

@ -0,0 +1,250 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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 ();
}
}

View File

@ -0,0 +1,109 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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);
__attribute__((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);
__attribute__((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:;
}
}

View File

@ -0,0 +1,305 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
extern void bar (int);
/* Test nested scopes. */
void
f (int i)
{
switch (i)
{
case 1:
{
int j;
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 10; /* { dg-warning "statement may fall through" } */
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int k = 9;
k++;
{
int j = 10;
j++; /* { dg-warning "statement may fall through" } */
}
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int k = 9;
k++;
{
int j = 10;
j++;
{
bar (1); /* { dg-warning "statement may fall through" } */
}
}
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
__attribute__((fallthrough));
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
{
int k = j + 5;
bar (k);
__attribute__((fallthrough));
}
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
return;
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
goto L1;
}
L1:
case 2:
bar (99);
}
switch (i)
{
case 1:
{ /* { dg-warning "statement may fall through" "" { target c } 120 } */
int j = 0;
bar (j);
if (j == 8)
return; /* { dg-warning "statement may fall through" "" { target c++ } 124 } */
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
return;
else
return;
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{ /* { dg-warning "statement may fall through" "" { target c } 148 } */
int j = 0;
bar (j);
if (j == 8)
bar (1);
else
return; /* { dg-warning "statement may fall through" "" { target c++ } 154 } */
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
return;
else
bar (2); /* { dg-warning "statement may fall through" } */
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{ /* { dg-warning "statement may fall through" "" { target c } 178 } */
int j = 0;
bar (j);
if (j == 8)
bar (1);
else
bar (2); /* { dg-warning "statement may fall through" "" { target c++ } 184 } */
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
return;
}
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
return;
else
return;
}
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
bar (1);
else
return;
}
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
return;
else
bar (2);
}
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
bar (1);
else
bar (2);
}
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 9;
while (1);
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{ /* { dg-warning "statement may fall through" "" { target c } 282 } */
int j = 9;
switch (j); /* { dg-warning "statement may fall through" "" { target c++ } 284 } */
}
case 2:
bar (99);
}
switch (i)
{
case 1:
{
int j = 0;
bar (j);
if (j == 8)
bar (1);
else
bar (2);
__attribute__((fallthrough));
}
case 2:
bar (99);
}
}

View File

@ -0,0 +1,124 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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:
bar (99);
}
switch (i)
{
case 1:
{ /* { dg-warning "statement may fall through" "" { target c } 23 } */
int a[i]; /* { dg-warning "statement may fall through" "" { target c++ } 24 } */
}
case 2:
bar (99);
}
switch (i)
{
case 1:
for (int j = 0; j < 10; j++) /* { dg-warning "statement may fall through" "" { target c } 33 } */
map[j] = j; /* { dg-warning "statement may fall through" "" { target c++ } 34 } */
case 2:
bar (99);
}
switch (i)
{
case 1:
do /* { dg-warning "statement may fall through" "" { target c++ } 42 } */
bar (2);
while (--i); /* { dg-warning "statement may fall through" "" { target c } 44 } */
case 2:
bar (99);
}
switch (i)
{
case 1:
{
switch (i + 2)
case 4:
bar (1); /* { dg-warning "statement may fall through" } */
case 5:
bar (5);
return;
}
case 2:
bar (99);
}
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:
bar (99);
}
switch (i)
{
case 1:
if (i > 9) /* { dg-warning "statement may fall through" } */
{
bar (9);
if (i == 10)
{
bar (10);
break;
}
}
case 2:
bar (99);
}
int r;
switch (i)
{
case 1:
r = bar2 ();
if (r) /* { dg-warning "statement may fall through" } */
break;
case 2:
bar (99);
}
switch (i)
{
case 1:
r = bar2 ();
if (r)
return;
if (!i) /* { dg-warning "statement may fall through" } */
return;
case 2:
bar (99);
}
}

View File

@ -0,0 +1,101 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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:
grace (9);
}
done:;
}
int
fn6 (int i)
{
switch (i)
{
case 1:
if (i == 5) /* { dg-warning "statement may fall through" } */
{
grace (1);
goto done;
}
case 2:
grace (8);
}
done:;
}

View File

@ -0,0 +1,26 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough" } */
/* Test we don't remove FALLTHROUGH () too early. */
extern void h (int);
void
g (int i)
{
switch (i)
{
case 1:
{
switch (i)
{
case 3:
h (7);
__attribute__((fallthrough));
case 4:;
}
}
case 2:;
}
}

View File

@ -0,0 +1,57 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wall -Wextra -Wpedantic" } */
extern void bar (int);
void
fn (int i)
{
__attribute__((fallthrough)) int j = 0; /* { dg-warning "ignored|attribute not followed" } */
if (j)
__attribute__((fallthrough)); /* { dg-error "invalid use" } */
__attribute__((fallthrough)); /* { dg-error "invalid use" } */
switch (i)
{
__attribute__((fallthrough)); /* { dg-warning "statement will never" } */
case 1:
i++;
__attribute__((fallthrough));
case 2:
if (i) /* { dg-warning "statement may fall through" } */
bar (2);
else
__attribute__((fallthrough));
case 3:
if (i > 1)
__attribute__((fallthrough));
else
return;
case 4:
if (i)
__attribute__((fallthrough)); /* { dg-warning "not preceding" } */
__attribute__((fallthrough));
case 5:
;
__attribute__((fallthrough));
case 6:
if (i) /* { dg-warning "statement may fall through" } */
bar (6);
else
{
__attribute__((fallthrough));
}
case 7:
if (i > 1)
{
__attribute__((fallthrough));
}
else
bar (7); /* { dg-warning "statement may fall through" } */
default:
--j;
}
__attribute__((fallthrough)); /* { dg-error "invalid use" } */
}

View File

@ -0,0 +1,54 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wall -Wextra -Wpedantic -Wno-unused -Wno-implicit-fallthrough" } */
extern void bar (int);
void
fn (int i)
{
switch (i)
{
case 1:
bar (1);
__attribute__((used));
/* { dg-warning "empty declaration" "" { target c } 13 } */
/* { dg-warning "ignored" "" { target c++ } 13 } */
case 2:
bar (1);
__attribute__((foo));
/* { dg-warning "empty declaration" "" { target c } 18 } */
/* { dg-warning "ignored" "" { target c++ } 18 } */
case 3:
bar (1);
__attribute__((fallthrough)) /* { dg-warning "not followed" "" { target c } } */
case 4: /* { dg-error "expected" } */
bar (1);
__attribute__((fallthrough)) 1;
/* { dg-error "expected" "" { target c } 26 } */
/* { dg-warning "not followed" "" { target *-*-* } 26 } */
case 5:
bar (1);
__attribute__((fallthrough)) int i; /* { dg-warning "ignored|not followed" } */
case 6:
bar (1);
__attribute__((fallthrough ("x"))); /* { dg-warning "specified with a parameter" } */
case 7:
bar (1);
__attribute__((fallthrough, fallthrough)); /* { dg-warning "attribute specified multiple times" } */
case 8:
bar (1);
__attribute__((fallthrough));
case 9:
__attribute__((fallthrough));
/* { dg-warning "not preceding" "" { target *-*-* } 42 } */
bar (1);
case 10:
bar (1);
__attribute__((unused, fallthrough)); /* { dg-warning "attribute ignored" } */
case 11:
bar (1);
__attribute__((fallthrough, unused)); /* { dg-warning "attribute ignored" } */
default:
bar (99);
}
}

View File

@ -0,0 +1,57 @@
// PR c/7652
// { dg-do compile { target c++11 } }
// { dg-options "-Wextra -Wall -Wpedantic" }
extern void bar (int);
void
fn (int i)
{
[[gnu::fallthrough]] int j = 0; // { dg-warning "attribute ignored" }
if (j)
[[gnu::fallthrough]]; // { dg-error "invalid use" }
[[gnu::fallthrough]]; // { dg-error "invalid use" }
switch (i)
{
[[gnu::fallthrough]]; // { dg-warning "statement will never" }
case 1:
i++;
[[gnu::fallthrough]];
case 2:
if (i) // { dg-warning "statement may fall through" }
bar (2);
else
[[gnu::fallthrough]];
case 3:
if (i > 1)
[[gnu::fallthrough]];
else
return;
case 4:
if (i)
[[gnu::fallthrough]]; // { dg-warning "not preceding" }
[[gnu::fallthrough]];
case 5:
;
[[gnu::fallthrough]];
case 6:
if (i) // { dg-warning "statement may fall through" }
bar (6);
else
{
[[gnu::fallthrough]];
}
case 7:
if (i > 1)
{
[[gnu::fallthrough]];
}
else
bar (7); // { dg-warning "statement may fall through" }
default:
--j;
}
[[gnu::fallthrough]]; // { dg-error "invalid use" }
}

View File

@ -0,0 +1,21 @@
// PR c/7652
// { dg-do compile { target c++11 } }
// { dg-options "-Wextra -Wall -Wpedantic" }
extern void bar (int);
void
f (int i)
{
switch (i)
{
case 1:
bar (1);
[[fallthrough]]; // { dg-warning ".fallthrough. is a C\\+\\+17 feature" }
case 3:
bar (1);
[[gnu::fallthrough, gnu::fallthrough]]; // { dg-warning ".fallthrough. attribute specified multiple times" }
case 2:
bar (2);
}
}

View File

@ -0,0 +1,20 @@
// PR c/7652
// { dg-do compile }
// { dg-options "-std=c++1z -Wextra -Wall -Wpedantic" }
// Check that we accept attribute [[fallthrough]].
extern void bar (int);
void
f (int i)
{
switch (i)
{
case 1:
bar (1);
[[fallthrough]];
case 2:
bar (2);
}
}

View File

@ -21,7 +21,7 @@ void
f3()
{
// The next line would be OK in C but is a syntax error in C++.
l2: __attribute__ ((unused)) f9(); // { dg-error "expected" }
l2: __attribute__ ((unused)) f9(); // { dg-warning "ignored" }
// We still get an unused label warning--this is
// optional and can be removed if it ever changes.
// { dg-warning "not used" "expected" { target *-*-* } 24 }

View File

@ -0,0 +1,22 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-fallthrough -Wdeclaration-after-statement" } */
/* Test we don't print bogus "mixed declarations and code" warning. */
int
f (int b)
{
switch (b)
{
case 0:
b++;
__attribute__((fallthrough));
case 1:
b--;
__attribute__((unused)) int a; /* { dg-warning "mixed declarations and code" } */
case 2:
break;
}
return 99;
}

View File

@ -0,0 +1,38 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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);
__attribute__((fallthrough));
case 55:
if (n > 10)
{
f (3);
break;
}
else
{
f (4);
__attribute__((fallthrough));
}
case 66:
f (5);
__attribute__((fallthrough)); /* { dg-warning "not preceding" } */
f (6); /* { dg-warning "statement may fall through" } */
case 77:
f (7);
}
}

View File

@ -0,0 +1,38 @@
/* PR c/7652 */
/* { dg-do compile } */
/* { dg-options "-Wimplicit-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);
__attribute__((fallthrough));
case 55:
if (n > 10)
{
f (3);
break;
}
else
{
f (4);
__attribute__((fallthrough));
}
case 66:
f (5);
__attribute__((fallthrough)); /* { dg-warning "not preceding" } */
f (6); /* { dg-warning "statement may fall through" } */
case 77:
f (7);
}
}

View File

@ -1077,6 +1077,9 @@ struct GTY(()) tree_base {
TRANSACTION_EXPR_RELAXED in
TRANSACTION_EXPR
FALLTHROUGH_LABEL_P in
LABEL_DECL
private_flag:
TREE_PRIVATE in

View File

@ -1885,8 +1885,8 @@ find_deriving_biv_for_expr (struct ivopts_data *data, tree expr)
iv = find_deriving_biv_for_expr (data, e2);
if (iv)
return iv;
gcc_fallthrough ();
/* Fallthru. */
CASE_CONVERT:
/* Casts are simple. */
return find_deriving_biv_for_expr (data, e1);

View File

@ -774,6 +774,11 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
computed gotos. */
#define FORCED_LABEL(NODE) (LABEL_DECL_CHECK (NODE)->base.side_effects_flag)
/* Whether a case or a user-defined label is allowed to fall through to.
This is used to implement -Wimplicit-fallthrough. */
#define FALLTHROUGH_LABEL_P(NODE) \
(LABEL_DECL_CHECK (NODE)->base.public_flag)
/* Nonzero means this expression is volatile in the C sense:
its address should be of type `volatile WHATEVER *'.
In other words, the declared item is volatile qualified.

View File

@ -4173,7 +4173,7 @@ output_addressed_constants (tree exp)
case POINTER_PLUS_EXPR:
case MINUS_EXPR:
output_addressed_constants (TREE_OPERAND (exp, 1));
/* Fall through. */
gcc_fallthrough ();
CASE_CONVERT:
case VIEW_CONVERT_EXPR:

View File

@ -1,3 +1,13 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
Jakub Jelinek <jakub@redhat.com>
PR c/7652
* include/cpplib.h (PREV_FALLTHROUGH): Define.
* internal.h (CPP_FALLTHRU): Define.
* lex.c (fallthrough_comment_p): New function.
(_cpp_lex_direct): Set PREV_FALLTHROUGH on tokens succeeding a falls
through comment.
2016-09-23 David Malcolm <dmalcolm@redhat.com>
PR preprocessor/77672

View File

@ -185,7 +185,8 @@ struct GTY(()) cpp_string {
#define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified. */
#define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */
#define NAMED_OP (1 << 4) /* C++ named operators. */
#define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */
#define PREV_FALLTHROUGH (1 << 5) /* On a token preceeded by FALLTHROUGH
comment. */
#define BOL (1 << 6) /* Token at beginning of line. */
#define PURE_ZERO (1 << 7) /* Single 0 digit, used by the C++ frontend,
set in c-lex.c. */
@ -193,6 +194,7 @@ struct GTY(()) cpp_string {
#define SP_PREV_WHITE (1 << 9) /* If whitespace before a ##
operator, or before this token
after a # operator. */
#define NO_EXPAND (1 << 10) /* Do not macro-expand this token. */
/* Specify which field, if any, of the cpp_token union is used. */

View File

@ -2032,6 +2032,94 @@ save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from,
store_comment (pfile, token);
}
/* Returns true if comment at COMMENT_START is a recognized FALLTHROUGH
comment. */
static bool
fallthrough_comment_p (cpp_reader *pfile, const unsigned char *comment_start)
{
const unsigned char *from = comment_start + 1;
/* Whole comment contents:
-fallthrough
@fallthrough@
*/
if (*from == '-' || *from == '@')
{
size_t len = sizeof "fallthrough" - 1;
if ((size_t) (pfile->buffer->cur - from - 1) < len)
return false;
if (memcmp (from + 1, "fallthrough", len))
return false;
if (*from == '@')
{
if (from[len + 1] != '@')
return false;
len++;
}
from += 1 + len;
}
/* Whole comment contents (regex):
[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*
[ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*
[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*
*/
else
{
while (*from == ' ' || *from == '\t')
from++;
unsigned char f = *from;
if (f != 'F' && f != 'f')
return false;
if ((size_t) (pfile->buffer->cur - from) < sizeof "fallthrough")
return false;
bool all_upper = false;
if (f == 'F' && memcmp (from + 1, "ALL", sizeof "ALL" - 1) == 0)
all_upper = true;
else if (memcmp (from + 1, "all", sizeof "all" - 1))
return false;
if (from[sizeof "fall" - 1] == (all_upper ? 'S' : 's')
&& from[sizeof "falls" - 1] == ' ')
from += sizeof "falls " - 1;
else if (from[sizeof "fall" - 1] == ' '
|| from[sizeof "fall" - 1] == '-')
from += sizeof "fall " - 1;
else if (from[sizeof "fall" - 1] != (all_upper ? 'T' : 't'))
return false;
else
from += sizeof "fall" - 1;
if ((f == 'f' || *from != 'T') && (all_upper || *from != 't'))
return false;
if ((size_t) (pfile->buffer->cur - from) < sizeof "thru")
return false;
if (memcmp (from + 1, all_upper ? "HRU" : "hru", sizeof "hru" - 1))
{
if ((size_t) (pfile->buffer->cur - from) < sizeof "through")
return false;
if (memcmp (from + 1, all_upper ? "HROUGH" : "hrough",
sizeof "hrough" - 1))
return false;
from += sizeof "through" - 1;
}
else
from += sizeof "thru" - 1;
if (*from == '.')
from++;
while (*from == ' ' || *from == '\t')
from++;
}
/* C block comment. */
if (*comment_start == '*')
{
if (*from != '*' || from[1] != '/')
return false;
}
/* C++ line comment. */
else if (*from != '\n')
return false;
return true;
}
/* Allocate COUNT tokens for RUN. */
void
_cpp_init_tokenrun (tokenrun *run, unsigned int count)
@ -2310,7 +2398,7 @@ _cpp_lex_direct (cpp_reader *pfile)
{
cppchar_t c;
cpp_buffer *buffer;
const unsigned char *comment_start;
const unsigned char *comment_start = NULL;
cpp_token *result = pfile->cur_token++;
fresh_line:
@ -2337,6 +2425,8 @@ _cpp_lex_direct (cpp_reader *pfile)
}
return result;
}
if (buffer != pfile->buffer)
comment_start = NULL;
if (!pfile->keep_tokens)
{
pfile->cur_run = &pfile->base_run;
@ -2443,6 +2533,11 @@ _cpp_lex_direct (cpp_reader *pfile)
result->flags |= NAMED_OP;
result->type = (enum cpp_ttype) result->val.node.node->directive_index;
}
/* Signal FALLTHROUGH comment followed by another token. */
if (comment_start
&& fallthrough_comment_p (pfile, comment_start))
result->flags |= PREV_FALLTHROUGH;
break;
case '\'':
@ -2534,6 +2629,9 @@ _cpp_lex_direct (cpp_reader *pfile)
goto update_tokens_line;
}
if (fallthrough_comment_p (pfile, comment_start))
result->flags |= PREV_FALLTHROUGH;
/* Save the comment as a token in its own right. */
save_comment (pfile, result, comment_start, c);
break;

View File

@ -1,3 +1,8 @@
2016-09-26 Marek Polacek <polacek@redhat.com>
PR c/7652
* libsupc++/hash_bytes.cc: Add [[gnu::fallthrough]].
2016-09-25 François Dumont <fdumont@gcc.gnu.org>
* src/c++11/debug.cc: Include debug/vector. Include cctype. Remove

View File

@ -95,8 +95,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
case 3:
hash ^= static_cast<unsigned char>(buf[2]) << 16;
[[gnu::fallthrough]];
case 2:
hash ^= static_cast<unsigned char>(buf[1]) << 8;
[[gnu::fallthrough]];
case 1:
hash ^= static_cast<unsigned char>(buf[0]);
hash *= m;