public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Implement -Wimplicit-fallthrough (version 9)
@ 2016-09-20 15:49 Marek Polacek
  2016-09-20 16:29 ` Jason Merrill
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-20 15:49 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill, Jakub Jelinek

Time for another latest & greatest version of -Wimplicit-fallthrough.
Hope this time it's near its end.

Changes from last time:

* I addressed Jakub's comment, for details see
  <https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01301.html>
* in the C FE:
  case 0:
    __attribute)) ((fallthrough));
  case 1:
    ...
  now works
* we've discussed cases like
  [[fallthrough]]; lab1: case 1:;
  and
  [[fallthrough]]; lab2:; case 2:;

  This was discussed on the C++ committee reflector and it was concluded that
  the former should work and the latter should not.  So I implemented that.
  But there's no way to tell the difference between "lab1: case 1:;" and
  "lab2:; case 2:;" so the null statements are ignored.  Another problem is
  what to do with "[[fallthrough]]; lab1: (void) 0; case 2:".  Currently it's
  not rejected because we optimize "(void) 0;" out in gimplify_expr.  And I
  couldn't figure out how to circumvent this (in gimplify_expr you can't see
  what the next statement is).  Though this seems more like a pedantic issue
  and probably not a real-world issue.  (E.g.
  "[[fallthrough]]; lab1: if (0) { ... } case 2:"
  should be rejected.)
 
Jason, would you mind looking at the C++ FE parts again?

Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?

2016-09-20  Marek Polacek  <polacek@redhat.com>
	    Jakub Jelinek  <jakub@redhat.com>

	PR c/7652
gcc/
	* 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.
gcc/c-family/
	* c-common.c (c_common_attribute_table): Add fallthrough attribute.
	(handle_fallthrough_attribute): New function.
	(maybe_attribute_fallthrough_p): New function.
	* c-common.h (maybe_attribute_fallthrough_p): Declare.
gcc/c/
	* 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.
gcc/cp/
	* 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_primary_expression): Handle RID_ATTRIBUTE.
	(cp_parser_statement): Handle fallthrough attribute.
	(cp_parser_label_for_labeled_statement): Set FALLTHROUGH_LABEL_P on
	labels.
	(cp_parser_std_attribute): Handle fallthrough attribute.
	(cp_parser_check_std_attribute): Detect duplicated fallthrough
	attribute.
	* pt.c (tsubst_copy_and_build): Handle internal functions.
	(instantiation_dependent_scope_ref_p): Return if the expression is
	null.
gcc/testsuite/
	* 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.
	* 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.
libcpp/
	* 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.

diff --git gcc/gcc/c-family/c-common.c gcc/gcc/c-family/c-common.c
index fc25686..dc132e2 100644
--- gcc/gcc/c-family/c-common.c
+++ gcc/gcc/c-family/c-common.c
@@ -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 }
 };
 
@@ -9840,6 +9843,49 @@ 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
+maybe_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)))
+    {
+      error ("%<fallthrough%> attribute specified multiple times");
+      return false;
+    }
+  /* No attribute-argument-clause shall be present.  */
+  if (TREE_VALUE (t) != NULL_TREE)
+    {
+      error ("%<fallthrough%> attribute specified with a parameter");
+      return false;
+    }
+  /* 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;
+}
+
 \f
 /* Check for valid arguments being passed to a function with FNTYPE.
    There are NARGS arguments in the array ARGARRAY.  LOC should be used for
diff --git gcc/gcc/c-family/c-common.h gcc/gcc/c-family/c-common.h
index 5bbf951..b9b42a1 100644
--- gcc/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -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 maybe_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 *);
diff --git gcc/gcc/c/c-parser.c gcc/gcc/c/c-parser.c
index 58424a9..95603ca 100644
--- gcc/gcc/c/c-parser.c
+++ gcc/gcc/c/c-parser.c
@@ -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,16 @@ 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
+	       && specs->attrs
+	       && maybe_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
@@ -4841,12 +4860,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 +4984,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 +5035,29 @@ 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 (maybe_attribute_fallthrough_p (attrs))
+	    {
+	      tree fn = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
+						      void_type_node, 0);
+	      add_stmt (fn);
+	    }
+	  else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    c_parser_error (parser, "only attribute %<fallthrough%> "
+			    "can be applied to a null statement");
+	  else
+	    c_parser_error (parser, "only attribute %<fallthrough%> "
+			    "followed by %<;%> can be used");
+	}
       if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  error_at (c_parser_peek_token (parser)->location,
@@ -5062,6 +5111,9 @@ c_parser_label (c_parser *parser)
    jump-statement:
      goto * expression ;
 
+   expression-statement:
+     attributes ;
+
    Objective-C:
 
    statement:
@@ -5323,6 +5375,26 @@ 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 (maybe_attribute_fallthrough_p (attrs))
+	      {
+		location_t loc = c_parser_peek_token (parser)->location;
+		c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>");
+		tree fn = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
+							void_type_node, 0);
+		add_stmt (fn);
+	      }
+	    else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	      c_parser_error (parser, "only attribute %<fallthrough%> "
+			      "can be applied to a null statement");
+	    else
+	      c_parser_error (parser, "only attribute %<fallthrough%> "
+			      "followed by %<;%> can be used");
+	  }
+	  break;
 	default:
 	  goto expr_stmt;
 	}
diff --git gcc/gcc/common.opt gcc/gcc/common.opt
index fa1c036..e8a0154 100644
--- gcc/gcc/common.opt
+++ gcc/gcc/common.opt
@@ -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.
diff --git gcc/gcc/cp/constexpr.c gcc/gcc/cp/constexpr.c
index 34806d6..ecc07a6 100644
--- gcc/gcc/cp/constexpr.c
+++ gcc/gcc/cp/constexpr.c
@@ -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:
@@ -4829,6 +4830,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:
diff --git gcc/gcc/cp/constraint.cc gcc/gcc/cp/constraint.cc
index 311d025..b4d85c9 100644
--- gcc/gcc/cp/constraint.cc
+++ gcc/gcc/cp/constraint.cc
@@ -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);
diff --git gcc/gcc/cp/parser.c gcc/gcc/cp/parser.c
index d704593..253f73e 100644
--- gcc/gcc/cp/parser.c
+++ gcc/gcc/cp/parser.c
@@ -5135,6 +5135,30 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_AT_SELECTOR:
 	  return cp_parser_objc_expression (parser);
 
+	case RID_ATTRIBUTE:
+	  {
+	    /* This might be attribute fallthrough.  */
+	    tree attr = cp_parser_gnu_attributes_opt (parser);
+	    if (maybe_attribute_fallthrough_p (attr))
+	      {
+		tree fn = build_call_expr_internal_loc (token->location,
+							IFN_FALLTHROUGH,
+							void_type_node, 0);
+		return cp_expr (fn, token->location);
+	      }
+	    else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+	      {
+		cp_parser_error (parser, "only attribute %<fallthrough%> "
+				 "can be applied to a null statement");
+		return error_mark_node;
+	      }
+	    else
+	      {
+		cp_parser_error (parser, "expected primary-expression");
+		return error_mark_node;
+	      }
+	  }
+
 	case RID_TEMPLATE:
 	  if (parser->in_function_body
 	      && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
@@ -10585,14 +10609,25 @@ 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 (std_attrs != NULL_TREE
+	  && maybe_attribute_fallthrough_p (std_attrs)
+	  && statement == NULL_TREE)
+	{
+	  statement = build_call_expr_internal_loc (statement_location,
+						    IFN_FALLTHROUGH,
+						    void_type_node, 0);
+	  finish_expr_stmt (statement);
+	  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 +10663,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 +10698,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 +10715,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 +10727,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;
     }
 
@@ -24115,7 +24164,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,
@@ -24123,6 +24172,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))
@@ -24181,11 +24239,15 @@ 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");
+      else if (is_attribute_p ("fallthrough", name)
+	       && lookup_attribute ("fallthrough", attributes))
+	error ("attribute %<fallthrough%> can appear at most once "
 	       "in an attribute-list");
     }
 }
diff --git gcc/gcc/cp/pt.c gcc/gcc/cp/pt.c
index 29d8beb..a0cbb2e 100644
--- gcc/gcc/cp/pt.c
+++ gcc/gcc/cp/pt.c
@@ -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.  */
diff --git gcc/gcc/doc/extend.texi gcc/gcc/doc/extend.texi
index 8df9d62..ff53ab5 100644
--- gcc/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -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
@@ -5563,8 +5565,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}).
 
@@ -6345,7 +6347,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
@@ -6855,7 +6858,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
@@ -6908,8 +6912,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:
@@ -6940,6 +6944,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
@@ -6967,6 +7011,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}
@@ -7032,6 +7078,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},
diff --git gcc/gcc/doc/invoke.texi gcc/gcc/doc/invoke.texi
index 8eb5eff..76576ff 100644
--- gcc/gcc/doc/invoke.texi
+++ gcc/gcc/doc/invoke.texi
@@ -272,8 +272,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
--Winit-self  -Winline  -Wno-int-conversion @gol
+-Wimplicit  -Wimplicit-fallthrough  -Wimplicit-function-declaration  @gol
+-Wimplicit-int  -Winit-self  -Winline  -Wno-int-conversion @gol
 -Wno-int-to-pointer-cast -Winvalid-memory-model -Wno-invalid-offsetof @gol
 -Winvalid-pch -Wlarger-than=@var{len} @gol
 -Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
@@ -3715,6 +3715,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
@@ -4001,6 +4002,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
diff --git gcc/gcc/gimple.h gcc/gcc/gimple.h
index 980bdf8..9fad15b 100644
--- gcc/gcc/gimple.h
+++ gcc/gcc/gimple.h
@@ -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.  */
 
diff --git gcc/gcc/gimplify.c gcc/gcc/gimplify.c
index e378ed0..66bb8be 100644
--- gcc/gcc/gimplify.c
+++ gcc/gcc/gimplify.c
@@ -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);
+}
+
 \f
 /* 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:
diff --git gcc/gcc/internal-fn.c gcc/gcc/internal-fn.c
index c269ca6..029a534 100644
--- gcc/gcc/internal-fn.c
+++ gcc/gcc/internal-fn.c
@@ -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
diff --git gcc/gcc/internal-fn.def gcc/gcc/internal-fn.def
index 6701cd9..d4fbdb2 100644
--- gcc/gcc/internal-fn.def
+++ gcc/gcc/internal-fn.def
@@ -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
diff --git gcc/gcc/langhooks.c gcc/gcc/langhooks.c
index 538d9f9..79a846c 100644
--- gcc/gcc/langhooks.c
+++ gcc/gcc/langhooks.c
@@ -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;
+}
diff --git gcc/gcc/langhooks.h gcc/gcc/langhooks.h
index c109c8c..cfaee62 100644
--- gcc/gcc/langhooks.h
+++ gcc/gcc/langhooks.h
@@ -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 */
diff --git gcc/gcc/system.h gcc/gcc/system.h
index 8a17197..8ca71cf 100644
--- gcc/gcc/system.h
+++ gcc/gcc/system.h
@@ -746,6 +746,12 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__))
 #endif
 
+#if GCC_VERSION >= 7000
+# define gcc_fallthrough() __attribute__((fallthrough))
+#else
+# define gcc_fallthrough()
+#endif
+
 #if GCC_VERSION >= 3001
 #define STATIC_CONSTANT_P(X) (__builtin_constant_p (X) && (X))
 #else
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
index e69de29..99e44d9 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
index e69de29..e8f47f5 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
index e69de29..91a68ab 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
index e69de29..f3ec79f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
index e69de29..b7c825b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
@@ -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:;
+  }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
index e69de29..ee3e52d 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
@@ -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;
+	}
+   }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
index e69de29..923f012 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
index e69de29..23ff5f1 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
index e69de29..2c8a3cb 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
index e69de29..b7a3791 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
@@ -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);
+	}
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
index e69de29..4dfb278 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
index e69de29..021a019 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
@@ -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-error "only attribute" } */
+    default:
+      __attribute__((used)); /* { dg-error "only attribute" } */
+    case 1:
+      return 6;
+    case 2 ... 4:
+      __attribute__((used)); /* { dg-error "only attribute" } */
+    case 5:
+      return 7;
+    }
+  return 0;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
index e69de29..6092a90 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
index e69de29..fbb9712 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
index e69de29..9a0aeb7 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
index e69de29..9317484 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
index e69de29..8364c1b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
index e69de29..21a158c 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
index e69de29..0ed7928 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
@@ -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:;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
index e69de29..394d699 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
index e69de29..5bd6a1a 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
@@ -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 "attribute ignored" } */
+
+  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" } */
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
index e69de29..db031cb 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
@@ -0,0 +1,57 @@
+/* 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-error "only attribute .fallthrough." "" { target c++ } 13 } */
+  case 2:
+    bar (1);
+    __attribute__((foo));
+    /* { dg-error "only attribute .fallthrough." "" { target c++ } 18 } */
+    /* { dg-warning "empty declaration" "" { target c } 18 } */
+  case 3:
+    bar (1);
+    __attribute__((fallthrough))
+    /* { dg-warning "not preceding" "" { target c++ } 23 } */
+  case 4: /* { dg-error "expected" } */
+    bar (1);
+    __attribute__((fallthrough)) 1; /* { dg-error "expected" } */
+  case 5:
+    bar (1);
+    __attribute__((fallthrough)) int i; /* { dg-warning "ignored" } */
+  case 6:
+    bar (1);
+    __attribute__((fallthrough ("x"))); /* { dg-error "attribute specified with a parameter" } */
+    /* { dg-error "only attribute .fallthrough." "" { target c++ } 33 } */
+    /* { dg-warning "empty declaration" "" { target c } 33 } */
+  case 7:
+    bar (1);
+    __attribute__((fallthrough, fallthrough)); /* { dg-error "attribute specified multiple times" } */
+    /* { dg-error "only attribute .fallthrough." "" { target c++ } 38 } */
+    /* { dg-warning "empty declaration" "" { target c } 38 } */
+  case 8:
+    bar (1);
+    __attribute__((fallthrough));
+  case 9:
+    __attribute__((fallthrough));
+    /* { dg-warning "not preceding" "" { target *-*-* } 45 } */
+    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);
+  }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
index e69de29..523067e 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
@@ -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" }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
index e69de29..1ecaf3e 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
@@ -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-error ".fallthrough. can appear at most once" }
+    case 2:
+      bar (2);
+    }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
index e69de29..d15b1ea 100644
--- gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
index e69de29..f8b54f5 100644
--- gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
+++ gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
+++ gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
@@ -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);
+    }
+}
diff --git gcc/gcc/tree-core.h gcc/gcc/tree-core.h
index 8b3e5cc..353a625 100644
--- gcc/gcc/tree-core.h
+++ gcc/gcc/tree-core.h
@@ -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
diff --git gcc/gcc/tree.h gcc/gcc/tree.h
index 38ee816..0d9ad01 100644
--- gcc/gcc/tree.h
+++ gcc/gcc/tree.h
@@ -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.
diff --git gcc/libcpp/include/cpplib.h gcc/libcpp/include/cpplib.h
index cfc6ccd..6352ac5 100644
--- gcc/libcpp/include/cpplib.h
+++ gcc/libcpp/include/cpplib.h
@@ -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.  */
 
diff --git gcc/libcpp/lex.c gcc/libcpp/lex.c
index 6254ed6..0c47e29 100644
--- gcc/libcpp/lex.c
+++ gcc/libcpp/lex.c
@@ -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;

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-20 15:49 Implement -Wimplicit-fallthrough (version 9) Marek Polacek
@ 2016-09-20 16:29 ` Jason Merrill
  2016-09-21 13:19   ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Jason Merrill @ 2016-09-20 16:29 UTC (permalink / raw)
  To: Marek Polacek, GCC Patches, Jakub Jelinek

On 09/20/2016 11:33 AM, Marek Polacek wrote:
> @@ -5135,6 +5135,30 @@ cp_parser_primary_expression (cp_parser *parser,
>  	case RID_AT_SELECTOR:
>  	  return cp_parser_objc_expression (parser);
>
> +	case RID_ATTRIBUTE:

Attribute handling doesn't belong in this function; we don't want to 
allow attributes anywhere we see a primary-expression.  This should be 
either in cp_parser_expression_statement or cp_parser_statement.

Jason

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-20 16:29 ` Jason Merrill
@ 2016-09-21 13:19   ` Marek Polacek
  2016-09-21 14:22     ` Jason Merrill
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-21 13:19 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek

On Tue, Sep 20, 2016 at 12:26:11PM -0400, Jason Merrill wrote:
> On 09/20/2016 11:33 AM, Marek Polacek wrote:
> > @@ -5135,6 +5135,30 @@ cp_parser_primary_expression (cp_parser *parser,
> >  	case RID_AT_SELECTOR:
> >  	  return cp_parser_objc_expression (parser);
> > 
> > +	case RID_ATTRIBUTE:
> 
> Attribute handling doesn't belong in this function; we don't want to allow
> attributes anywhere we see a primary-expression.  This should be either in
> cp_parser_expression_statement or cp_parser_statement.

All right.  I moved the attribute handling to cp_parser_expression_statement
in the following patch.  Anything else?  Thanks,

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2016-09-21  Marek Polacek  <polacek@redhat.com>
	    Jakub Jelinek  <jakub@redhat.com>

	PR c/7652
gcc/
	* 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.
gcc/c-family/
	* c-common.c (c_common_attribute_table): Add fallthrough attribute.
	(handle_fallthrough_attribute): New function.
	(maybe_attribute_fallthrough_p): New function.
	* c-common.h (maybe_attribute_fallthrough_p): Declare.
gcc/c/
	* 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.
gcc/cp/
	* 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 RID_ATTRIBUTE.
	(cp_parser_statement): Handle fallthrough attribute.
	(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.
gcc/testsuite/
	* 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.
	* 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.
libcpp/
	* 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.

diff --git gcc/gcc/c-family/c-common.c gcc/gcc/c-family/c-common.c
index d1372a4..4376e92 100644
--- gcc/gcc/c-family/c-common.c
+++ gcc/gcc/c-family/c-common.c
@@ -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 }
 };
 
@@ -9853,6 +9856,49 @@ 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
+maybe_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)))
+    {
+      error ("%<fallthrough%> attribute specified multiple times");
+      return false;
+    }
+  /* No attribute-argument-clause shall be present.  */
+  if (TREE_VALUE (t) != NULL_TREE)
+    {
+      error ("%<fallthrough%> attribute specified with a parameter");
+      return false;
+    }
+  /* 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;
+}
+
 \f
 /* Check for valid arguments being passed to a function with FNTYPE.
    There are NARGS arguments in the array ARGARRAY.  LOC should be used for
diff --git gcc/gcc/c-family/c-common.h gcc/gcc/c-family/c-common.h
index 5bbf951..b9b42a1 100644
--- gcc/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -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 maybe_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 *);
diff --git gcc/gcc/c/c-parser.c gcc/gcc/c/c-parser.c
index 58424a9..95603ca 100644
--- gcc/gcc/c/c-parser.c
+++ gcc/gcc/c/c-parser.c
@@ -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,16 @@ 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
+	       && specs->attrs
+	       && maybe_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
@@ -4841,12 +4860,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 +4984,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 +5035,29 @@ 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 (maybe_attribute_fallthrough_p (attrs))
+	    {
+	      tree fn = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
+						      void_type_node, 0);
+	      add_stmt (fn);
+	    }
+	  else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    c_parser_error (parser, "only attribute %<fallthrough%> "
+			    "can be applied to a null statement");
+	  else
+	    c_parser_error (parser, "only attribute %<fallthrough%> "
+			    "followed by %<;%> can be used");
+	}
       if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  error_at (c_parser_peek_token (parser)->location,
@@ -5062,6 +5111,9 @@ c_parser_label (c_parser *parser)
    jump-statement:
      goto * expression ;
 
+   expression-statement:
+     attributes ;
+
    Objective-C:
 
    statement:
@@ -5323,6 +5375,26 @@ 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 (maybe_attribute_fallthrough_p (attrs))
+	      {
+		location_t loc = c_parser_peek_token (parser)->location;
+		c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>");
+		tree fn = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
+							void_type_node, 0);
+		add_stmt (fn);
+	      }
+	    else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	      c_parser_error (parser, "only attribute %<fallthrough%> "
+			      "can be applied to a null statement");
+	    else
+	      c_parser_error (parser, "only attribute %<fallthrough%> "
+			      "followed by %<;%> can be used");
+	  }
+	  break;
 	default:
 	  goto expr_stmt;
 	}
diff --git gcc/gcc/common.opt gcc/gcc/common.opt
index fa1c036..e8a0154 100644
--- gcc/gcc/common.opt
+++ gcc/gcc/common.opt
@@ -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.
diff --git gcc/gcc/cp/constexpr.c gcc/gcc/cp/constexpr.c
index b7d49f1..9356d5d 100644
--- gcc/gcc/cp/constexpr.c
+++ gcc/gcc/cp/constexpr.c
@@ -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:
diff --git gcc/gcc/cp/constraint.cc gcc/gcc/cp/constraint.cc
index 311d025..b4d85c9 100644
--- gcc/gcc/cp/constraint.cc
+++ gcc/gcc/cp/constraint.cc
@@ -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);
diff --git gcc/gcc/cp/parser.c gcc/gcc/cp/parser.c
index 168486c..53028aa 100644
--- gcc/gcc/cp/parser.c
+++ gcc/gcc/cp/parser.c
@@ -10585,14 +10585,25 @@ 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 (std_attrs != NULL_TREE
+	  && maybe_attribute_fallthrough_p (std_attrs)
+	  && statement == NULL_TREE)
+	{
+	  statement = build_call_expr_internal_loc (statement_location,
+						    IFN_FALLTHROUGH,
+						    void_type_node, 0);
+	  finish_expr_stmt (statement);
+	  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 +10639,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 +10674,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 +10691,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 +10703,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;
     }
 
@@ -10733,12 +10758,35 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
      statement.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
     {
-      statement = cp_parser_expression (parser);
-      if (statement == error_mark_node
-	  && !cp_parser_uncommitted_to_tentative_parse_p (parser))
+      /* This might be attribute fallthrough.  */
+      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
 	{
-	  cp_parser_skip_to_end_of_block_or_statement (parser);
-	  return error_mark_node;
+	  tree attr = cp_parser_gnu_attributes_opt (parser);
+	  if (maybe_attribute_fallthrough_p (attr))
+	    statement = build_call_expr_internal_loc (token->location,
+						      IFN_FALLTHROUGH,
+						      void_type_node, 0);
+	  else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+	    {
+	      cp_parser_error (parser, "only attribute %<fallthrough%> "
+			       "can be applied to a null statement");
+	      return error_mark_node;
+	    }
+	  else
+	    {
+	      cp_parser_error (parser, "expected primary-expression");
+	      return error_mark_node;
+	    }
+	}
+      else
+	{
+	  statement = cp_parser_expression (parser);
+	  if (statement == error_mark_node
+	      && !cp_parser_uncommitted_to_tentative_parse_p (parser))
+	    {
+	      cp_parser_skip_to_end_of_block_or_statement (parser);
+	      return error_mark_node;
+	    }
 	}
     }
 
@@ -24116,7 +24164,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 +24172,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 +24239,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");
     }
 }
diff --git gcc/gcc/cp/pt.c gcc/gcc/cp/pt.c
index 29d8beb..a0cbb2e 100644
--- gcc/gcc/cp/pt.c
+++ gcc/gcc/cp/pt.c
@@ -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.  */
diff --git gcc/gcc/doc/extend.texi gcc/gcc/doc/extend.texi
index 299986d8..da0f5fa 100644
--- gcc/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -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
@@ -5563,8 +5565,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}).
 
@@ -6345,7 +6347,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
@@ -6855,7 +6858,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
@@ -6908,8 +6912,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:
@@ -6940,6 +6944,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
@@ -6967,6 +7011,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}
@@ -7032,6 +7078,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},
diff --git gcc/gcc/doc/invoke.texi gcc/gcc/doc/invoke.texi
index d171cfd..7f3a657 100644
--- gcc/gcc/doc/invoke.texi
+++ gcc/gcc/doc/invoke.texi
@@ -272,7 +272,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
@@ -3716,6 +3717,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
@@ -4002,6 +4004,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
diff --git gcc/gcc/gimple.h gcc/gcc/gimple.h
index 980bdf8..9fad15b 100644
--- gcc/gcc/gimple.h
+++ gcc/gcc/gimple.h
@@ -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.  */
 
diff --git gcc/gcc/gimplify.c gcc/gcc/gimplify.c
index e378ed0..66bb8be 100644
--- gcc/gcc/gimplify.c
+++ gcc/gcc/gimplify.c
@@ -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);
+}
+
 \f
 /* 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:
diff --git gcc/gcc/internal-fn.c gcc/gcc/internal-fn.c
index c269ca6..029a534 100644
--- gcc/gcc/internal-fn.c
+++ gcc/gcc/internal-fn.c
@@ -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
diff --git gcc/gcc/internal-fn.def gcc/gcc/internal-fn.def
index 6701cd9..d4fbdb2 100644
--- gcc/gcc/internal-fn.def
+++ gcc/gcc/internal-fn.def
@@ -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
diff --git gcc/gcc/langhooks.c gcc/gcc/langhooks.c
index 538d9f9..79a846c 100644
--- gcc/gcc/langhooks.c
+++ gcc/gcc/langhooks.c
@@ -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;
+}
diff --git gcc/gcc/langhooks.h gcc/gcc/langhooks.h
index c109c8c..cfaee62 100644
--- gcc/gcc/langhooks.h
+++ gcc/gcc/langhooks.h
@@ -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 */
diff --git gcc/gcc/system.h gcc/gcc/system.h
index 8a17197..8ca71cf 100644
--- gcc/gcc/system.h
+++ gcc/gcc/system.h
@@ -746,6 +746,12 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__))
 #endif
 
+#if GCC_VERSION >= 7000
+# define gcc_fallthrough() __attribute__((fallthrough))
+#else
+# define gcc_fallthrough()
+#endif
+
 #if GCC_VERSION >= 3001
 #define STATIC_CONSTANT_P(X) (__builtin_constant_p (X) && (X))
 #else
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
index e69de29..99e44d9 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
index e69de29..e8f47f5 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
index e69de29..91a68ab 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
index e69de29..f3ec79f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
index e69de29..b7c825b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
@@ -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:;
+  }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
index e69de29..ee3e52d 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
@@ -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;
+	}
+   }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
index e69de29..923f012 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
index e69de29..23ff5f1 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
index e69de29..2c8a3cb 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
index e69de29..b7a3791 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
@@ -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);
+	}
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
index e69de29..4dfb278 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
index e69de29..021a019 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
@@ -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-error "only attribute" } */
+    default:
+      __attribute__((used)); /* { dg-error "only attribute" } */
+    case 1:
+      return 6;
+    case 2 ... 4:
+      __attribute__((used)); /* { dg-error "only attribute" } */
+    case 5:
+      return 7;
+    }
+  return 0;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
index e69de29..6092a90 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
index e69de29..fbb9712 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
index e69de29..9a0aeb7 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
index e69de29..9317484 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
index e69de29..8364c1b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
index e69de29..21a158c 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
index e69de29..0ed7928 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
@@ -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:;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
index e69de29..394d699 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
index e69de29..5bd6a1a 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
@@ -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 "attribute ignored" } */
+
+  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" } */
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
index e69de29..db031cb 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
@@ -0,0 +1,57 @@
+/* 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-error "only attribute .fallthrough." "" { target c++ } 13 } */
+  case 2:
+    bar (1);
+    __attribute__((foo));
+    /* { dg-error "only attribute .fallthrough." "" { target c++ } 18 } */
+    /* { dg-warning "empty declaration" "" { target c } 18 } */
+  case 3:
+    bar (1);
+    __attribute__((fallthrough))
+    /* { dg-warning "not preceding" "" { target c++ } 23 } */
+  case 4: /* { dg-error "expected" } */
+    bar (1);
+    __attribute__((fallthrough)) 1; /* { dg-error "expected" } */
+  case 5:
+    bar (1);
+    __attribute__((fallthrough)) int i; /* { dg-warning "ignored" } */
+  case 6:
+    bar (1);
+    __attribute__((fallthrough ("x"))); /* { dg-error "attribute specified with a parameter" } */
+    /* { dg-error "only attribute .fallthrough." "" { target c++ } 33 } */
+    /* { dg-warning "empty declaration" "" { target c } 33 } */
+  case 7:
+    bar (1);
+    __attribute__((fallthrough, fallthrough)); /* { dg-error "attribute specified multiple times" } */
+    /* { dg-error "only attribute .fallthrough." "" { target c++ } 38 } */
+    /* { dg-warning "empty declaration" "" { target c } 38 } */
+  case 8:
+    bar (1);
+    __attribute__((fallthrough));
+  case 9:
+    __attribute__((fallthrough));
+    /* { dg-warning "not preceding" "" { target *-*-* } 45 } */
+    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);
+  }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
index e69de29..523067e 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
@@ -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" }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
index e69de29..12e89f5 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
@@ -0,0 +1,22 @@
+// 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); // { dg-warning "statement may fall through" }
+      [[gnu::fallthrough, gnu::fallthrough]]; // { dg-error ".fallthrough. attribute specified multiple times" }
+      // { dg-warning "ignored" "" { target *-*-* } 17 }
+    case 2:
+      bar (2);
+    }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
index e69de29..d15b1ea 100644
--- gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
index e69de29..f8b54f5 100644
--- gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
+++ gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
+++ gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
@@ -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);
+    }
+}
diff --git gcc/gcc/tree-core.h gcc/gcc/tree-core.h
index 8b3e5cc..353a625 100644
--- gcc/gcc/tree-core.h
+++ gcc/gcc/tree-core.h
@@ -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
diff --git gcc/gcc/tree.h gcc/gcc/tree.h
index 38ee816..0d9ad01 100644
--- gcc/gcc/tree.h
+++ gcc/gcc/tree.h
@@ -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.
diff --git gcc/libcpp/include/cpplib.h gcc/libcpp/include/cpplib.h
index cfc6ccd..6352ac5 100644
--- gcc/libcpp/include/cpplib.h
+++ gcc/libcpp/include/cpplib.h
@@ -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.  */
 
diff --git gcc/libcpp/lex.c gcc/libcpp/lex.c
index 6254ed6..0c47e29 100644
--- gcc/libcpp/lex.c
+++ gcc/libcpp/lex.c
@@ -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;

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-21 13:19   ` Marek Polacek
@ 2016-09-21 14:22     ` Jason Merrill
  2016-09-21 19:25       ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Jason Merrill @ 2016-09-21 14:22 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek

On 09/21/2016 08:44 AM, Marek Polacek wrote:
> @@ -10733,12 +10758,35 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
>       statement.  */
>    if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
>      {
> +      /* This might be attribute fallthrough.  */
> +      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
>  	{
> +	  tree attr = cp_parser_gnu_attributes_opt (parser);
> +	  if (maybe_attribute_fallthrough_p (attr))
> +	    statement = build_call_expr_internal_loc (token->location,
> +						      IFN_FALLTHROUGH,
> +						      void_type_node, 0);
> +	  else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
> +	    {
> +	      cp_parser_error (parser, "only attribute %<fallthrough%> "
> +			       "can be applied to a null statement");
> +	      return error_mark_node;
> +	    }
> +	  else
> +	    {
> +	      cp_parser_error (parser, "expected primary-expression");
> +	      return error_mark_node;
> +	    }
> +	}

Attributes that we don't handle should be warnings, not errors.  Like we 
do for C++11 attributes in cp_parser_statement, we should first parse 
attributes, then parse the expression-statement, then give any 
appropriate warnings.

Jason

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-21 14:22     ` Jason Merrill
@ 2016-09-21 19:25       ` Marek Polacek
  2016-09-21 19:40         ` Jason Merrill
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-21 19:25 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek

On Wed, Sep 21, 2016 at 10:06:07AM -0400, Jason Merrill wrote:
> On 09/21/2016 08:44 AM, Marek Polacek wrote:
> > @@ -10733,12 +10758,35 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
> >       statement.  */
> >    if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
> >      {
> > +      /* This might be attribute fallthrough.  */
> > +      if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
> >  	{
> > +	  tree attr = cp_parser_gnu_attributes_opt (parser);
> > +	  if (maybe_attribute_fallthrough_p (attr))
> > +	    statement = build_call_expr_internal_loc (token->location,
> > +						      IFN_FALLTHROUGH,
> > +						      void_type_node, 0);
> > +	  else if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
> > +	    {
> > +	      cp_parser_error (parser, "only attribute %<fallthrough%> "
> > +			       "can be applied to a null statement");
> > +	      return error_mark_node;
> > +	    }
> > +	  else
> > +	    {
> > +	      cp_parser_error (parser, "expected primary-expression");
> > +	      return error_mark_node;
> > +	    }
> > +	}
> 
> Attributes that we don't handle should be warnings, not errors.  Like we do
> for C++11 attributes in cp_parser_statement, we should first parse
> attributes, then parse the expression-statement, then give any appropriate
> warnings.

Ok, I hope this is at least somewhat closer to what you imagine.  I had to
adjust g++.dg/warn/Wunused-label-1.C test because of this.  I also turned
errors for e.g. __attribute__((used)); into warnings in the C FE.

So hopefully one step closer.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2016-09-21  Marek Polacek  <polacek@redhat.com>
	    Jakub Jelinek  <jakub@redhat.com>

	PR c/7652
gcc/
	* 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.
gcc/c-family/
	* c-common.c (c_common_attribute_table): Add fallthrough attribute.
	(handle_fallthrough_attribute): New function.
	(maybe_attribute_fallthrough_p): New function.
	* c-common.h (maybe_attribute_fallthrough_p): Declare.
gcc/c/
	* 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.
gcc/cp/
	* 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.
gcc/testsuite/
	* 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.
libcpp/
	* 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.

diff --git gcc/gcc/c-family/c-common.c gcc/gcc/c-family/c-common.c
index d1372a4..ae18c00 100644
--- gcc/gcc/c-family/c-common.c
+++ gcc/gcc/c-family/c-common.c
@@ -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 }
 };
 
@@ -9853,6 +9856,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
+maybe_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;
+}
+
 \f
 /* Check for valid arguments being passed to a function with FNTYPE.
    There are NARGS arguments in the array ARGARRAY.  LOC should be used for
diff --git gcc/gcc/c-family/c-common.h gcc/gcc/c-family/c-common.h
index 5bbf951..b9b42a1 100644
--- gcc/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -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 maybe_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 *);
diff --git gcc/gcc/c/c-parser.c gcc/gcc/c/c-parser.c
index 58424a9..90e62ec 100644
--- gcc/gcc/c/c-parser.c
+++ gcc/gcc/c/c-parser.c
@@ -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,16 @@ 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
+	       && specs->attrs
+	       && maybe_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
@@ -4841,12 +4860,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 +4984,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 +5035,29 @@ 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 (maybe_attribute_fallthrough_p (attrs))
+	    {
+	      tree fn = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
+						      void_type_node, 0);
+	      add_stmt (fn);
+	    }
+	  else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%> "
+			"can be applied to a null statement");
+	  else
+	    warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%> "
+			"followed by %<;%> can be used");
+	}
       if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  error_at (c_parser_peek_token (parser)->location,
@@ -5062,6 +5111,9 @@ c_parser_label (c_parser *parser)
    jump-statement:
      goto * expression ;
 
+   expression-statement:
+     attributes ;
+
    Objective-C:
 
    statement:
@@ -5323,6 +5375,26 @@ 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 (maybe_attribute_fallthrough_p (attrs))
+	      {
+		location_t loc = c_parser_peek_token (parser)->location;
+		c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>");
+		tree fn = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
+							void_type_node, 0);
+		add_stmt (fn);
+	      }
+	    else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	      warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
+			  " can be applied to a null statement");
+	    else
+	      warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
+			  " followed by %<;%> can be used");
+	    break;
+	  }
 	default:
 	  goto expr_stmt;
 	}
diff --git gcc/gcc/common.opt gcc/gcc/common.opt
index 8c0885c..b1d32fb 100644
--- gcc/gcc/common.opt
+++ gcc/gcc/common.opt
@@ -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.
diff --git gcc/gcc/cp/constexpr.c gcc/gcc/cp/constexpr.c
index b7d49f1..9356d5d 100644
--- gcc/gcc/cp/constexpr.c
+++ gcc/gcc/cp/constexpr.c
@@ -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:
diff --git gcc/gcc/cp/constraint.cc gcc/gcc/cp/constraint.cc
index 311d025..b4d85c9 100644
--- gcc/gcc/cp/constraint.cc
+++ gcc/gcc/cp/constraint.cc
@@ -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);
diff --git gcc/gcc/cp/parser.c gcc/gcc/cp/parser.c
index 168486c..ba509db 100644
--- gcc/gcc/cp/parser.c
+++ gcc/gcc/cp/parser.c
@@ -10585,14 +10585,25 @@ 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 (std_attrs != NULL_TREE
+	  && maybe_attribute_fallthrough_p (std_attrs)
+	  && statement == NULL_TREE)
+	{
+	  statement = build_call_expr_internal_loc (statement_location,
+						    IFN_FALLTHROUGH,
+						    void_type_node, 0);
+	  finish_expr_stmt (statement);
+	  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 +10639,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 +10674,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 +10691,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 +10703,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 +10753,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 +10771,21 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
 	}
     }
 
+  if (statement == NULL_TREE
+      && attr != NULL_TREE
+      && maybe_attribute_fallthrough_p (attr))
+    {
+      /* Turn [[fallthrough]]; into FALLTHROUGH ();.  */
+      statement = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
+						void_type_node, 0);
+      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))
@@ -24116,7 +24160,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 +24168,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 +24235,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");
     }
 }
diff --git gcc/gcc/cp/pt.c gcc/gcc/cp/pt.c
index 29d8beb..a0cbb2e 100644
--- gcc/gcc/cp/pt.c
+++ gcc/gcc/cp/pt.c
@@ -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.  */
diff --git gcc/gcc/doc/extend.texi gcc/gcc/doc/extend.texi
index 299986d8..da0f5fa 100644
--- gcc/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -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
@@ -5563,8 +5565,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}).
 
@@ -6345,7 +6347,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
@@ -6855,7 +6858,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
@@ -6908,8 +6912,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:
@@ -6940,6 +6944,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
@@ -6967,6 +7011,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}
@@ -7032,6 +7078,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},
diff --git gcc/gcc/doc/invoke.texi gcc/gcc/doc/invoke.texi
index cfba069..b9a5105 100644
--- gcc/gcc/doc/invoke.texi
+++ gcc/gcc/doc/invoke.texi
@@ -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
@@ -3717,6 +3718,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
@@ -4085,6 +4087,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
diff --git gcc/gcc/gimple.h gcc/gcc/gimple.h
index 980bdf8..9fad15b 100644
--- gcc/gcc/gimple.h
+++ gcc/gcc/gimple.h
@@ -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.  */
 
diff --git gcc/gcc/gimplify.c gcc/gcc/gimplify.c
index e378ed0..66bb8be 100644
--- gcc/gcc/gimplify.c
+++ gcc/gcc/gimplify.c
@@ -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);
+}
+
 \f
 /* 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:
diff --git gcc/gcc/internal-fn.c gcc/gcc/internal-fn.c
index c269ca6..029a534 100644
--- gcc/gcc/internal-fn.c
+++ gcc/gcc/internal-fn.c
@@ -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
diff --git gcc/gcc/internal-fn.def gcc/gcc/internal-fn.def
index 6701cd9..d4fbdb2 100644
--- gcc/gcc/internal-fn.def
+++ gcc/gcc/internal-fn.def
@@ -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
diff --git gcc/gcc/langhooks.c gcc/gcc/langhooks.c
index 538d9f9..79a846c 100644
--- gcc/gcc/langhooks.c
+++ gcc/gcc/langhooks.c
@@ -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;
+}
diff --git gcc/gcc/langhooks.h gcc/gcc/langhooks.h
index c109c8c..cfaee62 100644
--- gcc/gcc/langhooks.h
+++ gcc/gcc/langhooks.h
@@ -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 */
diff --git gcc/gcc/system.h gcc/gcc/system.h
index 8a17197..8ca71cf 100644
--- gcc/gcc/system.h
+++ gcc/gcc/system.h
@@ -746,6 +746,12 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__))
 #endif
 
+#if GCC_VERSION >= 7000
+# define gcc_fallthrough() __attribute__((fallthrough))
+#else
+# define gcc_fallthrough()
+#endif
+
 #if GCC_VERSION >= 3001
 #define STATIC_CONSTANT_P(X) (__builtin_constant_p (X) && (X))
 #else
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
index e69de29..99e44d9 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
index e69de29..e8f47f5 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
index e69de29..91a68ab 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
index e69de29..f3ec79f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
index e69de29..b7c825b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
@@ -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:;
+  }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
index e69de29..ee3e52d 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
@@ -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;
+	}
+   }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
index e69de29..923f012 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
index e69de29..23ff5f1 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
index e69de29..2c8a3cb 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
index e69de29..b7a3791 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
@@ -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);
+	}
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
index e69de29..4dfb278 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
index e69de29..d37a840 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
index e69de29..6092a90 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
index e69de29..fbb9712 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
index e69de29..9a0aeb7 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
index e69de29..9317484 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
index e69de29..8364c1b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
index e69de29..21a158c 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
index e69de29..0ed7928 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
@@ -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:;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
index e69de29..394d699 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
index e69de29..5bd6a1a 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
@@ -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 "attribute ignored" } */
+
+  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" } */
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
index e69de29..dca17fb 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
@@ -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))
+  case 4: /* { dg-error "expected" } */
+    bar (1);
+    __attribute__((fallthrough)) 1;
+    /* { dg-error "expected" "" { target c } 26 } */
+    /* { dg-warning "ignored" "" { target c++ } 26 } */
+  case 5:
+    bar (1);
+    __attribute__((fallthrough)) int i; /* { dg-warning "ignored" } */
+  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);
+  }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
index e69de29..523067e 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
@@ -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" }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
index e69de29..b6964e1 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
index e69de29..d15b1ea 100644
--- gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C
index 96f49b3..255a26e 100644
--- gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C
+++ gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C
@@ -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 }
diff --git gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
index e69de29..f8b54f5 100644
--- gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
+++ gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
+++ gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
@@ -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);
+    }
+}
diff --git gcc/gcc/tree-core.h gcc/gcc/tree-core.h
index 8b3e5cc..353a625 100644
--- gcc/gcc/tree-core.h
+++ gcc/gcc/tree-core.h
@@ -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
diff --git gcc/gcc/tree.h gcc/gcc/tree.h
index 38ee816..0d9ad01 100644
--- gcc/gcc/tree.h
+++ gcc/gcc/tree.h
@@ -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.
diff --git gcc/libcpp/include/cpplib.h gcc/libcpp/include/cpplib.h
index cfc6ccd..6352ac5 100644
--- gcc/libcpp/include/cpplib.h
+++ gcc/libcpp/include/cpplib.h
@@ -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.  */
 
diff --git gcc/libcpp/lex.c gcc/libcpp/lex.c
index 6254ed6..0c47e29 100644
--- gcc/libcpp/lex.c
+++ gcc/libcpp/lex.c
@@ -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;

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-21 19:25       ` Marek Polacek
@ 2016-09-21 19:40         ` Jason Merrill
  2016-09-22 14:24           ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Jason Merrill @ 2016-09-21 19:40 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek

On 09/21/2016 02:59 PM, Marek Polacek wrote:
> +  if (statement == NULL_TREE
> +      && attr != NULL_TREE
> +      && maybe_attribute_fallthrough_p (attr))
> +    {
> +      /* Turn [[fallthrough]]; into FALLTHROUGH ();.  */
> +      statement = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
> +						void_type_node, 0);
> +      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");

This is very close, thanks.  Let's give a more helpful warning about

[[fallthrough]] 0;
__attribute__ ((fallthrough)) 0;

both here and in cp_parser_statement, something like "fallthrough 
attribute not followed by ';'"

Jason

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-21 19:40         ` Jason Merrill
@ 2016-09-22 14:24           ` Marek Polacek
  2016-09-23 14:11             ` Marek Polacek
  2016-09-23 14:26             ` Jason Merrill
  0 siblings, 2 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-22 14:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek

On Wed, Sep 21, 2016 at 03:14:07PM -0400, Jason Merrill wrote:
> On 09/21/2016 02:59 PM, Marek Polacek wrote:
> > +  if (statement == NULL_TREE
> > +      && attr != NULL_TREE
> > +      && maybe_attribute_fallthrough_p (attr))
> > +    {
> > +      /* Turn [[fallthrough]]; into FALLTHROUGH ();.  */
> > +      statement = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH,
> > +						void_type_node, 0);
> > +      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");
> 
> This is very close, thanks.  Let's give a more helpful warning about
> 
> [[fallthrough]] 0;
> __attribute__ ((fallthrough)) 0;
> 
> both here and in cp_parser_statement, something like "fallthrough attribute
> not followed by ';'"

Done.  And I made similar tweaks in the C FE.

Bootstrapped/regtested on x86_64-linux and ppc64-linux.

2016-09-22  Marek Polacek  <polacek@redhat.com>
	    Jakub Jelinek  <jakub@redhat.com>

	PR c/7652
gcc/
	* 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.
gcc/c-family/
	* 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.
gcc/c/
	* 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.
gcc/cp/
	* 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.
gcc/testsuite/
	* 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.
libcpp/
	* 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.

diff --git gcc/gcc/c-family/c-common.c gcc/gcc/c-family/c-common.c
index d1372a4..acb18e6 100644
--- gcc/gcc/c-family/c-common.c
+++ gcc/gcc/c-family/c-common.c
@@ -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 }
 };
 
@@ -9853,6 +9856,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;
+}
+
 \f
 /* Check for valid arguments being passed to a function with FNTYPE.
    There are NARGS arguments in the array ARGARRAY.  LOC should be used for
diff --git gcc/gcc/c-family/c-common.h gcc/gcc/c-family/c-common.h
index 5bbf951..c88619b 100644
--- gcc/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -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 *);
diff --git gcc/gcc/c/c-parser.c gcc/gcc/c/c-parser.c
index 58424a9..556472c 100644
--- gcc/gcc/c/c-parser.c
+++ gcc/gcc/c/c-parser.c
@@ -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;
 	}
diff --git gcc/gcc/common.opt gcc/gcc/common.opt
index 8c0885c..b1d32fb 100644
--- gcc/gcc/common.opt
+++ gcc/gcc/common.opt
@@ -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.
diff --git gcc/gcc/cp/constexpr.c gcc/gcc/cp/constexpr.c
index b7d49f1..9356d5d 100644
--- gcc/gcc/cp/constexpr.c
+++ gcc/gcc/cp/constexpr.c
@@ -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:
diff --git gcc/gcc/cp/constraint.cc gcc/gcc/cp/constraint.cc
index 311d025..b4d85c9 100644
--- gcc/gcc/cp/constraint.cc
+++ gcc/gcc/cp/constraint.cc
@@ -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);
diff --git gcc/gcc/cp/parser.c gcc/gcc/cp/parser.c
index 168486c..0796f19 100644
--- gcc/gcc/cp/parser.c
+++ gcc/gcc/cp/parser.c
@@ -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))
@@ -24116,7 +24170,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 +24178,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 +24245,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");
     }
 }
diff --git gcc/gcc/cp/pt.c gcc/gcc/cp/pt.c
index 29d8beb..a0cbb2e 100644
--- gcc/gcc/cp/pt.c
+++ gcc/gcc/cp/pt.c
@@ -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.  */
diff --git gcc/gcc/doc/extend.texi gcc/gcc/doc/extend.texi
index 299986d8..da0f5fa 100644
--- gcc/gcc/doc/extend.texi
+++ gcc/gcc/doc/extend.texi
@@ -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
@@ -5563,8 +5565,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}).
 
@@ -6345,7 +6347,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
@@ -6855,7 +6858,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
@@ -6908,8 +6912,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:
@@ -6940,6 +6944,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
@@ -6967,6 +7011,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}
@@ -7032,6 +7078,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},
diff --git gcc/gcc/doc/invoke.texi gcc/gcc/doc/invoke.texi
index cfba069..b9a5105 100644
--- gcc/gcc/doc/invoke.texi
+++ gcc/gcc/doc/invoke.texi
@@ -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
@@ -3717,6 +3718,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
@@ -4085,6 +4087,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
diff --git gcc/gcc/gimple.h gcc/gcc/gimple.h
index 980bdf8..9fad15b 100644
--- gcc/gcc/gimple.h
+++ gcc/gcc/gimple.h
@@ -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.  */
 
diff --git gcc/gcc/gimplify.c gcc/gcc/gimplify.c
index e378ed0..66bb8be 100644
--- gcc/gcc/gimplify.c
+++ gcc/gcc/gimplify.c
@@ -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);
+}
+
 \f
 /* 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:
diff --git gcc/gcc/internal-fn.c gcc/gcc/internal-fn.c
index c269ca6..029a534 100644
--- gcc/gcc/internal-fn.c
+++ gcc/gcc/internal-fn.c
@@ -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
diff --git gcc/gcc/internal-fn.def gcc/gcc/internal-fn.def
index 6701cd9..d4fbdb2 100644
--- gcc/gcc/internal-fn.def
+++ gcc/gcc/internal-fn.def
@@ -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
diff --git gcc/gcc/langhooks.c gcc/gcc/langhooks.c
index 538d9f9..79a846c 100644
--- gcc/gcc/langhooks.c
+++ gcc/gcc/langhooks.c
@@ -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;
+}
diff --git gcc/gcc/langhooks.h gcc/gcc/langhooks.h
index c109c8c..cfaee62 100644
--- gcc/gcc/langhooks.h
+++ gcc/gcc/langhooks.h
@@ -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 */
diff --git gcc/gcc/system.h gcc/gcc/system.h
index 8a17197..8ca71cf 100644
--- gcc/gcc/system.h
+++ gcc/gcc/system.h
@@ -746,6 +746,12 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__))
 #endif
 
+#if GCC_VERSION >= 7000
+# define gcc_fallthrough() __attribute__((fallthrough))
+#else
+# define gcc_fallthrough()
+#endif
+
 #if GCC_VERSION >= 3001
 #define STATIC_CONSTANT_P(X) (__builtin_constant_p (X) && (X))
 #else
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
index e69de29..99e44d9 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
index e69de29..e8f47f5 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
index e69de29..91a68ab 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
index e69de29..f3ec79f 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
index e69de29..b7c825b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c
@@ -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:;
+  }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
index e69de29..ee3e52d 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c
@@ -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;
+	}
+   }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
index e69de29..923f012 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
index e69de29..23ff5f1 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c
@@ -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;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
index e69de29..2c8a3cb 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
index e69de29..b7a3791 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c
@@ -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);
+	}
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
index e69de29..4dfb278 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
index e69de29..d37a840 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
index e69de29..6092a90 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
index e69de29..fbb9712 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
index e69de29..9a0aeb7 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c
@@ -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 ();
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
index e69de29..9317484 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
index e69de29..8364c1b 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
index e69de29..21a158c 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
index e69de29..0ed7928 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c
@@ -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:;
+}
diff --git gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
index e69de29..394d699 100644
--- gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
+++ gcc/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c
@@ -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:;
+    }
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
index e69de29..ecfd094 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-1.c
@@ -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" } */
+}
diff --git gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
index e69de29..959564b 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
@@ -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);
+  }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
index e69de29..523067e 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
@@ -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" }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
index e69de29..b6964e1 100644
--- gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
+++ gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
index e69de29..d15b1ea 100644
--- gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
+++ gcc/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C
index 96f49b3..255a26e 100644
--- gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C
+++ gcc/gcc/testsuite/g++.dg/warn/Wunused-label-1.C
@@ -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 }
diff --git gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
index e69de29..f8b54f5 100644
--- gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
@@ -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;
+}
diff --git gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
+++ gcc/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm
@@ -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);
+    }
+}
diff --git gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
index e69de29..b45880f 100644
--- gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
+++ gcc/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m
@@ -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);
+    }
+}
diff --git gcc/gcc/tree-core.h gcc/gcc/tree-core.h
index 8b3e5cc..353a625 100644
--- gcc/gcc/tree-core.h
+++ gcc/gcc/tree-core.h
@@ -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
diff --git gcc/gcc/tree.h gcc/gcc/tree.h
index 38ee816..0d9ad01 100644
--- gcc/gcc/tree.h
+++ gcc/gcc/tree.h
@@ -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.
diff --git gcc/libcpp/include/cpplib.h gcc/libcpp/include/cpplib.h
index cfc6ccd..6352ac5 100644
--- gcc/libcpp/include/cpplib.h
+++ gcc/libcpp/include/cpplib.h
@@ -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.  */
 
diff --git gcc/libcpp/lex.c gcc/libcpp/lex.c
index 6254ed6..0c47e29 100644
--- gcc/libcpp/lex.c
+++ gcc/libcpp/lex.c
@@ -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;

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-22 14:24           ` Marek Polacek
@ 2016-09-23 14:11             ` Marek Polacek
  2016-09-23 14:26             ` Jason Merrill
  1 sibling, 0 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-23 14:11 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches, Jakub Jelinek

It occurred to me that I should also handle the
__has_cpp_attribute(fallthrough) part.  But I hope that can be done after the
main -Wimplicit-fallthrough is committed.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-22 14:24           ` Marek Polacek
  2016-09-23 14:11             ` Marek Polacek
@ 2016-09-23 14:26             ` Jason Merrill
  2016-09-23 14:27               ` Jakub Jelinek
  2016-09-23 14:31               ` Marek Polacek
  1 sibling, 2 replies; 81+ messages in thread
From: Jason Merrill @ 2016-09-23 14:26 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jakub Jelinek

On Thu, Sep 22, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
>> This is very close, thanks.  Let's give a more helpful warning about
>>
>> [[fallthrough]] 0;
>> __attribute__ ((fallthrough)) 0;
>>
>> both here and in cp_parser_statement, something like "fallthrough attribute
>> not followed by ';'"
>
> Done.  And I made similar tweaks in the C FE.

The C++ changes are OK.

Jason

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-23 14:26             ` Jason Merrill
@ 2016-09-23 14:27               ` Jakub Jelinek
  2016-09-23 14:34                 ` Marek Polacek
  2016-09-23 14:31               ` Marek Polacek
  1 sibling, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-23 14:27 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Marek Polacek, GCC Patches

On Fri, Sep 23, 2016 at 10:22:15AM -0400, Jason Merrill wrote:
> On Thu, Sep 22, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> >> This is very close, thanks.  Let's give a more helpful warning about
> >>
> >> [[fallthrough]] 0;
> >> __attribute__ ((fallthrough)) 0;
> >>
> >> both here and in cp_parser_statement, something like "fallthrough attribute
> >> not followed by ';'"
> >
> > Done.  And I made similar tweaks in the C FE.
> 
> The C++ changes are OK.

And the middle-end changes are ok too.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-23 14:26             ` Jason Merrill
  2016-09-23 14:27               ` Jakub Jelinek
@ 2016-09-23 14:31               ` Marek Polacek
  2016-09-24  0:19                 ` Joseph Myers
  1 sibling, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-23 14:31 UTC (permalink / raw)
  To: Jason Merrill, Joseph Myers; +Cc: GCC Patches, Jakub Jelinek

On Fri, Sep 23, 2016 at 10:22:15AM -0400, Jason Merrill wrote:
> On Thu, Sep 22, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> >> This is very close, thanks.  Let's give a more helpful warning about
> >>
> >> [[fallthrough]] 0;
> >> __attribute__ ((fallthrough)) 0;
> >>
> >> both here and in cp_parser_statement, something like "fallthrough attribute
> >> not followed by ';'"
> >
> > Done.  And I made similar tweaks in the C FE.
> 
> The C++ changes are OK.

Thanks very much!

Now I'd like to ask for an approval of the ME parts.

Also, Joseph said he had no comments, but since I've changed the C FE
parts a bit, I'd like to give him a chance to comment to perhaps look
at this again.

Thanks,

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-23 14:27               ` Jakub Jelinek
@ 2016-09-23 14:34                 ` Marek Polacek
  0 siblings, 0 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-23 14:34 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, GCC Patches

On Fri, Sep 23, 2016 at 04:23:29PM +0200, Jakub Jelinek wrote:
> On Fri, Sep 23, 2016 at 10:22:15AM -0400, Jason Merrill wrote:
> > On Thu, Sep 22, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> > >> This is very close, thanks.  Let's give a more helpful warning about
> > >>
> > >> [[fallthrough]] 0;
> > >> __attribute__ ((fallthrough)) 0;
> > >>
> > >> both here and in cp_parser_statement, something like "fallthrough attribute
> > >> not followed by ';'"
> > >
> > > Done.  And I made similar tweaks in the C FE.
> > 
> > The C++ changes are OK.
> 
> And the middle-end changes are ok too.

Thanks a lot.  As mentioned in the other mail I've just sent, I'll give
Joseph a chance to comment on this, if he wishes to.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-23 14:31               ` Marek Polacek
@ 2016-09-24  0:19                 ` Joseph Myers
  2016-09-24 13:32                   ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Joseph Myers @ 2016-09-24  0:19 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jason Merrill, GCC Patches, Jakub Jelinek

On Fri, 23 Sep 2016, Marek Polacek wrote:

> On Fri, Sep 23, 2016 at 10:22:15AM -0400, Jason Merrill wrote:
> > On Thu, Sep 22, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> > >> This is very close, thanks.  Let's give a more helpful warning about
> > >>
> > >> [[fallthrough]] 0;
> > >> __attribute__ ((fallthrough)) 0;
> > >>
> > >> both here and in cp_parser_statement, something like "fallthrough attribute
> > >> not followed by ';'"
> > >
> > > Done.  And I made similar tweaks in the C FE.
> > 
> > The C++ changes are OK.
> 
> Thanks very much!
> 
> Now I'd like to ask for an approval of the ME parts.
> 
> Also, Joseph said he had no comments, but since I've changed the C FE
> parts a bit, I'd like to give him a chance to comment to perhaps look
> at this again.

I still have no comments on the C changes.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-24  0:19                 ` Joseph Myers
@ 2016-09-24 13:32                   ` Marek Polacek
  2016-09-26 13:41                     ` Rainer Orth
                                       ` (2 more replies)
  0 siblings, 3 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-24 13:32 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jason Merrill, GCC Patches, Jakub Jelinek

On Fri, Sep 23, 2016 at 10:12:00PM +0000, Joseph Myers wrote:
> On Fri, 23 Sep 2016, Marek Polacek wrote:
> 
> > On Fri, Sep 23, 2016 at 10:22:15AM -0400, Jason Merrill wrote:
> > > On Thu, Sep 22, 2016 at 9:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> > > >> This is very close, thanks.  Let's give a more helpful warning about
> > > >>
> > > >> [[fallthrough]] 0;
> > > >> __attribute__ ((fallthrough)) 0;
> > > >>
> > > >> both here and in cp_parser_statement, something like "fallthrough attribute
> > > >> not followed by ';'"
> > > >
> > > > Done.  And I made similar tweaks in the C FE.
> > > 
> > > The C++ changes are OK.
> > 
> > Thanks very much!
> > 
> > Now I'd like to ask for an approval of the ME parts.
> > 
> > Also, Joseph said he had no comments, but since I've changed the C FE
> > parts a bit, I'd like to give him a chance to comment to perhaps look
> > at this again.
> 
> I still have no comments on the C changes.

All right.  I'll commit the patch on Monday.

Thanks all.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-24 13:32                   ` Marek Polacek
@ 2016-09-26 13:41                     ` Rainer Orth
  2016-09-26 13:53                       ` Jakub Jelinek
                                         ` (3 more replies)
  2016-09-27  7:55                     ` Gerald Pfeifer
  2016-09-27  8:17                     ` Andreas Schwab
  2 siblings, 4 replies; 81+ messages in thread
From: Rainer Orth @ 2016-09-26 13:41 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Joseph Myers, Jason Merrill, GCC Patches, Jakub Jelinek,
	Arnaud Charlet, Eric Botcazou

[-- Attachment #1: Type: text/plain, Size: 444 bytes --]

Hi Marek,

> All right.  I'll commit the patch on Monday.

this patch caused quite some breakage: Ada, Solaris/x86 and SPARC don't
bootstrap any longer. 

The following patch allows i386-pc-solaris2.12 and sparc-sun-solaris2.12
bootstraps continue.

Strangely, I needed to use gcc_fallthrough () in i386.c; a mere /* FALLTHRU */
had no effect.

Ok for mainline if the bootstraps pass (with appropriate changelog
entries, of course)?

	Rainer



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: fallthrough.patch --]
[-- Type: text/x-patch, Size: 9677 bytes --]

diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -596,7 +596,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	gnu_expr
 	  = gnat_to_gnu_external (Expression (Declaration_Node (gnat_entity)));
 
-      /* ... fall through ... */
+      /* fall through */
 
     case E_Exception:
     case E_Loop_Parameter:
@@ -3369,7 +3369,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	  break;
 	}
 
-      /* ... fall through ... */
+      /* fall through */
 
     case E_Record_Subtype:
       /* If Cloned_Subtype is Present it means this record subtype has
@@ -3804,7 +3804,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	    break;
 	}
 
-      /* ... fall through ... */
+      /* fall through */
 
     case E_Allocator_Type:
     case E_Access_Type:
@@ -6882,7 +6882,7 @@ choices_to_gnu (tree operand, Node_Id ch
 	      break;
 	    }
 
-	  /* ... fall through ... */
+	  /* fall through */
 
 	case N_Character_Literal:
 	case N_Integer_Literal:
@@ -8089,7 +8089,7 @@ annotate_value (tree gnu_size)
       else
 	return Uint_Minus_1;
 
-      /* Fall through... */
+      /* fall through */
 
     default:
       return No_Uint;
diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -157,7 +157,7 @@ gnat_handle_option (size_t scode, const 
     case OPT_gant:
       warning (0, "%<-gnat%> misspelled as %<-gant%>");
 
-      /* ... fall through ... */
+      /* fall through */
 
     case OPT_gnat:
     case OPT_gnatO:
@@ -486,13 +486,13 @@ gnat_print_type (FILE *file, tree node, 
       else
 	print_node (file, "index type", TYPE_INDEX_TYPE (node), indent + 4);
 
-      /* ... fall through ... */
+      /* fall through */
 
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
       print_node_brief (file, "RM size", TYPE_RM_SIZE (node), indent + 4);
 
-      /* ... fall through ... */
+      /* fall through */
 
     case REAL_TYPE:
       print_node_brief (file, "RM min", TYPE_RM_MIN_VALUE (node), indent + 4);
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -844,7 +844,7 @@ lvalue_required_p (Node_Id gnat_node, tr
 		 && Ekind (Entity (gnat_temp)) == E_Enumeration_Literal))
 	  return 1;
 
-      /* ... fall through ... */
+      /* fall through */
 
     case N_Slice:
       /* Only the array expression can require an lvalue.  */
@@ -890,7 +890,7 @@ lvalue_required_p (Node_Id gnat_node, tr
 	if (!constant)
 	  return 1;
 
-      /* ... fall through ... */
+      /* fall through */
 
     case N_Type_Conversion:
     case N_Qualified_Expression:
@@ -914,7 +914,7 @@ lvalue_required_p (Node_Id gnat_node, tr
 				  get_unpadded_type (Etype (gnat_parent)),
 				  true, false, true);
 
-      /* ... fall through ... */
+      /* fall through */
 
     default:
       return 0;
@@ -1681,7 +1681,7 @@ Attribute_to_gnu (Node_Id gnat_node, tre
 	  break;
 	}
 
-      /* ... fall through ... */
+      /* fall through */
 
     case Attr_Access:
     case Attr_Unchecked_Access:
@@ -1938,7 +1938,7 @@ Attribute_to_gnu (Node_Id gnat_node, tre
 	  break;
 	}
 
-      /* ... fall through ... */
+      /* fall through */
 
     case Attr_Length:
       {
@@ -2393,7 +2393,7 @@ Attribute_to_gnu (Node_Id gnat_node, tre
       /* We treat Model as identical to Machine.  This is true for at least
 	 IEEE and some other nice floating-point systems.  */
 
-      /* ... fall through ... */
+      /* fall through */
 
     case Attr_Machine:
       /* The trick is to force the compiler to store the result in memory so
@@ -2537,7 +2537,7 @@ Case_Statement_to_gnu (Node_Id gnat_node
 		  break;
 		}
 
-	      /* ... fall through ... */
+	      /* fall through */
 
 	    case N_Character_Literal:
 	    case N_Integer_Literal:
@@ -4007,7 +4007,7 @@ node_is_atomic (Node_Id gnat_node)
 	  && Has_Atomic_Components (Entity (Prefix (gnat_node))))
 	return true;
 
-      /* ... fall through ... */
+      /* fall through */
 
     case N_Explicit_Dereference:
       return Is_Atomic (Etype (gnat_node));
@@ -4123,7 +4123,7 @@ atomic_access_required_p (Node_Id gnat_n
       /* Nothing to do if we are the prefix of an attribute, since we do not
 	 want an atomic access for things like 'Size.  */
 
-      /* ... fall through ... */
+      /* fall through */
 
     case N_Reference:
       /* The N_Reference node is like an attribute.  */
@@ -6580,7 +6580,7 @@ gnat_to_gnu (Node_Id gnat_node)
 	  break;
 	}
 
-      /* ... fall through ... */
+      /* fall through */
 
     case N_Op_Eq:
     case N_Op_Ne:
@@ -6747,7 +6747,7 @@ gnat_to_gnu (Node_Id gnat_node)
 	  break;
 	}
 
-      /* ... fall through ... */
+      /* fall through */
 
     case N_Op_Minus:
     case N_Op_Abs:
@@ -8344,7 +8344,7 @@ gnat_gimplify_expr (tree *expr_p, gimple
 	    break;
 	  }
 
-      /* ... fall through ... */
+      /* fall through */
 
     default:
       return GS_UNHANDLED;
@@ -9867,7 +9867,7 @@ set_gnu_expr_location_from_node (tree no
       if (EXPR_P (TREE_OPERAND (node, 1)))
 	set_gnu_expr_location_from_node (TREE_OPERAND (node, 1), gnat_node);
 
-      /* ... fall through ... */
+      /* fall through */
 
     default:
       if (!REFERENCE_CLASS_P (node) && !EXPR_HAS_LOCATION (node))
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -3166,7 +3166,7 @@ create_subprog_decl (tree name, tree asm
 				    NULL_TREE, NULL_TREE),
 			 ATTR_FLAG_TYPE_IN_PLACE);
 
-      /* ... fall through ... */
+      /* fall through */
 
     case is_enabled:
       DECL_DECLARED_INLINE_P (subprog_decl) = 1;
@@ -4271,6 +4271,8 @@ convert (tree type, tree expr)
 	  return expr;
 	}
 
+      /* fall through */
+
     case CONSTRUCTOR:
       /* If we are converting a CONSTRUCTOR to a mere type variant, or to
 	 another padding type around the same type, just make a new one in
@@ -4508,7 +4510,7 @@ convert (tree type, tree expr)
 					  convert (TREE_TYPE (type),
 						   TYPE_MIN_VALUE (type))));
 
-      /* ... fall through ... */
+      /* fall through */
 
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
@@ -4585,7 +4587,7 @@ convert (tree type, tree expr)
 	  return gnat_build_constructor (type, v);
 	}
 
-      /* ... fall through ... */
+      /* fall through */
 
     case ARRAY_TYPE:
       /* In these cases, assume the front-end has validated the conversion.
@@ -4701,7 +4703,7 @@ convert_to_index_type (tree expr)
 	  break;
       }
 
-      /* ... fall through ... */
+      /* fall through */
 
     case NON_LVALUE_EXPR:
       return fold_build1 (code, sizetype,
diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c
--- a/gcc/ada/gcc-interface/utils2.c
+++ b/gcc/ada/gcc-interface/utils2.c
@@ -180,7 +180,7 @@ known_alignment (tree exp)
 	  return known_alignment (t);
       }
 
-      /* ... fall through ... */
+      /* fall through */
 
     default:
       /* For other pointer expressions, we assume that the pointed-to object
@@ -1011,7 +1011,7 @@ build_binary_op (enum tree_code op_code,
       if (!operation_type)
 	operation_type = TREE_TYPE (left_type);
 
-      /* ... fall through ... */
+      /* fall through */
 
     case ARRAY_RANGE_REF:
       /* First look through conversion between type variants.  Note that
@@ -1230,7 +1230,7 @@ build_binary_op (enum tree_code op_code,
 	op_code = MINUS_EXPR;
       modulus = NULL_TREE;
 
-      /* ... fall through ... */
+      /* fall through */
 
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -1244,7 +1244,7 @@ build_binary_op (enum tree_code op_code,
 	  = gnat_type_for_mode (TYPE_MODE (operation_type),
 				TYPE_UNSIGNED (operation_type));
 
-      /* ... fall through ... */
+      /* fall through */
 
     default:
     common:
@@ -1466,7 +1466,7 @@ build_unary_op (enum tree_code op_code, 
 	    return build_unary_op (ADDR_EXPR, result_type,
 				   TREE_OPERAND (operand, 0));
 
-	  /* ... fallthru ... */
+	  /* fallthru */
 
 	case VIEW_CONVERT_EXPR:
 	  /* If this just a variant conversion or if the conversion doesn't
@@ -1487,7 +1487,7 @@ build_unary_op (enum tree_code op_code, 
 	case CONST_DECL:
 	  operand = DECL_CONST_CORRESPONDING_VAR (operand);
 
-	  /* ... fall through ... */
+	  /* fall through */
 
 	default:
 	common:
@@ -1648,7 +1648,7 @@ build_unary_op (enum tree_code op_code, 
 	  }
       }
 
-      /* ... fall through ... */
+      /* fall through */
 
     default:
       gcc_assert (operation_type == base_type);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -17917,6 +17917,7 @@ ix86_print_operand (FILE *file, rtx x, i
 #ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
 	  if (ASSEMBLER_DIALECT == ASM_ATT)
 	    putc ('.', file);
+	  gcc_fallthrough ();
 #endif
 
 	case 'C':
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -3832,6 +3832,7 @@ check_pic (int i)
 		      || (GET_CODE (XEXP (op, 0)) == MINUS
 			  && XEXP (XEXP (op, 0), 0) == sparc_got ()
 			  && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST)));
+      /* fallthrough */
     case 2:
     default:
       return 1;
@@ -8371,6 +8372,7 @@ epilogue_renumber (register rtx *where, 
 	return 1;
       if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
 	*where = gen_rtx_REG (GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
+      /* fallthrough */
     case SCRATCH:
     case CC0:
     case PC:

[-- Attachment #3: Type: text/plain, Size: 143 bytes --]


-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 13:41                     ` Rainer Orth
@ 2016-09-26 13:53                       ` Jakub Jelinek
  2016-09-26 20:36                         ` Rainer Orth
  2016-09-26 13:56                       ` Marek Polacek
                                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-26 13:53 UTC (permalink / raw)
  To: Rainer Orth
  Cc: Marek Polacek, Joseph Myers, Jason Merrill, GCC Patches,
	Arnaud Charlet, Eric Botcazou

On Mon, Sep 26, 2016 at 03:34:40PM +0200, Rainer Orth wrote:
> Ok for mainline if the bootstraps pass (with appropriate changelog
> entries, of course)?

Yes.

> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -17917,6 +17917,7 @@ ix86_print_operand (FILE *file, rtx x, i
>  #ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
>  	  if (ASSEMBLER_DIALECT == ASM_ATT)
>  	    putc ('.', file);
> +	  gcc_fallthrough ();
>  #endif

Where have you been adding the /*FALLTHROUGH*/ ?  Before #endif or after it?

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 13:41                     ` Rainer Orth
  2016-09-26 13:53                       ` Jakub Jelinek
@ 2016-09-26 13:56                       ` Marek Polacek
  2016-09-26 21:01                         ` Rainer Orth
  2016-09-26 15:22                       ` Arnaud Charlet
  2016-09-26 15:55                       ` Jason Merrill
  3 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-26 13:56 UTC (permalink / raw)
  To: Rainer Orth
  Cc: Joseph Myers, Jason Merrill, GCC Patches, Jakub Jelinek,
	Arnaud Charlet, Eric Botcazou

On Mon, Sep 26, 2016 at 03:34:40PM +0200, Rainer Orth wrote:
> Hi Marek,
> 
> > All right.  I'll commit the patch on Monday.
> 
> this patch caused quite some breakage: Ada, Solaris/x86 and SPARC don't
> bootstrap any longer. 
 
Sorry about that.  I had tested Ada + x86_64/ppc64/aarch64, but couldn't
test neither Solaris nor SPARC.

> The following patch allows i386-pc-solaris2.12 and sparc-sun-solaris2.12
> bootstraps continue.
> 
> Strangely, I needed to use gcc_fallthrough () in i386.c; a mere /* FALLTHRU */
> had no effect.
 
Yes, this is expected.  /* FALLTHRU */ comments only work if the next token
is a case label or default label.

> Ok for mainline if the bootstraps pass (with appropriate changelog
> entries, of course)?

LGTM, though I can't approve.

Thanks a lot.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 13:41                     ` Rainer Orth
  2016-09-26 13:53                       ` Jakub Jelinek
  2016-09-26 13:56                       ` Marek Polacek
@ 2016-09-26 15:22                       ` Arnaud Charlet
  2016-09-26 15:55                       ` Jason Merrill
  3 siblings, 0 replies; 81+ messages in thread
From: Arnaud Charlet @ 2016-09-26 15:22 UTC (permalink / raw)
  To: Rainer Orth
  Cc: Marek Polacek, Joseph Myers, Jason Merrill, GCC Patches,
	Jakub Jelinek, Eric Botcazou

> this patch caused quite some breakage: Ada, Solaris/x86 and SPARC don't
> bootstrap any longer. 
> 
> The following patch allows i386-pc-solaris2.12 and
> sparc-sun-solaris2.12
> bootstraps continue.
> 
> Strangely, I needed to use gcc_fallthrough () in i386.c; a mere /* FALLTHRU
> */
> had no effect.
> 
> Ok for mainline if the bootstraps pass (with appropriate changelog
> entries, of course)?

Ada part is OK

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 13:41                     ` Rainer Orth
                                         ` (2 preceding siblings ...)
  2016-09-26 15:22                       ` Arnaud Charlet
@ 2016-09-26 15:55                       ` Jason Merrill
  2016-09-27  7:47                         ` Eric Botcazou
  3 siblings, 1 reply; 81+ messages in thread
From: Jason Merrill @ 2016-09-26 15:55 UTC (permalink / raw)
  To: Rainer Orth
  Cc: Marek Polacek, Joseph Myers, GCC Patches, Jakub Jelinek,
	Arnaud Charlet, Eric Botcazou

It seems unfortunate that the warning doesn't accept /* ... fall
through ... */ as a fallthrough comment.

Jason

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 13:53                       ` Jakub Jelinek
@ 2016-09-26 20:36                         ` Rainer Orth
  2016-10-08 17:04                           ` Eric Botcazou
  0 siblings, 1 reply; 81+ messages in thread
From: Rainer Orth @ 2016-09-26 20:36 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Marek Polacek, Joseph Myers, Jason Merrill, GCC Patches,
	Arnaud Charlet, Eric Botcazou

Hi Jakub,

> On Mon, Sep 26, 2016 at 03:34:40PM +0200, Rainer Orth wrote:
>> Ok for mainline if the bootstraps pass (with appropriate changelog
>> entries, of course)?
>
> Yes.

testing completed successfully, so I've installed the patch with this
ChangeLog entry:

2016-09-26  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	gcc:
	* config/i386/i386.c (ix86_print_operand)
	[HAVE_AS_IX86_CMOV_SUN_SYNTAX]: Add gcc_fallthrough.
	* config/sparc/sparc.c (check_pic): Add fallthrough comment.
	(epilogue_renumber): Likewise.

	gcc/ada:
	* gcc-interface/decl.c: Fix fall through comment formatting.
	* gcc-interface/misc.c: Likewise.
	* gcc-interface/trans.c: Likewise.
	* gcc-interface/utils.c: Likewise.
	* gcc-interface/utils2.c: Likewise.

>> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
>> --- a/gcc/config/i386/i386.c
>> +++ b/gcc/config/i386/i386.c
>> @@ -17917,6 +17917,7 @@ ix86_print_operand (FILE *file, rtx x, i
>>  #ifdef HAVE_AS_IX86_CMOV_SUN_SYNTAX
>>  	  if (ASSEMBLER_DIALECT == ASM_ATT)
>>  	    putc ('.', file);
>> +	  gcc_fallthrough ();
>>  #endif
>
> Where have you been adding the /*FALLTHROUGH*/ ?  Before #endif or after it?

Before: seemed natural to me.

	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 13:56                       ` Marek Polacek
@ 2016-09-26 21:01                         ` Rainer Orth
  0 siblings, 0 replies; 81+ messages in thread
From: Rainer Orth @ 2016-09-26 21:01 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Joseph Myers, Jason Merrill, GCC Patches, Jakub Jelinek,
	Arnaud Charlet, Eric Botcazou

Hi Marek,

> On Mon, Sep 26, 2016 at 03:34:40PM +0200, Rainer Orth wrote:
>> Hi Marek,
>> 
>> > All right.  I'll commit the patch on Monday.
>> 
>> this patch caused quite some breakage: Ada, Solaris/x86 and SPARC don't
>> bootstrap any longer. 
>  
> Sorry about that.  I had tested Ada + x86_64/ppc64/aarch64, but couldn't
> test neither Solaris nor SPARC.

the Solaris/x86 and SPARC issues were minor; I was just astonished to
see that so much didn't work on the Ada side.

>> The following patch allows i386-pc-solaris2.12 and sparc-sun-solaris2.12
>> bootstraps continue.
>> 
>> Strangely, I needed to use gcc_fallthrough () in i386.c; a mere /* FALLTHRU */
>> had no effect.
>  
> Yes, this is expected.  /* FALLTHRU */ comments only work if the next token
> is a case label or default label.

Ok, that explains what's going on.  I guess it would be good to make
this explicit in invoke.texi since someone else is guaranteed to stumble
across this as well.

Thanks.
        Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 15:55                       ` Jason Merrill
@ 2016-09-27  7:47                         ` Eric Botcazou
  2016-09-27  8:01                           ` Eric Botcazou
  2016-09-27  8:32                           ` Implement -Wimplicit-fallthrough (version 9) Jakub Jelinek
  0 siblings, 2 replies; 81+ messages in thread
From: Eric Botcazou @ 2016-09-27  7:47 UTC (permalink / raw)
  To: Jason Merrill
  Cc: gcc-patches, Rainer Orth, Marek Polacek, Joseph Myers,
	Jakub Jelinek, Arnaud Charlet

> It seems unfortunate that the warning doesn't accept /* ... fall
> through ... */ as a fallthrough comment.

Seconded.  The warning should take into account existing practices instead of 
forcing the user to make completely bogus changes to the code (and Ada should 
have been tested before the patch was approved).

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-24 13:32                   ` Marek Polacek
  2016-09-26 13:41                     ` Rainer Orth
@ 2016-09-27  7:55                     ` Gerald Pfeifer
  2016-09-27  9:44                       ` Marek Polacek
  2016-09-27  8:17                     ` Andreas Schwab
  2 siblings, 1 reply; 81+ messages in thread
From: Gerald Pfeifer @ 2016-09-27  7:55 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Joseph Myers, Jason Merrill, GCC Patches, Jakub Jelinek

Hi Marek,

On Sat, 24 Sep 2016, Marek Polacek wrote:
> All right.  I'll commit the patch on Monday.

my thrice a week bootstrap on old (but still "supported") 
i?86-unknown-freebsd9 broke as follows:

  cc1plus: error: unrecognized command line option "-Wno-implicit-fallthrough"
  gmake[3]: *** [Makefile:1102: insn-emit.o] Error 1
  gmake[3]: *** Waiting for unfinished jobs....
  gmake[3]: Leaving directory '/scratch/tmp/gerald/OBJ-0927-0731/gcc'
  gmake[2]: *** [Makefile:4571: all-stage1-gcc] Error 2
  gmake[2]: Leaving directory '/scratch/tmp/gerald/OBJ-0927-0731'
  gmake[1]: *** [Makefile:24240: stage1-bubble] Error 2

(Also filed as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77751 )

Gerald

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  7:47                         ` Eric Botcazou
@ 2016-09-27  8:01                           ` Eric Botcazou
  2016-09-27  8:02                             ` Fix bootstrap failure in combine.c and i386.c due to -Wimplicit-fallthrough Jakub Jelinek
  2016-09-27  8:32                           ` Implement -Wimplicit-fallthrough (version 9) Jakub Jelinek
  1 sibling, 1 reply; 81+ messages in thread
From: Eric Botcazou @ 2016-09-27  8:01 UTC (permalink / raw)
  To: Jason Merrill
  Cc: gcc-patches, Rainer Orth, Marek Polacek, Joseph Myers,
	Jakub Jelinek, Arnaud Charlet

> Seconded.  The warning should take into account existing practices instead
> of forcing the user to make completely bogus changes to the code (and Ada
> should have been tested before the patch was approved).

I have a bootstrap failure on x86-64/Linux:

/home/eric/svn/gcc/gcc/combine.c: In function 'rtx_code 
simplify_comparison(rtx_code, rtx_def**, rtx_def**)':
/home/eric/svn/gcc/gcc/combine.c:11928:11: error: this statement may fall 
through [-Werror=implicit-fallthrough]
      break;
           ^
/home/eric/svn/gcc/gcc/combine.c:11932:2: note: here
  case ZERO_EXTEND:
  ^~~~
/home/eric/svn/gcc/gcc/combine.c:12340:6: error: this statement may fall 
through [-Werror=implicit-fallthrough]
      }
      ^
/home/eric/svn/gcc/gcc/combine.c:12343:2: note: here
  case LSHIFTRT:
  ^~~~

	  /* ... fall through ...  */

	  /* ... fall through ...  */

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Fix bootstrap failure in combine.c and i386.c due to -Wimplicit-fallthrough
  2016-09-27  8:01                           ` Eric Botcazou
@ 2016-09-27  8:02                             ` Jakub Jelinek
  2016-09-27  8:13                               ` Richard Biener
  0 siblings, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27  8:02 UTC (permalink / raw)
  To: Eric Botcazou, Uros Bizjak
  Cc: Jason Merrill, gcc-patches, Rainer Orth, Marek Polacek,
	Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 09:55:24AM +0200, Eric Botcazou wrote:
> > Seconded.  The warning should take into account existing practices instead
> > of forcing the user to make completely bogus changes to the code (and Ada
> > should have been tested before the patch was approved).
> 
> I have a bootstrap failure on x86-64/Linux:
> 
> /home/eric/svn/gcc/gcc/combine.c: In function 'rtx_code 
> simplify_comparison(rtx_code, rtx_def**, rtx_def**)':
> /home/eric/svn/gcc/gcc/combine.c:11928:11: error: this statement may fall 
> through [-Werror=implicit-fallthrough]
>       break;
>            ^
> /home/eric/svn/gcc/gcc/combine.c:11932:2: note: here
>   case ZERO_EXTEND:
>   ^~~~
> /home/eric/svn/gcc/gcc/combine.c:12340:6: error: this statement may fall 
> through [-Werror=implicit-fallthrough]
>       }
>       ^
> /home/eric/svn/gcc/gcc/combine.c:12343:2: note: here
>   case LSHIFTRT:
>   ^~~~
> 
> 	  /* ... fall through ...  */
> 
> 	  /* ... fall through ...  */
> 

Yeah, I ran into this and another issue in i386.c.  Fixed thusly,
bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-09-26  Jakub Jelinek  <jakub@redhat.com>

	* combine.c (simplify_comparison): Add canonical FALLTHROUGH comments.
	* config/i386/i386.c (ix86_dep_by_shift_count_body): Add FALLTHROUGH
	comments.  Remove break after return.
	(ix86_fp_compare_code_to_integer, has_dispatch,
	ix86_simd_clone_usable): Remove break after return.

--- gcc/combine.c.jj	2016-09-19 16:33:57.000000000 +0200
+++ gcc/combine.c	2016-09-26 22:15:39.553198973 +0200
@@ -11923,11 +11923,11 @@ simplify_comparison (enum rtx_code code,
 	     we can treat the SUBREG as if it were a ZERO_EXTEND.  */
 	  if (subreg_lowpart_p (op0)
 	      && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op0))) < mode_width)
-	    /* Fall through */ ;
+	    ;
 	  else
 	    break;
 
-	  /* ... fall through ...  */
+	  /* FALLTHROUGH */
 
 	case ZERO_EXTEND:
 	  mode = GET_MODE (XEXP (op0, 0));
@@ -12339,7 +12339,7 @@ simplify_comparison (enum rtx_code code,
 	      continue;
 	    }
 
-	  /* ... fall through ...  */
+	  /* FALLTHROUGH */
 	case LSHIFTRT:
 	  /* If we have (compare (xshiftrt FOO N) (const_int C)) and
 	     the low order N bits of FOO are known to be zero, we can do this
--- gcc/config/i386/i386.c.jj	2016-09-26 20:22:23.000000000 +0200
+++ gcc/config/i386/i386.c	2016-09-26 23:15:46.988142242 +0200
@@ -21237,9 +21237,9 @@ ix86_dep_by_shift_count_body (const_rtx
 	if (ix86_dep_by_shift_count_body (XVECEXP (set_body, 0, i),
 					  use_body))
 	  return true;
+      /* FALLTHROUGH */
     default:
       return false;
-      break;
     }
 
   /* Retrieve shift count of USE_BODY.  */
@@ -21253,9 +21253,9 @@ ix86_dep_by_shift_count_body (const_rtx
 	if (ix86_dep_by_shift_count_body (set_body,
 					  XVECEXP (use_body, 0, i)))
 	  return true;
+      /* FALLTHROUGH */
     default:
       return false;
-      break;
     }
 
   if (shift_rtx
@@ -22369,19 +22369,14 @@ ix86_fp_compare_code_to_integer (enum rt
     case ORDERED:
     case UNORDERED:
       return code;
-      break;
     case UNEQ:
       return EQ;
-      break;
     case UNLT:
       return LTU;
-      break;
     case UNLE:
       return LEU;
-      break;
     case LTGT:
       return NE;
-      break;
     default:
       return UNKNOWN;
     }
@@ -49500,7 +49495,6 @@ has_dispatch (rtx_insn *insn, int action
 
       case IS_DISPATCH_ON:
 	return true;
-	break;
 
       case IS_CMP:
 	return is_cmp (insn);
@@ -49958,7 +49952,6 @@ ix86_simd_clone_usable (struct cgraph_no
       if (!TARGET_AVX)
 	return -1;
       return TARGET_AVX2 ? 1 : 0;
-      break;
     case 'd':
       if (!TARGET_AVX2)
 	return -1;


	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Fix bootstrap failure in combine.c and i386.c due to -Wimplicit-fallthrough
  2016-09-27  8:02                             ` Fix bootstrap failure in combine.c and i386.c due to -Wimplicit-fallthrough Jakub Jelinek
@ 2016-09-27  8:13                               ` Richard Biener
  2016-09-27  9:41                                 ` Jakub Jelinek
  0 siblings, 1 reply; 81+ messages in thread
From: Richard Biener @ 2016-09-27  8:13 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Eric Botcazou, Uros Bizjak, Jason Merrill, GCC Patches,
	Rainer Orth, Marek Polacek, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 10:01 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Sep 27, 2016 at 09:55:24AM +0200, Eric Botcazou wrote:
>> > Seconded.  The warning should take into account existing practices instead
>> > of forcing the user to make completely bogus changes to the code (and Ada
>> > should have been tested before the patch was approved).
>>
>> I have a bootstrap failure on x86-64/Linux:
>>
>> /home/eric/svn/gcc/gcc/combine.c: In function 'rtx_code
>> simplify_comparison(rtx_code, rtx_def**, rtx_def**)':
>> /home/eric/svn/gcc/gcc/combine.c:11928:11: error: this statement may fall
>> through [-Werror=implicit-fallthrough]
>>       break;
>>            ^
>> /home/eric/svn/gcc/gcc/combine.c:11932:2: note: here
>>   case ZERO_EXTEND:
>>   ^~~~
>> /home/eric/svn/gcc/gcc/combine.c:12340:6: error: this statement may fall
>> through [-Werror=implicit-fallthrough]
>>       }
>>       ^
>> /home/eric/svn/gcc/gcc/combine.c:12343:2: note: here
>>   case LSHIFTRT:
>>   ^~~~
>>
>>         /* ... fall through ...  */
>>
>>         /* ... fall through ...  */
>>
>
> Yeah, I ran into this and another issue in i386.c.  Fixed thusly,
> bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok.

Richard.

> 2016-09-26  Jakub Jelinek  <jakub@redhat.com>
>
>         * combine.c (simplify_comparison): Add canonical FALLTHROUGH comments.
>         * config/i386/i386.c (ix86_dep_by_shift_count_body): Add FALLTHROUGH
>         comments.  Remove break after return.
>         (ix86_fp_compare_code_to_integer, has_dispatch,
>         ix86_simd_clone_usable): Remove break after return.
>
> --- gcc/combine.c.jj    2016-09-19 16:33:57.000000000 +0200
> +++ gcc/combine.c       2016-09-26 22:15:39.553198973 +0200
> @@ -11923,11 +11923,11 @@ simplify_comparison (enum rtx_code code,
>              we can treat the SUBREG as if it were a ZERO_EXTEND.  */
>           if (subreg_lowpart_p (op0)
>               && GET_MODE_PRECISION (GET_MODE (SUBREG_REG (op0))) < mode_width)
> -           /* Fall through */ ;
> +           ;
>           else
>             break;
>
> -         /* ... fall through ...  */
> +         /* FALLTHROUGH */
>
>         case ZERO_EXTEND:
>           mode = GET_MODE (XEXP (op0, 0));
> @@ -12339,7 +12339,7 @@ simplify_comparison (enum rtx_code code,
>               continue;
>             }
>
> -         /* ... fall through ...  */
> +         /* FALLTHROUGH */
>         case LSHIFTRT:
>           /* If we have (compare (xshiftrt FOO N) (const_int C)) and
>              the low order N bits of FOO are known to be zero, we can do this
> --- gcc/config/i386/i386.c.jj   2016-09-26 20:22:23.000000000 +0200
> +++ gcc/config/i386/i386.c      2016-09-26 23:15:46.988142242 +0200
> @@ -21237,9 +21237,9 @@ ix86_dep_by_shift_count_body (const_rtx
>         if (ix86_dep_by_shift_count_body (XVECEXP (set_body, 0, i),
>                                           use_body))
>           return true;
> +      /* FALLTHROUGH */
>      default:
>        return false;
> -      break;
>      }
>
>    /* Retrieve shift count of USE_BODY.  */
> @@ -21253,9 +21253,9 @@ ix86_dep_by_shift_count_body (const_rtx
>         if (ix86_dep_by_shift_count_body (set_body,
>                                           XVECEXP (use_body, 0, i)))
>           return true;
> +      /* FALLTHROUGH */
>      default:
>        return false;
> -      break;
>      }
>
>    if (shift_rtx
> @@ -22369,19 +22369,14 @@ ix86_fp_compare_code_to_integer (enum rt
>      case ORDERED:
>      case UNORDERED:
>        return code;
> -      break;
>      case UNEQ:
>        return EQ;
> -      break;
>      case UNLT:
>        return LTU;
> -      break;
>      case UNLE:
>        return LEU;
> -      break;
>      case LTGT:
>        return NE;
> -      break;
>      default:
>        return UNKNOWN;
>      }
> @@ -49500,7 +49495,6 @@ has_dispatch (rtx_insn *insn, int action
>
>        case IS_DISPATCH_ON:
>         return true;
> -       break;
>
>        case IS_CMP:
>         return is_cmp (insn);
> @@ -49958,7 +49952,6 @@ ix86_simd_clone_usable (struct cgraph_no
>        if (!TARGET_AVX)
>         return -1;
>        return TARGET_AVX2 ? 1 : 0;
> -      break;
>      case 'd':
>        if (!TARGET_AVX2)
>         return -1;
>
>
>         Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-24 13:32                   ` Marek Polacek
  2016-09-26 13:41                     ` Rainer Orth
  2016-09-27  7:55                     ` Gerald Pfeifer
@ 2016-09-27  8:17                     ` Andreas Schwab
  2016-09-27  8:27                       ` Jakub Jelinek
  2016-09-27 10:15                       ` Marek Polacek
  2 siblings, 2 replies; 81+ messages in thread
From: Andreas Schwab @ 2016-09-27  8:17 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Joseph Myers, Jason Merrill, GCC Patches, Jakub Jelinek

This breaks building with gcc-4.3.

g++ -std=gnu++98 -fno-PIE -c  -DUSE_LIBUNWIND_EXCEPTIONS  -g -DIN_GCC     -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wwrite-strings -Wcast-qual -Wno-format -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings  -Wno-implicit-fallthrough -DHAVE_CONFIG_H -I. -I. -I../../gcc -I../../gcc/. -I../../gcc/../include -I../../gcc/../libcpp/include  -I../../gcc/../libdecnumber -I../../gcc/../libdecnumber/dpd -I../libdecnumber -I../../gcc/../libbacktrace   -o insn-emit.o -MT insn-emit.o -MMD -MP -MF ./.deps/insn-emit.TPo insn-emit.c
cc1plus: error: unrecognized command line option "-Wno-implicit-fallthrough"
make[3]: *** [insn-emit.o] Error 1

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  8:17                     ` Andreas Schwab
@ 2016-09-27  8:27                       ` Jakub Jelinek
  2016-09-27  8:46                         ` Richard Biener
  2016-09-27 10:15                       ` Marek Polacek
  1 sibling, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27  8:27 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Marek Polacek, Joseph Myers, Jason Merrill, GCC Patches

On Tue, Sep 27, 2016 at 10:03:10AM +0200, Andreas Schwab wrote:
> This breaks building with gcc-4.3.
> 
> g++ -std=gnu++98 -fno-PIE -c  -DUSE_LIBUNWIND_EXCEPTIONS  -g -DIN_GCC     -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wwrite-strings -Wcast-qual -Wno-format -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings  -Wno-implicit-fallthrough -DHAVE_CONFIG_H -I. -I. -I../../gcc -I../../gcc/. -I../../gcc/../include -I../../gcc/../libcpp/include  -I../../gcc/../libdecnumber -I../../gcc/../libdecnumber/dpd -I../libdecnumber -I../../gcc/../libbacktrace   -o insn-emit.o -MT insn-emit.o -MMD -MP -MF ./.deps/insn-emit.TPo insn-emit.c
> cc1plus: error: unrecognized command line option "-Wno-implicit-fallthrough"
> make[3]: *** [insn-emit.o] Error 1

Guess it must have been some mistake against the policy that unknown -Wno-*
options aren't complained about, unless something else is diagnosed.

Anyway, Marek, can you add configure check for that?

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  7:47                         ` Eric Botcazou
  2016-09-27  8:01                           ` Eric Botcazou
@ 2016-09-27  8:32                           ` Jakub Jelinek
  2016-09-27  9:40                             ` Eric Botcazou
  1 sibling, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27  8:32 UTC (permalink / raw)
  To: Eric Botcazou
  Cc: Jason Merrill, gcc-patches, Rainer Orth, Marek Polacek,
	Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 08:49:00AM +0200, Eric Botcazou wrote:
> > It seems unfortunate that the warning doesn't accept /* ... fall
> > through ... */ as a fallthrough comment.
> 
> Seconded.  The warning should take into account existing practices instead of 
> forcing the user to make completely bogus changes to the code (and Ada should 
> have been tested before the patch was approved).

The intent has been that we catch the most common forms, but still require it not
to be complete free form.  Because, as experience shows, people are
extremely creative in these comments, and it is not very good idea to
support everything.  For ... fall through ... , what is the purpose of those
...s?

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  8:27                       ` Jakub Jelinek
@ 2016-09-27  8:46                         ` Richard Biener
  0 siblings, 0 replies; 81+ messages in thread
From: Richard Biener @ 2016-09-27  8:46 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Andreas Schwab, Marek Polacek, Joseph Myers, Jason Merrill, GCC Patches

On Tue, Sep 27, 2016 at 10:13 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Sep 27, 2016 at 10:03:10AM +0200, Andreas Schwab wrote:
>> This breaks building with gcc-4.3.
>>
>> g++ -std=gnu++98 -fno-PIE -c  -DUSE_LIBUNWIND_EXCEPTIONS  -g -DIN_GCC     -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wwrite-strings -Wcast-qual -Wno-format -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings  -Wno-implicit-fallthrough -DHAVE_CONFIG_H -I. -I. -I../../gcc -I../../gcc/. -I../../gcc/../include -I../../gcc/../libcpp/include  -I../../gcc/../libdecnumber -I../../gcc/../libdecnumber/dpd -I../libdecnumber -I../../gcc/../libbacktrace   -o insn-emit.o -MT insn-emit.o -MMD -MP -MF ./.deps/insn-emit.TPo insn-emit.c
>> cc1plus: error: unrecognized command line option "-Wno-implicit-fallthrough"
>> make[3]: *** [insn-emit.o] Error 1
>
> Guess it must have been some mistake against the policy that unknown -Wno-*
> options aren't complained about, unless something else is diagnosed.
>
> Anyway, Marek, can you add configure check for that?

Existing practice is to instead use -Wno-error rather than warning
flags that were not present in those early GCC versions.

Richard.

>         Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  8:32                           ` Implement -Wimplicit-fallthrough (version 9) Jakub Jelinek
@ 2016-09-27  9:40                             ` Eric Botcazou
  2016-09-27 10:42                               ` Markus Trippelsdorf
  0 siblings, 1 reply; 81+ messages in thread
From: Eric Botcazou @ 2016-09-27  9:40 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: gcc-patches, Jason Merrill, Rainer Orth, Marek Polacek,
	Joseph Myers, Arnaud Charlet

> The intent has been that we catch the most common forms, but still require
> it not to be complete free form.  Because, as experience shows, people are
> extremely creative in these comments, and it is not very good idea to
> support everything.  For ... fall through ... , what is the purpose of
> those ...s?

No idea, but it has been there for a while and seems perfectly reasonable.
IMO any sentence containing "fall" and "through/thru/etc" on the same line 
should be accepted, otherwise it's just misplaced pickiness.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Fix bootstrap failure in combine.c and i386.c due to -Wimplicit-fallthrough
  2016-09-27  8:13                               ` Richard Biener
@ 2016-09-27  9:41                                 ` Jakub Jelinek
  2016-09-27 10:32                                   ` Richard Biener
  0 siblings, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27  9:41 UTC (permalink / raw)
  To: Richard Biener
  Cc: Eric Botcazou, Uros Bizjak, Jason Merrill, GCC Patches,
	Rainer Orth, Marek Polacek, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 10:02:03AM +0200, Richard Biener wrote:
> >         ix86_simd_clone_usable): Remove break after return.

And after scripting this a little bit:
#/bin/awk -f
/^[[:blank:]]+return[[:blank:]]/ { L1=$0; PP=gensub(/^([[:blank:]]+)return.*$/,"\\1","",L1); next; }
/^[[:blank:]]+break/ { if (PP) { PQ=gensub(/^([[:blank:]]+)break.*$/,"\\1","",$0); if (PP == PQ) { print L1; print $0 } PP=""; } next }
{ PP=""; }

I found lots of other spots where we have useless break; right after return
stmt.  IMHO it is just too confusing to keep them around, ok for trunk if
this passes bootstrap/regtest?

2016-09-27  Jakub Jelinek  <jakub@redhat.com>

	* auto-inc-dec.c (try_merge): Remove break after return.
	* cselib.c (autoinc_split): Likewise.
	* explow.c (promote_mode): Likewise.
	* fixed-value.c (fixed_arithmetic): Likewise.
	* hsa.c (hsa_internal_fn::get_arity): Likewise.
	* rtlanal.c (modified_between_p, modified_in_p): Likewise.
	* trans-mem.c (get_attrs_for): Likewise.
	* tree-if-conv.c (if_convertible_stmt_p): Likewise.
	* tree-vrp.c (simplify_stmt_using_ranges): Likewise.
	* config/aarch64/aarch64-builtins.c (aarch64_fold_builtin): Likewise.
	* config/aarch64/aarch64.c (aarch64_get_condition_code_1): Likewise.
	* config/c6x/c6x.c (c6x_get_unit_specifier): Likewise.
	* config/cr16/cr16.c (legitimate_pic_operand_p): Likewise.
	* config/cris/cris.c (cris_op_str): Likewise.
	* config/mn10300/mn10300.c (cc_flags_for_code): Likewise.
	* config/tilepro/tilepro.c (tilepro_emit_setcc_internal_di): Likewise.
c-family/
	* c-ada-spec.c (print_ada_declaration): Remove break after return.
objc/
	* objc-act.c (continue_class): Remove break after return.
	(objc_maybe_printable_name): Likewise.
fortran/
	* dependency.c (gfc_dep_compare_expr): Remove break after return.
	* frontend-passes.c (optimize_op): Likewise.
	* interface.c (gfc_current_interface_head): Likewise.
	* symbol.c (check_conflict): Likewise.
	* trans-intrinsic.c (build_fix_expr): Likewise.
ada/
	* terminals.c (is_gui_app): Remove break after return.

--- gcc/auto-inc-dec.c.jj	2016-01-04 14:55:53.000000000 +0100
+++ gcc/auto-inc-dec.c	2016-09-27 10:29:15.510619645 +0200
@@ -658,25 +658,21 @@ try_merge (void)
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_PRE_INC\n");
       return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg);
-      break;
 
     case SIMPLE_POST_INC:    /* size++  */
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_POST_INC\n");
       return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg);
-      break;
 
     case SIMPLE_PRE_DEC:     /* --size  */
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_PRE_DEC\n");
       return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg);
-      break;
 
     case SIMPLE_POST_DEC:    /* size--  */
       if (dump_file)
 	fprintf (dump_file, "trying SIMPLE_POST_DEC\n");
       return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg);
-      break;
 
     case DISP_PRE:           /* ++con   */
       if (dump_file)
@@ -687,7 +683,6 @@ try_merge (void)
 							       inc_reg,
 							       inc_insn.reg1)),
 			     inc_reg);
-      break;
 
     case DISP_POST:          /* con++   */
       if (dump_file)
@@ -698,7 +693,6 @@ try_merge (void)
 								inc_reg,
 								inc_insn.reg1)),
 			     inc_reg);
-      break;
 
     case REG_PRE:            /* ++reg   */
       if (dump_file)
@@ -709,7 +703,6 @@ try_merge (void)
 							       inc_reg,
 							       inc_insn.reg1)),
 			     inc_reg);
-      break;
 
     case REG_POST:            /* reg++   */
       if (dump_file)
@@ -720,7 +713,6 @@ try_merge (void)
 								inc_reg,
 								inc_insn.reg1)),
 			     inc_reg);
-      break;
     }
 }
 
--- gcc/cselib.c.jj	2016-08-10 00:21:08.000000000 +0200
+++ gcc/cselib.c	2016-09-27 10:29:42.125282563 +0200
@@ -805,7 +805,6 @@ autoinc_split (rtx x, rtx *off, machine_
 
       *off = GEN_INT (-GET_MODE_SIZE (memmode));
       return XEXP (x, 0);
-      break;
 
     case PRE_INC:
       if (memmode == VOIDmode)
--- gcc/explow.c.jj	2016-09-05 19:27:05.000000000 +0200
+++ gcc/explow.c	2016-09-27 10:30:05.435987326 +0200
@@ -802,7 +802,6 @@ promote_mode (const_tree type ATTRIBUTE_
       PROMOTE_MODE (mode, unsignedp, type);
       *punsignedp = unsignedp;
       return mode;
-      break;
 
 #ifdef POINTERS_EXTEND_UNSIGNED
     case REFERENCE_TYPE:
@@ -810,7 +809,6 @@ promote_mode (const_tree type ATTRIBUTE_
       *punsignedp = POINTERS_EXTEND_UNSIGNED;
       return targetm.addr_space.address_mode
 	       (TYPE_ADDR_SPACE (TREE_TYPE (type)));
-      break;
 #endif
 
     default:
--- gcc/fixed-value.c.jj	2016-01-04 14:55:52.000000000 +0100
+++ gcc/fixed-value.c	2016-09-27 10:30:22.692768763 +0200
@@ -730,35 +730,28 @@ fixed_arithmetic (FIXED_VALUE_TYPE *f, i
     {
     case NEGATE_EXPR:
       return do_fixed_neg (f, op0, sat_p);
-      break;
 
     case PLUS_EXPR:
       gcc_assert (op0->mode == op1->mode);
       return do_fixed_add (f, op0, op1, false, sat_p);
-      break;
 
     case MINUS_EXPR:
       gcc_assert (op0->mode == op1->mode);
       return do_fixed_add (f, op0, op1, true, sat_p);
-      break;
 
     case MULT_EXPR:
       gcc_assert (op0->mode == op1->mode);
       return do_fixed_multiply (f, op0, op1, sat_p);
-      break;
 
     case TRUNC_DIV_EXPR:
       gcc_assert (op0->mode == op1->mode);
       return do_fixed_divide (f, op0, op1, sat_p);
-      break;
 
     case LSHIFT_EXPR:
       return do_fixed_shift (f, op0, op1, true, sat_p);
-      break;
 
     case RSHIFT_EXPR:
       return do_fixed_shift (f, op0, op1, false, sat_p);
-      break;
 
     default:
       gcc_unreachable ();
--- gcc/hsa.c.jj	2016-04-01 17:21:31.000000000 +0200
+++ gcc/hsa.c	2016-09-27 10:30:43.226508698 +0200
@@ -947,7 +947,6 @@ hsa_internal_fn::get_arity ()
     case IFN_SCALB:
     case IFN_LDEXP:
       return 2;
-      break;
     case IFN_CLRSB:
     case IFN_CLZ:
     case IFN_CTZ:
--- gcc/rtlanal.c.jj	2016-09-16 22:19:38.000000000 +0200
+++ gcc/rtlanal.c	2016-09-27 10:31:56.008586891 +0200
@@ -1244,7 +1244,6 @@ modified_between_p (const_rtx x, const r
 	if (memory_modified_in_insn_p (x, insn))
 	  return 1;
       return 0;
-      break;
 
     case REG:
       return reg_set_between_p (x, start, end);
@@ -1299,7 +1298,6 @@ modified_in_p (const_rtx x, const_rtx in
       if (memory_modified_in_insn_p (x, insn))
 	return 1;
       return 0;
-      break;
 
     case REG:
       return reg_set_p (x, insn);
--- gcc/trans-mem.c.jj	2016-05-03 14:12:19.000000000 +0200
+++ gcc/trans-mem.c	2016-09-27 10:32:09.775412530 +0200
@@ -165,7 +165,6 @@ get_attrs_for (const_tree x)
     {
     case FUNCTION_DECL:
       return TYPE_ATTRIBUTES (TREE_TYPE (x));
-      break;
 
     default:
       if (TYPE_P (x))
--- gcc/tree-if-conv.c.jj	2016-08-18 12:45:22.000000000 +0200
+++ gcc/tree-if-conv.c	2016-09-27 10:32:23.708236066 +0200
@@ -1050,7 +1050,6 @@ if_convertible_stmt_p (gimple *stmt, vec
 	  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
 	}
       return false;
-      break;
     }
 
   return true;
--- gcc/tree-vrp.c.jj	2016-09-27 09:46:07.000000000 +0200
+++ gcc/tree-vrp.c	2016-09-27 10:32:46.822943312 +0200
@@ -10215,7 +10215,6 @@ simplify_stmt_using_ranges (gimple_stmt_
 	case MIN_EXPR:
 	case MAX_EXPR:
 	  return simplify_min_or_max_using_ranges (stmt);
-	  break;
 
 	default:
 	  break;
--- gcc/config/aarch64/aarch64-builtins.c.jj	2016-09-13 19:06:26.000000000 +0200
+++ gcc/config/aarch64/aarch64-builtins.c	2016-09-27 10:52:44.303729325 +0200
@@ -1460,7 +1460,6 @@ aarch64_fold_builtin (tree fndecl, int n
     {
       BUILTIN_VDQF (UNOP, abs, 2)
 	return fold_build1 (ABS_EXPR, type, args[0]);
-	break;
       VAR1 (UNOP, floatv2si, 2, v2sf)
       VAR1 (UNOP, floatv4si, 2, v4sf)
       VAR1 (UNOP, floatv2di, 2, v2df)
--- gcc/config/aarch64/aarch64.c.jj	2016-09-27 09:46:13.000000000 +0200
+++ gcc/config/aarch64/aarch64.c	2016-09-27 10:52:58.014555073 +0200
@@ -4433,7 +4433,6 @@ aarch64_get_condition_code_1 (enum machi
 
     default:
       return -1;
-      break;
     }
 
   return -1;
--- gcc/config/c6x/c6x.c.jj	2016-09-23 09:32:16.000000000 +0200
+++ gcc/config/c6x/c6x.c	2016-09-27 10:53:18.782291133 +0200
@@ -1987,17 +1987,13 @@ c6x_get_unit_specifier (rtx_insn *insn)
     case UNITS_DLS:
     case UNITS_D_ADDR:
       return 'd';
-      break;
     case UNITS_L:
     case UNITS_LS:
       return 'l';
-      break;
     case UNITS_S:
       return 's';
-      break;
     case UNITS_M:
       return 'm';
-      break;
     default:
       gcc_unreachable ();
     }
--- gcc/config/cr16/cr16.c.jj	2016-09-14 16:01:10.000000000 +0200
+++ gcc/config/cr16/cr16.c	2016-09-27 10:53:43.110981802 +0200
@@ -1120,10 +1120,8 @@ legitimate_pic_operand_p (rtx x)
     {
     case SYMBOL_REF:
       return 0;
-      break;
     case LABEL_REF:
       return 0;
-      break;
     case CONST:
       /* REVISIT: Use something like symbol_referenced_p.  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
@@ -1134,7 +1132,6 @@ legitimate_pic_operand_p (rtx x)
       break;
     case MEM:
       return legitimate_pic_operand_p (XEXP (x, 0));
-      break;
     default:
       break;
     }
--- gcc/config/cris/cris.c.jj	2016-09-23 09:32:16.000000000 +0200
+++ gcc/config/cris/cris.c	2016-09-27 10:54:07.405672880 +0200
@@ -544,11 +544,9 @@ cris_op_str (rtx x)
     {
     case PLUS:
       return "add";
-      break;
 
     case MINUS:
       return "sub";
-      break;
 
     case MULT:
       /* This function is for retrieving a part of an instruction name for
@@ -560,46 +558,36 @@ cris_op_str (rtx x)
 
     case DIV:
       return "div";
-      break;
 
     case AND:
       return "and";
-      break;
 
     case IOR:
       return "or";
-      break;
 
     case XOR:
       return "xor";
-      break;
 
     case NOT:
       return "not";
-      break;
 
     case ASHIFT:
       return "lsl";
-      break;
 
     case LSHIFTRT:
       return "lsr";
-      break;
 
     case ASHIFTRT:
       return "asr";
-      break;
 
     case UMIN:
       /* Used to control the sign/zero-extend character for the 'E' modifier.
 	 BOUND has none.  */
       cris_output_insn_is_bound = 1;
       return "bound";
-      break;
 
     default:
       return "Unknown operator";
-      break;
   }
 }
 
--- gcc/config/mn10300/mn10300.c.jj	2016-09-14 16:01:09.000000000 +0200
+++ gcc/config/mn10300/mn10300.c	2016-09-27 10:54:30.375380805 +0200
@@ -2693,7 +2693,6 @@ cc_flags_for_code (enum rtx_code code)
     case LT:	/* N */
     case GE:	/* ~N */
       return CC_FLAG_N;
-      break;
 
     case GT:    /* ~(Z|(N^V)) */
     case LE:    /* Z|(N^V) */
--- gcc/config/tilepro/tilepro.c.jj	2016-09-14 16:01:09.000000000 +0200
+++ gcc/config/tilepro/tilepro.c	2016-09-27 10:54:52.187103456 +0200
@@ -2137,13 +2137,11 @@ tilepro_emit_setcc_internal_di (rtx res,
       emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
       emit_insn (gen_andsi3 (res, tmp0, tmp1));
       return true;
-      break;
     case NE:
       emit_insn (gen_insn_sne (tmp0, lo_half[0], lo_half[1]));
       emit_insn (gen_insn_sne (tmp1, hi_half[0], hi_half[1]));
       emit_insn (gen_iorsi3 (res, tmp0, tmp1));
       return true;
-      break;
     case LE:
       emit_insn (gen_insn_slte (tmp0, hi_half[0], hi_half[1]));
       emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
--- gcc/c-family/c-ada-spec.c.jj	2016-09-02 18:17:27.000000000 +0200
+++ gcc/c-family/c-ada-spec.c	2016-09-27 10:50:05.265750558 +0200
@@ -2902,7 +2902,6 @@ print_ada_declaration (pretty_printer *b
 	    pp_string (buffer, "--  skipped function type ");
 	    dump_generic_ada_node (buffer, t, type, spc, false, true);
 	    return 1;
-	    break;
 
 	  case ENUMERAL_TYPE:
 	    if ((orig && TYPE_NAME (orig) && orig != TREE_TYPE (t))
--- gcc/objc/objc-act.c.jj	2016-06-07 17:44:04.000000000 +0200
+++ gcc/objc/objc-act.c	2016-09-27 10:52:23.992987457 +0200
@@ -7054,7 +7054,6 @@ continue_class (tree klass)
 #endif /* OBJCPLUS */
 
 	return get_class_ivars (implementation_template, true);
-	break;
       }
     case CLASS_INTERFACE_TYPE:
       {
@@ -7070,7 +7069,6 @@ continue_class (tree klass)
 	pop_lang_context ();
 #endif /* OBJCPLUS */
 	return NULL_TREE;
-	break;
       }
     default:
       return error_mark_node;
@@ -9279,7 +9277,6 @@ objc_maybe_printable_name (tree decl, in
     {
     case FUNCTION_DECL:
       return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)));
-      break;
 
       /* The following happens when we are printing a deprecation
 	 warning for a method.  The warn_deprecation() will end up
@@ -9294,17 +9291,14 @@ objc_maybe_printable_name (tree decl, in
     case INSTANCE_METHOD_DECL:
     case CLASS_METHOD_DECL:
       return IDENTIFIER_POINTER (DECL_NAME (decl));
-      break;
       /* This happens when printing a deprecation warning for a
 	 property.  We may want to consider some sort of pretty
 	 printing (eg, include the class name where it was declared
 	 ?).  */
     case PROPERTY_DECL:
       return IDENTIFIER_POINTER (PROPERTY_NAME (decl));
-      break;
     default:
       return NULL;
-      break;
     }
 }
 
--- gcc/fortran/dependency.c.jj	2016-09-26 12:06:44.000000000 +0200
+++ gcc/fortran/dependency.c	2016-09-27 10:50:34.163383295 +0200
@@ -486,7 +486,6 @@ gfc_dep_compare_expr (gfc_expr *e1, gfc_
 
     case EXPR_FUNCTION:
       return gfc_dep_compare_functions (e1, e2, false);
-      break;
 
     default:
       return -2;
--- gcc/fortran/frontend-passes.c.jj	2016-09-26 12:06:44.000000000 +0200
+++ gcc/fortran/frontend-passes.c	2016-09-27 10:50:48.976195037 +0200
@@ -1491,7 +1491,6 @@ optimize_op (gfc_expr *e)
 
     case INTRINSIC_POWER:
       return optimize_power (e);
-      break;
 
     default:
       break;
--- gcc/fortran/interface.c.jj	2016-09-27 09:46:11.000000000 +0200
+++ gcc/fortran/interface.c	2016-09-27 10:51:11.692906327 +0200
@@ -4306,16 +4306,13 @@ gfc_current_interface_head (void)
     {
       case INTERFACE_INTRINSIC_OP:
 	return current_interface.ns->op[current_interface.op];
-	break;
 
       case INTERFACE_GENERIC:
       case INTERFACE_DTIO:
 	return current_interface.sym->generic;
-	break;
 
       case INTERFACE_USER_OP:
 	return current_interface.uop->op;
-	break;
 
       default:
 	gcc_unreachable ();
--- gcc/fortran/symbol.c.jj	2016-09-26 12:06:44.000000000 +0200
+++ gcc/fortran/symbol.c	2016-09-27 10:51:20.103799432 +0200
@@ -464,7 +464,6 @@ check_conflict (symbol_attribute *attr,
 	    gfc_error ("Namelist group name at %L cannot have the "
 		       "SAVE attribute", where);
 	    return false; 
-	    break;
 	  case FL_PROCEDURE:
 	    /* Conflicts between SAVE and PROCEDURE will be checked at
 	       resolution stage, see "resolve_fl_procedure".  */
--- gcc/fortran/trans-intrinsic.c.jj	2016-09-23 18:55:40.000000000 +0200
+++ gcc/fortran/trans-intrinsic.c	2016-09-27 10:51:32.725639020 +0200
@@ -410,19 +410,15 @@ build_fix_expr (stmtblock_t * pblock, tr
     {
     case RND_FLOOR:
       return build_fixbound_expr (pblock, arg, type, 0);
-      break;
 
     case RND_CEIL:
       return build_fixbound_expr (pblock, arg, type, 1);
-      break;
 
     case RND_ROUND:
       return build_round_expr (arg, type);
-      break;
 
     case RND_TRUNC:
       return fold_build1_loc (input_location, FIX_TRUNC_EXPR, type, arg);
-      break;
 
     default:
       gcc_unreachable ();
--- gcc/ada/terminals.c.jj	2016-02-12 00:50:55.000000000 +0100
+++ gcc/ada/terminals.c	2016-09-27 10:33:42.042243943 +0200
@@ -289,34 +289,27 @@ is_gui_app (char *exe)
     {
     case IMAGE_SUBSYSTEM_UNKNOWN:
         return 1;
-        break;
 
     case IMAGE_SUBSYSTEM_NATIVE:
         return 1;
-        break;
 
     case IMAGE_SUBSYSTEM_WINDOWS_GUI:
         return 1;
-        break;
 
     case IMAGE_SUBSYSTEM_WINDOWS_CUI:
         return 0;
-        break;
 
     case IMAGE_SUBSYSTEM_OS2_CUI:
         return 0;
-        break;
 
     case IMAGE_SUBSYSTEM_POSIX_CUI:
         return 0;
-        break;
 
     default:
         /* Unknown, return GUI app to be preservative: if yes, it will be
            correctly launched, if no, it will be launched, and a console will
            be also displayed, which is not a big deal */
         return 1;
-        break;
     }
 
 }


	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  7:55                     ` Gerald Pfeifer
@ 2016-09-27  9:44                       ` Marek Polacek
  0 siblings, 0 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-27  9:44 UTC (permalink / raw)
  To: Gerald Pfeifer; +Cc: GCC Patches

On Tue, Sep 27, 2016 at 09:50:17AM +0200, Gerald Pfeifer wrote:
> Hi Marek,
> 
> On Sat, 24 Sep 2016, Marek Polacek wrote:
> > All right.  I'll commit the patch on Monday.
> 
> my thrice a week bootstrap on old (but still "supported") 
> i?86-unknown-freebsd9 broke as follows:
> 
>   cc1plus: error: unrecognized command line option "-Wno-implicit-fallthrough"
>   gmake[3]: *** [Makefile:1102: insn-emit.o] Error 1
>   gmake[3]: *** Waiting for unfinished jobs....
>   gmake[3]: Leaving directory '/scratch/tmp/gerald/OBJ-0927-0731/gcc'
>   gmake[2]: *** [Makefile:4571: all-stage1-gcc] Error 2
>   gmake[2]: Leaving directory '/scratch/tmp/gerald/OBJ-0927-0731'
>   gmake[1]: *** [Makefile:24240: stage1-bubble] Error 2
> 
> (Also filed as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77751 )

Sorry about that.  I just sent a fix.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  8:17                     ` Andreas Schwab
  2016-09-27  8:27                       ` Jakub Jelinek
@ 2016-09-27 10:15                       ` Marek Polacek
  2016-09-27 10:39                         ` Kyrill Tkachov
  1 sibling, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 10:15 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Joseph Myers, Jason Merrill, GCC Patches, Jakub Jelinek

On Tue, Sep 27, 2016 at 10:03:10AM +0200, Andreas Schwab wrote:
> This breaks building with gcc-4.3.
> 
> g++ -std=gnu++98 -fno-PIE -c  -DUSE_LIBUNWIND_EXCEPTIONS  -g -DIN_GCC     -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wwrite-strings -Wcast-qual -Wno-format -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings  -Wno-implicit-fallthrough -DHAVE_CONFIG_H -I. -I. -I../../gcc -I../../gcc/. -I../../gcc/../include -I../../gcc/../libcpp/include  -I../../gcc/../libdecnumber -I../../gcc/../libdecnumber/dpd -I../libdecnumber -I../../gcc/../libbacktrace   -o insn-emit.o -MT insn-emit.o -MMD -MP -MF ./.deps/insn-emit.TPo insn-emit.c
> cc1plus: error: unrecognized command line option "-Wno-implicit-fallthrough"
> make[3]: *** [insn-emit.o] Error 1

You're right, sorry.  Should be fixed in a bit.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Fix bootstrap failure in combine.c and i386.c due to -Wimplicit-fallthrough
  2016-09-27  9:41                                 ` Jakub Jelinek
@ 2016-09-27 10:32                                   ` Richard Biener
  0 siblings, 0 replies; 81+ messages in thread
From: Richard Biener @ 2016-09-27 10:32 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Eric Botcazou, Uros Bizjak, Jason Merrill, GCC Patches,
	Rainer Orth, Marek Polacek, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 11:06 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Sep 27, 2016 at 10:02:03AM +0200, Richard Biener wrote:
>> >         ix86_simd_clone_usable): Remove break after return.
>
> And after scripting this a little bit:
> #/bin/awk -f
> /^[[:blank:]]+return[[:blank:]]/ { L1=$0; PP=gensub(/^([[:blank:]]+)return.*$/,"\\1","",L1); next; }
> /^[[:blank:]]+break/ { if (PP) { PQ=gensub(/^([[:blank:]]+)break.*$/,"\\1","",$0); if (PP == PQ) { print L1; print $0 } PP=""; } next }
> { PP=""; }
>
> I found lots of other spots where we have useless break; right after return
> stmt.  IMHO it is just too confusing to keep them around, ok for trunk if
> this passes bootstrap/regtest?

Ok (this counts as obvious changes IMHO).

Richard.

> 2016-09-27  Jakub Jelinek  <jakub@redhat.com>
>
>         * auto-inc-dec.c (try_merge): Remove break after return.
>         * cselib.c (autoinc_split): Likewise.
>         * explow.c (promote_mode): Likewise.
>         * fixed-value.c (fixed_arithmetic): Likewise.
>         * hsa.c (hsa_internal_fn::get_arity): Likewise.
>         * rtlanal.c (modified_between_p, modified_in_p): Likewise.
>         * trans-mem.c (get_attrs_for): Likewise.
>         * tree-if-conv.c (if_convertible_stmt_p): Likewise.
>         * tree-vrp.c (simplify_stmt_using_ranges): Likewise.
>         * config/aarch64/aarch64-builtins.c (aarch64_fold_builtin): Likewise.
>         * config/aarch64/aarch64.c (aarch64_get_condition_code_1): Likewise.
>         * config/c6x/c6x.c (c6x_get_unit_specifier): Likewise.
>         * config/cr16/cr16.c (legitimate_pic_operand_p): Likewise.
>         * config/cris/cris.c (cris_op_str): Likewise.
>         * config/mn10300/mn10300.c (cc_flags_for_code): Likewise.
>         * config/tilepro/tilepro.c (tilepro_emit_setcc_internal_di): Likewise.
> c-family/
>         * c-ada-spec.c (print_ada_declaration): Remove break after return.
> objc/
>         * objc-act.c (continue_class): Remove break after return.
>         (objc_maybe_printable_name): Likewise.
> fortran/
>         * dependency.c (gfc_dep_compare_expr): Remove break after return.
>         * frontend-passes.c (optimize_op): Likewise.
>         * interface.c (gfc_current_interface_head): Likewise.
>         * symbol.c (check_conflict): Likewise.
>         * trans-intrinsic.c (build_fix_expr): Likewise.
> ada/
>         * terminals.c (is_gui_app): Remove break after return.
>
> --- gcc/auto-inc-dec.c.jj       2016-01-04 14:55:53.000000000 +0100
> +++ gcc/auto-inc-dec.c  2016-09-27 10:29:15.510619645 +0200
> @@ -658,25 +658,21 @@ try_merge (void)
>        if (dump_file)
>         fprintf (dump_file, "trying SIMPLE_PRE_INC\n");
>        return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg);
> -      break;
>
>      case SIMPLE_POST_INC:    /* size++  */
>        if (dump_file)
>         fprintf (dump_file, "trying SIMPLE_POST_INC\n");
>        return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg);
> -      break;
>
>      case SIMPLE_PRE_DEC:     /* --size  */
>        if (dump_file)
>         fprintf (dump_file, "trying SIMPLE_PRE_DEC\n");
>        return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg);
> -      break;
>
>      case SIMPLE_POST_DEC:    /* size--  */
>        if (dump_file)
>         fprintf (dump_file, "trying SIMPLE_POST_DEC\n");
>        return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg);
> -      break;
>
>      case DISP_PRE:           /* ++con   */
>        if (dump_file)
> @@ -687,7 +683,6 @@ try_merge (void)
>                                                                inc_reg,
>                                                                inc_insn.reg1)),
>                              inc_reg);
> -      break;
>
>      case DISP_POST:          /* con++   */
>        if (dump_file)
> @@ -698,7 +693,6 @@ try_merge (void)
>                                                                 inc_reg,
>                                                                 inc_insn.reg1)),
>                              inc_reg);
> -      break;
>
>      case REG_PRE:            /* ++reg   */
>        if (dump_file)
> @@ -709,7 +703,6 @@ try_merge (void)
>                                                                inc_reg,
>                                                                inc_insn.reg1)),
>                              inc_reg);
> -      break;
>
>      case REG_POST:            /* reg++   */
>        if (dump_file)
> @@ -720,7 +713,6 @@ try_merge (void)
>                                                                 inc_reg,
>                                                                 inc_insn.reg1)),
>                              inc_reg);
> -      break;
>      }
>  }
>
> --- gcc/cselib.c.jj     2016-08-10 00:21:08.000000000 +0200
> +++ gcc/cselib.c        2016-09-27 10:29:42.125282563 +0200
> @@ -805,7 +805,6 @@ autoinc_split (rtx x, rtx *off, machine_
>
>        *off = GEN_INT (-GET_MODE_SIZE (memmode));
>        return XEXP (x, 0);
> -      break;
>
>      case PRE_INC:
>        if (memmode == VOIDmode)
> --- gcc/explow.c.jj     2016-09-05 19:27:05.000000000 +0200
> +++ gcc/explow.c        2016-09-27 10:30:05.435987326 +0200
> @@ -802,7 +802,6 @@ promote_mode (const_tree type ATTRIBUTE_
>        PROMOTE_MODE (mode, unsignedp, type);
>        *punsignedp = unsignedp;
>        return mode;
> -      break;
>
>  #ifdef POINTERS_EXTEND_UNSIGNED
>      case REFERENCE_TYPE:
> @@ -810,7 +809,6 @@ promote_mode (const_tree type ATTRIBUTE_
>        *punsignedp = POINTERS_EXTEND_UNSIGNED;
>        return targetm.addr_space.address_mode
>                (TYPE_ADDR_SPACE (TREE_TYPE (type)));
> -      break;
>  #endif
>
>      default:
> --- gcc/fixed-value.c.jj        2016-01-04 14:55:52.000000000 +0100
> +++ gcc/fixed-value.c   2016-09-27 10:30:22.692768763 +0200
> @@ -730,35 +730,28 @@ fixed_arithmetic (FIXED_VALUE_TYPE *f, i
>      {
>      case NEGATE_EXPR:
>        return do_fixed_neg (f, op0, sat_p);
> -      break;
>
>      case PLUS_EXPR:
>        gcc_assert (op0->mode == op1->mode);
>        return do_fixed_add (f, op0, op1, false, sat_p);
> -      break;
>
>      case MINUS_EXPR:
>        gcc_assert (op0->mode == op1->mode);
>        return do_fixed_add (f, op0, op1, true, sat_p);
> -      break;
>
>      case MULT_EXPR:
>        gcc_assert (op0->mode == op1->mode);
>        return do_fixed_multiply (f, op0, op1, sat_p);
> -      break;
>
>      case TRUNC_DIV_EXPR:
>        gcc_assert (op0->mode == op1->mode);
>        return do_fixed_divide (f, op0, op1, sat_p);
> -      break;
>
>      case LSHIFT_EXPR:
>        return do_fixed_shift (f, op0, op1, true, sat_p);
> -      break;
>
>      case RSHIFT_EXPR:
>        return do_fixed_shift (f, op0, op1, false, sat_p);
> -      break;
>
>      default:
>        gcc_unreachable ();
> --- gcc/hsa.c.jj        2016-04-01 17:21:31.000000000 +0200
> +++ gcc/hsa.c   2016-09-27 10:30:43.226508698 +0200
> @@ -947,7 +947,6 @@ hsa_internal_fn::get_arity ()
>      case IFN_SCALB:
>      case IFN_LDEXP:
>        return 2;
> -      break;
>      case IFN_CLRSB:
>      case IFN_CLZ:
>      case IFN_CTZ:
> --- gcc/rtlanal.c.jj    2016-09-16 22:19:38.000000000 +0200
> +++ gcc/rtlanal.c       2016-09-27 10:31:56.008586891 +0200
> @@ -1244,7 +1244,6 @@ modified_between_p (const_rtx x, const r
>         if (memory_modified_in_insn_p (x, insn))
>           return 1;
>        return 0;
> -      break;
>
>      case REG:
>        return reg_set_between_p (x, start, end);
> @@ -1299,7 +1298,6 @@ modified_in_p (const_rtx x, const_rtx in
>        if (memory_modified_in_insn_p (x, insn))
>         return 1;
>        return 0;
> -      break;
>
>      case REG:
>        return reg_set_p (x, insn);
> --- gcc/trans-mem.c.jj  2016-05-03 14:12:19.000000000 +0200
> +++ gcc/trans-mem.c     2016-09-27 10:32:09.775412530 +0200
> @@ -165,7 +165,6 @@ get_attrs_for (const_tree x)
>      {
>      case FUNCTION_DECL:
>        return TYPE_ATTRIBUTES (TREE_TYPE (x));
> -      break;
>
>      default:
>        if (TYPE_P (x))
> --- gcc/tree-if-conv.c.jj       2016-08-18 12:45:22.000000000 +0200
> +++ gcc/tree-if-conv.c  2016-09-27 10:32:23.708236066 +0200
> @@ -1050,7 +1050,6 @@ if_convertible_stmt_p (gimple *stmt, vec
>           print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
>         }
>        return false;
> -      break;
>      }
>
>    return true;
> --- gcc/tree-vrp.c.jj   2016-09-27 09:46:07.000000000 +0200
> +++ gcc/tree-vrp.c      2016-09-27 10:32:46.822943312 +0200
> @@ -10215,7 +10215,6 @@ simplify_stmt_using_ranges (gimple_stmt_
>         case MIN_EXPR:
>         case MAX_EXPR:
>           return simplify_min_or_max_using_ranges (stmt);
> -         break;
>
>         default:
>           break;
> --- gcc/config/aarch64/aarch64-builtins.c.jj    2016-09-13 19:06:26.000000000 +0200
> +++ gcc/config/aarch64/aarch64-builtins.c       2016-09-27 10:52:44.303729325 +0200
> @@ -1460,7 +1460,6 @@ aarch64_fold_builtin (tree fndecl, int n
>      {
>        BUILTIN_VDQF (UNOP, abs, 2)
>         return fold_build1 (ABS_EXPR, type, args[0]);
> -       break;
>        VAR1 (UNOP, floatv2si, 2, v2sf)
>        VAR1 (UNOP, floatv4si, 2, v4sf)
>        VAR1 (UNOP, floatv2di, 2, v2df)
> --- gcc/config/aarch64/aarch64.c.jj     2016-09-27 09:46:13.000000000 +0200
> +++ gcc/config/aarch64/aarch64.c        2016-09-27 10:52:58.014555073 +0200
> @@ -4433,7 +4433,6 @@ aarch64_get_condition_code_1 (enum machi
>
>      default:
>        return -1;
> -      break;
>      }
>
>    return -1;
> --- gcc/config/c6x/c6x.c.jj     2016-09-23 09:32:16.000000000 +0200
> +++ gcc/config/c6x/c6x.c        2016-09-27 10:53:18.782291133 +0200
> @@ -1987,17 +1987,13 @@ c6x_get_unit_specifier (rtx_insn *insn)
>      case UNITS_DLS:
>      case UNITS_D_ADDR:
>        return 'd';
> -      break;
>      case UNITS_L:
>      case UNITS_LS:
>        return 'l';
> -      break;
>      case UNITS_S:
>        return 's';
> -      break;
>      case UNITS_M:
>        return 'm';
> -      break;
>      default:
>        gcc_unreachable ();
>      }
> --- gcc/config/cr16/cr16.c.jj   2016-09-14 16:01:10.000000000 +0200
> +++ gcc/config/cr16/cr16.c      2016-09-27 10:53:43.110981802 +0200
> @@ -1120,10 +1120,8 @@ legitimate_pic_operand_p (rtx x)
>      {
>      case SYMBOL_REF:
>        return 0;
> -      break;
>      case LABEL_REF:
>        return 0;
> -      break;
>      case CONST:
>        /* REVISIT: Use something like symbol_referenced_p.  */
>        if (GET_CODE (XEXP (x, 0)) == PLUS
> @@ -1134,7 +1132,6 @@ legitimate_pic_operand_p (rtx x)
>        break;
>      case MEM:
>        return legitimate_pic_operand_p (XEXP (x, 0));
> -      break;
>      default:
>        break;
>      }
> --- gcc/config/cris/cris.c.jj   2016-09-23 09:32:16.000000000 +0200
> +++ gcc/config/cris/cris.c      2016-09-27 10:54:07.405672880 +0200
> @@ -544,11 +544,9 @@ cris_op_str (rtx x)
>      {
>      case PLUS:
>        return "add";
> -      break;
>
>      case MINUS:
>        return "sub";
> -      break;
>
>      case MULT:
>        /* This function is for retrieving a part of an instruction name for
> @@ -560,46 +558,36 @@ cris_op_str (rtx x)
>
>      case DIV:
>        return "div";
> -      break;
>
>      case AND:
>        return "and";
> -      break;
>
>      case IOR:
>        return "or";
> -      break;
>
>      case XOR:
>        return "xor";
> -      break;
>
>      case NOT:
>        return "not";
> -      break;
>
>      case ASHIFT:
>        return "lsl";
> -      break;
>
>      case LSHIFTRT:
>        return "lsr";
> -      break;
>
>      case ASHIFTRT:
>        return "asr";
> -      break;
>
>      case UMIN:
>        /* Used to control the sign/zero-extend character for the 'E' modifier.
>          BOUND has none.  */
>        cris_output_insn_is_bound = 1;
>        return "bound";
> -      break;
>
>      default:
>        return "Unknown operator";
> -      break;
>    }
>  }
>
> --- gcc/config/mn10300/mn10300.c.jj     2016-09-14 16:01:09.000000000 +0200
> +++ gcc/config/mn10300/mn10300.c        2016-09-27 10:54:30.375380805 +0200
> @@ -2693,7 +2693,6 @@ cc_flags_for_code (enum rtx_code code)
>      case LT:   /* N */
>      case GE:   /* ~N */
>        return CC_FLAG_N;
> -      break;
>
>      case GT:    /* ~(Z|(N^V)) */
>      case LE:    /* Z|(N^V) */
> --- gcc/config/tilepro/tilepro.c.jj     2016-09-14 16:01:09.000000000 +0200
> +++ gcc/config/tilepro/tilepro.c        2016-09-27 10:54:52.187103456 +0200
> @@ -2137,13 +2137,11 @@ tilepro_emit_setcc_internal_di (rtx res,
>        emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
>        emit_insn (gen_andsi3 (res, tmp0, tmp1));
>        return true;
> -      break;
>      case NE:
>        emit_insn (gen_insn_sne (tmp0, lo_half[0], lo_half[1]));
>        emit_insn (gen_insn_sne (tmp1, hi_half[0], hi_half[1]));
>        emit_insn (gen_iorsi3 (res, tmp0, tmp1));
>        return true;
> -      break;
>      case LE:
>        emit_insn (gen_insn_slte (tmp0, hi_half[0], hi_half[1]));
>        emit_insn (gen_insn_seq (tmp1, hi_half[0], hi_half[1]));
> --- gcc/c-family/c-ada-spec.c.jj        2016-09-02 18:17:27.000000000 +0200
> +++ gcc/c-family/c-ada-spec.c   2016-09-27 10:50:05.265750558 +0200
> @@ -2902,7 +2902,6 @@ print_ada_declaration (pretty_printer *b
>             pp_string (buffer, "--  skipped function type ");
>             dump_generic_ada_node (buffer, t, type, spc, false, true);
>             return 1;
> -           break;
>
>           case ENUMERAL_TYPE:
>             if ((orig && TYPE_NAME (orig) && orig != TREE_TYPE (t))
> --- gcc/objc/objc-act.c.jj      2016-06-07 17:44:04.000000000 +0200
> +++ gcc/objc/objc-act.c 2016-09-27 10:52:23.992987457 +0200
> @@ -7054,7 +7054,6 @@ continue_class (tree klass)
>  #endif /* OBJCPLUS */
>
>         return get_class_ivars (implementation_template, true);
> -       break;
>        }
>      case CLASS_INTERFACE_TYPE:
>        {
> @@ -7070,7 +7069,6 @@ continue_class (tree klass)
>         pop_lang_context ();
>  #endif /* OBJCPLUS */
>         return NULL_TREE;
> -       break;
>        }
>      default:
>        return error_mark_node;
> @@ -9279,7 +9277,6 @@ objc_maybe_printable_name (tree decl, in
>      {
>      case FUNCTION_DECL:
>        return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)));
> -      break;
>
>        /* The following happens when we are printing a deprecation
>          warning for a method.  The warn_deprecation() will end up
> @@ -9294,17 +9291,14 @@ objc_maybe_printable_name (tree decl, in
>      case INSTANCE_METHOD_DECL:
>      case CLASS_METHOD_DECL:
>        return IDENTIFIER_POINTER (DECL_NAME (decl));
> -      break;
>        /* This happens when printing a deprecation warning for a
>          property.  We may want to consider some sort of pretty
>          printing (eg, include the class name where it was declared
>          ?).  */
>      case PROPERTY_DECL:
>        return IDENTIFIER_POINTER (PROPERTY_NAME (decl));
> -      break;
>      default:
>        return NULL;
> -      break;
>      }
>  }
>
> --- gcc/fortran/dependency.c.jj 2016-09-26 12:06:44.000000000 +0200
> +++ gcc/fortran/dependency.c    2016-09-27 10:50:34.163383295 +0200
> @@ -486,7 +486,6 @@ gfc_dep_compare_expr (gfc_expr *e1, gfc_
>
>      case EXPR_FUNCTION:
>        return gfc_dep_compare_functions (e1, e2, false);
> -      break;
>
>      default:
>        return -2;
> --- gcc/fortran/frontend-passes.c.jj    2016-09-26 12:06:44.000000000 +0200
> +++ gcc/fortran/frontend-passes.c       2016-09-27 10:50:48.976195037 +0200
> @@ -1491,7 +1491,6 @@ optimize_op (gfc_expr *e)
>
>      case INTRINSIC_POWER:
>        return optimize_power (e);
> -      break;
>
>      default:
>        break;
> --- gcc/fortran/interface.c.jj  2016-09-27 09:46:11.000000000 +0200
> +++ gcc/fortran/interface.c     2016-09-27 10:51:11.692906327 +0200
> @@ -4306,16 +4306,13 @@ gfc_current_interface_head (void)
>      {
>        case INTERFACE_INTRINSIC_OP:
>         return current_interface.ns->op[current_interface.op];
> -       break;
>
>        case INTERFACE_GENERIC:
>        case INTERFACE_DTIO:
>         return current_interface.sym->generic;
> -       break;
>
>        case INTERFACE_USER_OP:
>         return current_interface.uop->op;
> -       break;
>
>        default:
>         gcc_unreachable ();
> --- gcc/fortran/symbol.c.jj     2016-09-26 12:06:44.000000000 +0200
> +++ gcc/fortran/symbol.c        2016-09-27 10:51:20.103799432 +0200
> @@ -464,7 +464,6 @@ check_conflict (symbol_attribute *attr,
>             gfc_error ("Namelist group name at %L cannot have the "
>                        "SAVE attribute", where);
>             return false;
> -           break;
>           case FL_PROCEDURE:
>             /* Conflicts between SAVE and PROCEDURE will be checked at
>                resolution stage, see "resolve_fl_procedure".  */
> --- gcc/fortran/trans-intrinsic.c.jj    2016-09-23 18:55:40.000000000 +0200
> +++ gcc/fortran/trans-intrinsic.c       2016-09-27 10:51:32.725639020 +0200
> @@ -410,19 +410,15 @@ build_fix_expr (stmtblock_t * pblock, tr
>      {
>      case RND_FLOOR:
>        return build_fixbound_expr (pblock, arg, type, 0);
> -      break;
>
>      case RND_CEIL:
>        return build_fixbound_expr (pblock, arg, type, 1);
> -      break;
>
>      case RND_ROUND:
>        return build_round_expr (arg, type);
> -      break;
>
>      case RND_TRUNC:
>        return fold_build1_loc (input_location, FIX_TRUNC_EXPR, type, arg);
> -      break;
>
>      default:
>        gcc_unreachable ();
> --- gcc/ada/terminals.c.jj      2016-02-12 00:50:55.000000000 +0100
> +++ gcc/ada/terminals.c 2016-09-27 10:33:42.042243943 +0200
> @@ -289,34 +289,27 @@ is_gui_app (char *exe)
>      {
>      case IMAGE_SUBSYSTEM_UNKNOWN:
>          return 1;
> -        break;
>
>      case IMAGE_SUBSYSTEM_NATIVE:
>          return 1;
> -        break;
>
>      case IMAGE_SUBSYSTEM_WINDOWS_GUI:
>          return 1;
> -        break;
>
>      case IMAGE_SUBSYSTEM_WINDOWS_CUI:
>          return 0;
> -        break;
>
>      case IMAGE_SUBSYSTEM_OS2_CUI:
>          return 0;
> -        break;
>
>      case IMAGE_SUBSYSTEM_POSIX_CUI:
>          return 0;
> -        break;
>
>      default:
>          /* Unknown, return GUI app to be preservative: if yes, it will be
>             correctly launched, if no, it will be launched, and a console will
>             be also displayed, which is not a big deal */
>          return 1;
> -        break;
>      }
>
>  }
>
>
>         Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:15                       ` Marek Polacek
@ 2016-09-27 10:39                         ` Kyrill Tkachov
  2016-09-27 10:48                           ` Jakub Jelinek
  0 siblings, 1 reply; 81+ messages in thread
From: Kyrill Tkachov @ 2016-09-27 10:39 UTC (permalink / raw)
  To: Marek Polacek, Andreas Schwab
  Cc: Joseph Myers, Jason Merrill, GCC Patches, Jakub Jelinek

Hi Marek,

On 27/09/16 10:44, Marek Polacek wrote:
> On Tue, Sep 27, 2016 at 10:03:10AM +0200, Andreas Schwab wrote:
>> This breaks building with gcc-4.3.
>>
>> g++ -std=gnu++98 -fno-PIE -c  -DUSE_LIBUNWIND_EXCEPTIONS  -g -DIN_GCC     -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wwrite-strings -Wcast-qual -Wno-format -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings  -Wno-implicit-fallthrough -DHAVE_CONFIG_H -I. -I. -I../../gcc -I../../gcc/. -I../../gcc/../include -I../../gcc/../libcpp/include  -I../../gcc/../libdecnumber -I../../gcc/../libdecnumber/dpd -I../libdecnumber -I../../gcc/../libbacktrace   -o insn-emit.o -MT insn-emit.o -MMD -MP -MF ./.deps/insn-emit.TPo insn-emit.c
>> cc1plus: error: unrecognized command line option "-Wno-implicit-fallthrough"
>> make[3]: *** [insn-emit.o] Error 1
> You're right, sorry.  Should be fixed in a bit.
>
> 	Marek
>

I'm seeing about 4 triggers of this warning in the arm backend (thus breaking bootstrap),
  mostly due to the fall through comment adding some explanation.
For example:
$SRC/gcc/config/arm/arm-builtins.c: In function 'rtx_def* arm_expand_neon_args(rtx, machine_mode, int, int, int, tree, builtin_arg*)':
$SRC/gcc/config/arm/arm-builtins.c:2155:3: error: this statement may fall through [-Werror=implicit-fallthrough]
    }
    ^
$SRC/gcc/config/arm/arm-builtins.c:2159:6: note: here
       case NEON_ARG_CONSTANT:


where the code is:
2156               /* Fall through - if the lane index isn't a constant then
2157                  the next case will error.  */
2158
2159             case NEON_ARG_CONSTANT:


Is there supposed to be no empty line between the case statement and the comment?
Or is the comment only supposed to contain "Fall through"?

Thanks,
Kyrill

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27  9:40                             ` Eric Botcazou
@ 2016-09-27 10:42                               ` Markus Trippelsdorf
  2016-09-27 10:53                                 ` Jakub Jelinek
  0 siblings, 1 reply; 81+ messages in thread
From: Markus Trippelsdorf @ 2016-09-27 10:42 UTC (permalink / raw)
  To: Eric Botcazou
  Cc: Jakub Jelinek, gcc-patches, Jason Merrill, Rainer Orth,
	Marek Polacek, Joseph Myers, Arnaud Charlet

On 2016.09.27 at 10:46 +0200, Eric Botcazou wrote:
> > The intent has been that we catch the most common forms, but still require
> > it not to be complete free form.  Because, as experience shows, people are
> > extremely creative in these comments, and it is not very good idea to
> > support everything.  For ... fall through ... , what is the purpose of
> > those ...s?
> 
> No idea, but it has been there for a while and seems perfectly reasonable.
> IMO any sentence containing "fall" and "through/thru/etc" on the same line 
> should be accepted, otherwise it's just misplaced pickiness.

+1. Folks will just disable the warning if gcc is not very permissive
when paring existing comments. You cannot expect anyone to change
perfectly fine fall-through comments just to accommodate an arbitrary
gcc style.

-- 
Markus

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:39                         ` Kyrill Tkachov
@ 2016-09-27 10:48                           ` Jakub Jelinek
  2016-09-27 11:15                             ` Kyrill Tkachov
  0 siblings, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 10:48 UTC (permalink / raw)
  To: Kyrill Tkachov
  Cc: Marek Polacek, Andreas Schwab, Joseph Myers, Jason Merrill, GCC Patches

On Tue, Sep 27, 2016 at 11:32:42AM +0100, Kyrill Tkachov wrote:
> where the code is:
> 2156               /* Fall through - if the lane index isn't a constant then
> 2157                  the next case will error.  */
> 2158
> 2159             case NEON_ARG_CONSTANT:
> 
> 
> Is there supposed to be no empty line between the case statement and the comment?
> Or is the comment only supposed to contain "Fall through"?

The last comment before case or default keyword (or user label before
case/default) has to match one of the following regexps:
//-fallthrough$
//@fallthrough@$
//[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*$
//[ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*$
//[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*$
/\*-fallthrough\*/
/\*@fallthrough@\*/
/\*[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*\*/
/\*[ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*\*/
/\*[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*\*/

So, you could e.g. write:
	/* If the lane index isn't a constant, then the next case will error.  */
	/* Fall through.  */
but not what you have, free form is not accepted.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:42                               ` Markus Trippelsdorf
@ 2016-09-27 10:53                                 ` Jakub Jelinek
  2016-09-27 10:56                                   ` Jakub Jelinek
                                                     ` (2 more replies)
  0 siblings, 3 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 10:53 UTC (permalink / raw)
  To: Markus Trippelsdorf
  Cc: Eric Botcazou, gcc-patches, Jason Merrill, Rainer Orth,
	Marek Polacek, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 12:39:41PM +0200, Markus Trippelsdorf wrote:
> On 2016.09.27 at 10:46 +0200, Eric Botcazou wrote:
> > > The intent has been that we catch the most common forms, but still require
> > > it not to be complete free form.  Because, as experience shows, people are
> > > extremely creative in these comments, and it is not very good idea to
> > > support everything.  For ... fall through ... , what is the purpose of
> > > those ...s?
> > 
> > No idea, but it has been there for a while and seems perfectly reasonable.
> > IMO any sentence containing "fall" and "through/thru/etc" on the same line 
> > should be accepted, otherwise it's just misplaced pickiness.
> 
> +1. Folks will just disable the warning if gcc is not very permissive
> when paring existing comments. You cannot expect anyone to change
> perfectly fine fall-through comments just to accommodate an arbitrary
> gcc style.

The accepted style is already very permissive, we don't allow just one
spelling as various lint tools.  I'm afraid looking for various cases of
fall and through/thru possibly separated by anything and surrounded by
anything is IMHO already too much, the compiler shouldn't try to try to
grammar analyze the comments on what they actually talk about and whether it
might be related to the switch fall through or something completely
different.  Users should start using [[fallthrough]]; anyway.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:53                                 ` Jakub Jelinek
@ 2016-09-27 10:56                                   ` Jakub Jelinek
  2016-09-27 10:58                                   ` Marek Polacek
  2016-09-27 11:08                                   ` Eric Botcazou
  2 siblings, 0 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 10:56 UTC (permalink / raw)
  To: Markus Trippelsdorf
  Cc: Eric Botcazou, gcc-patches, Jason Merrill, Rainer Orth,
	Marek Polacek, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 12:47:50PM +0200, Jakub Jelinek wrote:
> On Tue, Sep 27, 2016 at 12:39:41PM +0200, Markus Trippelsdorf wrote:
> > On 2016.09.27 at 10:46 +0200, Eric Botcazou wrote:
> > > > The intent has been that we catch the most common forms, but still require
> > > > it not to be complete free form.  Because, as experience shows, people are
> > > > extremely creative in these comments, and it is not very good idea to
> > > > support everything.  For ... fall through ... , what is the purpose of
> > > > those ...s?
> > > 
> > > No idea, but it has been there for a while and seems perfectly reasonable.
> > > IMO any sentence containing "fall" and "through/thru/etc" on the same line 
> > > should be accepted, otherwise it's just misplaced pickiness.
> > 
> > +1. Folks will just disable the warning if gcc is not very permissive
> > when paring existing comments. You cannot expect anyone to change
> > perfectly fine fall-through comments just to accommodate an arbitrary
> > gcc style.
> 
> The accepted style is already very permissive, we don't allow just one
> spelling as various lint tools.  I'm afraid looking for various cases of
> fall and through/thru possibly separated by anything and surrounded by
> anything is IMHO already too much, the compiler shouldn't try to try to
> grammar analyze the comments on what they actually talk about and whether it
> might be related to the switch fall through or something completely
> different.  Users should start using [[fallthrough]]; anyway.

Oh, forgot, I think allowing
  /* Fallthrough */
  /* arbitrary comment */
  case ...
might be something we could be also supporting, especially because
sometimes users might want to comment on what the following case handle and
fallthrough would be just something in between.  But IMHO forcing users to
use some clear markup style if they don't want to/can't switch to
[[fallthrough]];
__attribute__((fallthrough));
or some macro that does that is a good idea.  That will certainly increase
the chance other compilers could do the same thing, parsing arbitrary stuff
is hard to agree on.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:53                                 ` Jakub Jelinek
  2016-09-27 10:56                                   ` Jakub Jelinek
@ 2016-09-27 10:58                                   ` Marek Polacek
  2016-09-27 11:46                                     ` Jakub Jelinek
  2016-09-27 11:51                                     ` Markus Trippelsdorf
  2016-09-27 11:08                                   ` Eric Botcazou
  2 siblings, 2 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 10:58 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Markus Trippelsdorf, Eric Botcazou, gcc-patches, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 12:47:50PM +0200, Jakub Jelinek wrote:
> On Tue, Sep 27, 2016 at 12:39:41PM +0200, Markus Trippelsdorf wrote:
> > On 2016.09.27 at 10:46 +0200, Eric Botcazou wrote:
> > > > The intent has been that we catch the most common forms, but still require
> > > > it not to be complete free form.  Because, as experience shows, people are
> > > > extremely creative in these comments, and it is not very good idea to
> > > > support everything.  For ... fall through ... , what is the purpose of
> > > > those ...s?
> > > 
> > > No idea, but it has been there for a while and seems perfectly reasonable.
> > > IMO any sentence containing "fall" and "through/thru/etc" on the same line 
> > > should be accepted, otherwise it's just misplaced pickiness.
> > 
> > +1. Folks will just disable the warning if gcc is not very permissive
> > when paring existing comments. You cannot expect anyone to change
> > perfectly fine fall-through comments just to accommodate an arbitrary
> > gcc style.
> 
> The accepted style is already very permissive, we don't allow just one
> spelling as various lint tools.  I'm afraid looking for various cases of
> fall and through/thru possibly separated by anything and surrounded by
> anything is IMHO already too much, the compiler shouldn't try to try to
> grammar analyze the comments on what they actually talk about and whether it
> might be related to the switch fall through or something completely
> different.  Users should start using [[fallthrough]]; anyway.

I'm thinking perhaps we should also accept /* ... fall through ... */
and /* else fall through */, but accepting any sentence containing "fall" and
"through/thru/etc" on the same line would mean that we also accept
/* Don't fall through here.  */ and that is clearly not desirable.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:53                                 ` Jakub Jelinek
  2016-09-27 10:56                                   ` Jakub Jelinek
  2016-09-27 10:58                                   ` Marek Polacek
@ 2016-09-27 11:08                                   ` Eric Botcazou
  2016-09-27 11:12                                     ` Richard Biener
  2 siblings, 1 reply; 81+ messages in thread
From: Eric Botcazou @ 2016-09-27 11:08 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: gcc-patches, Markus Trippelsdorf, Jason Merrill, Rainer Orth,
	Marek Polacek, Joseph Myers, Arnaud Charlet

> The accepted style is already very permissive, we don't allow just one
> spelling as various lint tools.

Well, it cannot even handle the variations of a single codebase, GCC itself, 
so I'm afraid very permissive is not exactly the appropriate wording here.
Anyway, we'll see whether Bugzilla is flooded or not in the upcoming days.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:08                                   ` Eric Botcazou
@ 2016-09-27 11:12                                     ` Richard Biener
  2016-09-27 11:52                                       ` Bernd Schmidt
  0 siblings, 1 reply; 81+ messages in thread
From: Richard Biener @ 2016-09-27 11:12 UTC (permalink / raw)
  To: Eric Botcazou
  Cc: Jakub Jelinek, GCC Patches, Markus Trippelsdorf, Jason Merrill,
	Rainer Orth, Marek Polacek, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 1:06 PM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>> The accepted style is already very permissive, we don't allow just one
>> spelling as various lint tools.
>
> Well, it cannot even handle the variations of a single codebase, GCC itself,
> so I'm afraid very permissive is not exactly the appropriate wording here.
> Anyway, we'll see whether Bugzilla is flooded or not in the upcoming days.

During discussion I already pointed out that people may use non-english
variants as well.  I've seen a lot of french variable/function names in my
academic life for example.

Richard.

> --
> Eric Botcazou

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:48                           ` Jakub Jelinek
@ 2016-09-27 11:15                             ` Kyrill Tkachov
  2016-09-27 12:31                               ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Kyrill Tkachov @ 2016-09-27 11:15 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Marek Polacek, Andreas Schwab, Joseph Myers, Jason Merrill, GCC Patches


On 27/09/16 11:41, Jakub Jelinek wrote:
> On Tue, Sep 27, 2016 at 11:32:42AM +0100, Kyrill Tkachov wrote:
>> where the code is:
>> 2156               /* Fall through - if the lane index isn't a constant then
>> 2157                  the next case will error.  */
>> 2158
>> 2159             case NEON_ARG_CONSTANT:
>>
>>
>> Is there supposed to be no empty line between the case statement and the comment?
>> Or is the comment only supposed to contain "Fall through"?
> The last comment before case or default keyword (or user label before
> case/default) has to match one of the following regexps:
> //-fallthrough$
> //@fallthrough@$
> //[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*$
> //[ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*$
> //[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*$
> /\*-fallthrough\*/
> /\*@fallthrough@\*/
> /\*[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*\*/
> /\*[ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*\*/
> /\*[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*\*/
>
> So, you could e.g. write:
> 	/* If the lane index isn't a constant, then the next case will error.  */
> 	/* Fall through.  */
> but not what you have, free form is not accepted.
Thanks. Given the discussion going on about the acceptable comment formats,
is it preferable to use comments in the gcc codebase at all, or should I
use gcc_fallthrough () (with an explanatory comment if needed)?

Kyrill

> 	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:58                                   ` Marek Polacek
@ 2016-09-27 11:46                                     ` Jakub Jelinek
  2016-09-27 11:53                                       ` Segher Boessenkool
  2016-09-27 17:31                                       ` Marek Polacek
  2016-09-27 11:51                                     ` Markus Trippelsdorf
  1 sibling, 2 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 11:46 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Markus Trippelsdorf, Eric Botcazou, gcc-patches, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 12:56:29PM +0200, Marek Polacek wrote:
> On Tue, Sep 27, 2016 at 12:47:50PM +0200, Jakub Jelinek wrote:
> > On Tue, Sep 27, 2016 at 12:39:41PM +0200, Markus Trippelsdorf wrote:
> > > On 2016.09.27 at 10:46 +0200, Eric Botcazou wrote:
> > > > > The intent has been that we catch the most common forms, but still require
> > > > > it not to be complete free form.  Because, as experience shows, people are
> > > > > extremely creative in these comments, and it is not very good idea to
> > > > > support everything.  For ... fall through ... , what is the purpose of
> > > > > those ...s?
> > > > 
> > > > No idea, but it has been there for a while and seems perfectly reasonable.
> > > > IMO any sentence containing "fall" and "through/thru/etc" on the same line 
> > > > should be accepted, otherwise it's just misplaced pickiness.
> > > 
> > > +1. Folks will just disable the warning if gcc is not very permissive
> > > when paring existing comments. You cannot expect anyone to change
> > > perfectly fine fall-through comments just to accommodate an arbitrary
> > > gcc style.
> > 
> > The accepted style is already very permissive, we don't allow just one
> > spelling as various lint tools.  I'm afraid looking for various cases of
> > fall and through/thru possibly separated by anything and surrounded by
> > anything is IMHO already too much, the compiler shouldn't try to try to
> > grammar analyze the comments on what they actually talk about and whether it
> > might be related to the switch fall through or something completely
> > different.  Users should start using [[fallthrough]]; anyway.
> 
> I'm thinking perhaps we should also accept /* ... fall through ... */
> and /* else fall through */, but accepting any sentence containing "fall" and
> "through/thru/etc" on the same line would mean that we also accept
> /* Don't fall through here.  */ and that is clearly not desirable.

I think it is important to think in terms of what regexps we still want to
match, even when the matching is actually implemented in C, not using
regexps.  And yes, you list one reason why arbitrary text with fall and
through somewhere in it is not a good idea.  Another:
/* XXX Really fallthru?  */
(what we have in pch.c).
So, if you want to allow ... fall through ... and else fall through, and
perhaps // fall through - some explanation
then it might be e.g.
//-fallthrough$
//@fallthrough@$
/\*-fallthrough\*/
/\*@fallthrough@\*/
//[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?$
//[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?$
//[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?$
/\*[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?\*/
/\*[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?\*/
/\*[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?\*/
where . would match even newlines in the last 3,
but $ would always match just end of line?

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 10:58                                   ` Marek Polacek
  2016-09-27 11:46                                     ` Jakub Jelinek
@ 2016-09-27 11:51                                     ` Markus Trippelsdorf
  2016-09-27 12:27                                       ` Marek Polacek
  1 sibling, 1 reply; 81+ messages in thread
From: Markus Trippelsdorf @ 2016-09-27 11:51 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Jakub Jelinek, Eric Botcazou, gcc-patches, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

On 2016.09.27 at 12:56 +0200, Marek Polacek wrote:
> On Tue, Sep 27, 2016 at 12:47:50PM +0200, Jakub Jelinek wrote:
> > On Tue, Sep 27, 2016 at 12:39:41PM +0200, Markus Trippelsdorf wrote:
> > > On 2016.09.27 at 10:46 +0200, Eric Botcazou wrote:
> > > > > The intent has been that we catch the most common forms, but still require
> > > > > it not to be complete free form.  Because, as experience shows, people are
> > > > > extremely creative in these comments, and it is not very good idea to
> > > > > support everything.  For ... fall through ... , what is the purpose of
> > > > > those ...s?
> > > >
> > > > No idea, but it has been there for a while and seems perfectly reasonable.
> > > > IMO any sentence containing "fall" and "through/thru/etc" on the same line
> > > > should be accepted, otherwise it's just misplaced pickiness.
> > >
> > > +1. Folks will just disable the warning if gcc is not very permissive
> > > when paring existing comments. You cannot expect anyone to change
> > > perfectly fine fall-through comments just to accommodate an arbitrary
> > > gcc style.
> >
> > The accepted style is already very permissive, we don't allow just one
> > spelling as various lint tools.  I'm afraid looking for various cases of
> > fall and through/thru possibly separated by anything and surrounded by
> > anything is IMHO already too much, the compiler shouldn't try to try to
> > grammar analyze the comments on what they actually talk about and whether it
> > might be related to the switch fall through or something completely
> > different.  Users should start using [[fallthrough]]; anyway.
>
> I'm thinking perhaps we should also accept /* ... fall through ... */
> and /* else fall through */, but accepting any sentence containing "fall" and
> "through/thru/etc" on the same line would mean that we also accept
> /* Don't fall through here.  */ and that is clearly not desirable.
>

I'm also wondering about the situation where not a single break is used
in all of the cases. It would be best not to warn here.

An example from ffmpeg:

#define LPC1(x) {           \
    int c = coefs[(x)-1];   \
    p0   += MUL(c, s);      \
    s     = smp[i-(x)+1];   \
    p1   += MUL(c, s);      \
}

static av_always_inline void FUNC(lpc_encode_unrolled)(int32_t *res,
                                  const int32_t *smp, int len, int order,
                                  const int32_t *coefs, int shift, int big)
{
    int i;
    for (i = order; i < len; i += 2) {
        int s  = smp[i-order];
        sum_type p0 = 0, p1 = 0;
        if (big) {
            switch (order) {
            case 32: LPC1(32)
            case 31: LPC1(31)
            case 30: LPC1(30)
            case 29: LPC1(29)
            case 28: LPC1(28)
            case 27: LPC1(27)
            case 26: LPC1(26)
            case 25: LPC1(25)
            case 24: LPC1(24)
            case 23: LPC1(23)
            case 22: LPC1(22)
            case 21: LPC1(21)
            case 20: LPC1(20)
            case 19: LPC1(19)
            case 18: LPC1(18)
            case 17: LPC1(17)
            case 16: LPC1(16)
            case 15: LPC1(15)
            case 14: LPC1(14)
            case 13: LPC1(13)
            case 12: LPC1(12)
            case 11: LPC1(11)
            case 10: LPC1(10)
            case  9: LPC1( 9)
                     LPC1( 8)
                     LPC1( 7)
                     LPC1( 6)
                     LPC1( 5)
                     LPC1( 4)
                     LPC1( 3)
                     LPC1( 2)
                     LPC1( 1)
            }
        } else {
            switch (order) {
            case  8: LPC1( 8)
            case  7: LPC1( 7)
            case  6: LPC1( 6)
            case  5: LPC1( 5)
            case  4: LPC1( 4)
            case  3: LPC1( 3)
            case  2: LPC1( 2)
            case  1: LPC1( 1)
            }
        }
        res[i  ] = smp[i  ] - CLIP(p0 >> shift);
        res[i+1] = smp[i+1] - CLIP(p1 >> shift);
    }
}


--
Markus

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:12                                     ` Richard Biener
@ 2016-09-27 11:52                                       ` Bernd Schmidt
  2016-09-27 11:55                                         ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Bernd Schmidt @ 2016-09-27 11:52 UTC (permalink / raw)
  To: Richard Biener, Eric Botcazou
  Cc: Jakub Jelinek, GCC Patches, Markus Trippelsdorf, Jason Merrill,
	Rainer Orth, Marek Polacek, Joseph Myers, Arnaud Charlet

On 09/27/2016 01:09 PM, Richard Biener wrote:
> On Tue, Sep 27, 2016 at 1:06 PM, Eric Botcazou <ebotcazou@adacore.com> wrote:
>>> The accepted style is already very permissive, we don't allow just one
>>> spelling as various lint tools.
>>
>> Well, it cannot even handle the variations of a single codebase, GCC itself,
>> so I'm afraid very permissive is not exactly the appropriate wording here.
>> Anyway, we'll see whether Bugzilla is flooded or not in the upcoming days.
>
> During discussion I already pointed out that people may use non-english
> variants as well.  I've seen a lot of french variable/function names in my
> academic life for example.

Yes, I pointed out the same thing a few weeks ago.

The warning does seem to be useful and discover errors, but I worry 
about the large amount of false positives it produces.


Bernd

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:46                                     ` Jakub Jelinek
@ 2016-09-27 11:53                                       ` Segher Boessenkool
  2016-09-27 12:03                                         ` Jakub Jelinek
  2016-09-27 17:31                                       ` Marek Polacek
  1 sibling, 1 reply; 81+ messages in thread
From: Segher Boessenkool @ 2016-09-27 11:53 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Marek Polacek, Markus Trippelsdorf, Eric Botcazou, gcc-patches,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 01:31:15PM +0200, Jakub Jelinek wrote:
> I think it is important to think in terms of what regexps we still want to
> match, even when the matching is actually implemented in C, not using
> regexps.  And yes, you list one reason why arbitrary text with fall and
> through somewhere in it is not a good idea.  Another:
> /* XXX Really fallthru?  */
> (what we have in pch.c).
> So, if you want to allow ... fall through ... and else fall through, and
> perhaps // fall through - some explanation
> then it might be e.g.
> //-fallthrough$
> //@fallthrough@$
> /\*-fallthrough\*/
> /\*@fallthrough@\*/
> //[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?$
> //[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?$
> //[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?$
> /\*[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?\*/
> /\*[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?\*/
> /\*[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?\*/
> where . would match even newlines in the last 3,
> but $ would always match just end of line?

Any comment with text

^[^_[:alnum:]]*(else )?fall(s | |-)?thr(ough|u)[^_[:alnum:]]*$

perhaps?  Case-insensitive.  Or allow any amount of space, or even any
interpunction.  Just don't allow any alphanumerics except for those
exact words, and there won't be many false hits at all.


Segher

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:52                                       ` Bernd Schmidt
@ 2016-09-27 11:55                                         ` Marek Polacek
  2016-09-27 12:01                                           ` Bernd Schmidt
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 11:55 UTC (permalink / raw)
  To: Bernd Schmidt
  Cc: Richard Biener, Eric Botcazou, Jakub Jelinek, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On Tue, Sep 27, 2016 at 01:47:07PM +0200, Bernd Schmidt wrote:
> On 09/27/2016 01:09 PM, Richard Biener wrote:
> > On Tue, Sep 27, 2016 at 1:06 PM, Eric Botcazou <ebotcazou@adacore.com> wrote:
> > > > The accepted style is already very permissive, we don't allow just one
> > > > spelling as various lint tools.
> > > 
> > > Well, it cannot even handle the variations of a single codebase, GCC itself,
> > > so I'm afraid very permissive is not exactly the appropriate wording here.
> > > Anyway, we'll see whether Bugzilla is flooded or not in the upcoming days.
> > 
> > During discussion I already pointed out that people may use non-english
> > variants as well.  I've seen a lot of french variable/function names in my
> > academic life for example.
> 
> Yes, I pointed out the same thing a few weeks ago.

But the C/C++ keywords are all English, too; lint tools only accept English,
and so it wouldn't seem unreasonable to only accept English keywords in the
comments.  And in any case, I don't see how a compiler can be expected to
be able to parse non-English languages.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:55                                         ` Marek Polacek
@ 2016-09-27 12:01                                           ` Bernd Schmidt
  2016-09-27 12:22                                             ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Bernd Schmidt @ 2016-09-27 12:01 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Richard Biener, Eric Botcazou, Jakub Jelinek, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On 09/27/2016 01:51 PM, Marek Polacek wrote:
> But the C/C++ keywords are all English, too; lint tools only accept English,
> and so it wouldn't seem unreasonable to only accept English keywords in the
> comments.  And in any case, I don't see how a compiler can be expected to
> be able to parse non-English languages.

It isn't. But it can also be reasonably by expected not to warn about 
things that are valid according to the language specification and are 
frequently used.


Bernd

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:53                                       ` Segher Boessenkool
@ 2016-09-27 12:03                                         ` Jakub Jelinek
  2016-09-27 12:57                                           ` Segher Boessenkool
  0 siblings, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 12:03 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: Marek Polacek, Markus Trippelsdorf, Eric Botcazou, gcc-patches,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 06:51:31AM -0500, Segher Boessenkool wrote:
> On Tue, Sep 27, 2016 at 01:31:15PM +0200, Jakub Jelinek wrote:
> > I think it is important to think in terms of what regexps we still want to
> > match, even when the matching is actually implemented in C, not using
> > regexps.  And yes, you list one reason why arbitrary text with fall and
> > through somewhere in it is not a good idea.  Another:
> > /* XXX Really fallthru?  */
> > (what we have in pch.c).
> > So, if you want to allow ... fall through ... and else fall through, and
> > perhaps // fall through - some explanation
> > then it might be e.g.
> > //-fallthrough$
> > //@fallthrough@$
> > /\*-fallthrough\*/
> > /\*@fallthrough@\*/
> > //[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?$
> > //[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?$
> > //[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?$
> > /\*[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?\*/
> > /\*[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?\*/
> > /\*[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?\*/
> > where . would match even newlines in the last 3,
> > but $ would always match just end of line?
> 
> Any comment with text
> 
> ^[^_[:alnum:]]*(else )?fall(s | |-)?thr(ough|u)[^_[:alnum:]]*$
> 
> perhaps?  Case-insensitive.  Or allow any amount of space, or even any
> interpunction.  Just don't allow any alphanumerics except for those
> exact words, and there won't be many false hits at all.

Not sure we want to match FaLlS THrouGH, and [^_[:alnum:]]* isn't without a
problem either, what if there is hebrew, or chinese, etc. text in there?
The matching shouldn't depend on the current locale IMHO, and figuring out what
unicode entry points are letters and which are not really isn't easy without that.

IMO before changing anything further, we want to gather some statistics what
styles are actually used in the wild together with how often they are used,
and then for the more common ones decide what is really supportable.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 12:01                                           ` Bernd Schmidt
@ 2016-09-27 12:22                                             ` Marek Polacek
  2016-09-27 13:50                                               ` Bernd Schmidt
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 12:22 UTC (permalink / raw)
  To: Bernd Schmidt
  Cc: Richard Biener, Eric Botcazou, Jakub Jelinek, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On Tue, Sep 27, 2016 at 01:55:22PM +0200, Bernd Schmidt wrote:
> On 09/27/2016 01:51 PM, Marek Polacek wrote:
> > But the C/C++ keywords are all English, too; lint tools only accept English,
> > and so it wouldn't seem unreasonable to only accept English keywords in the
> > comments.  And in any case, I don't see how a compiler can be expected to
> > be able to parse non-English languages.
> 
> It isn't. But it can also be reasonably by expected not to warn about things
> that are valid according to the language specification and are frequently
> used.

Ok, but note that the warning is in -Wextra, not enabled by default/-Wall.
I'm all for reducing false positives whenever possible and we can improve
out comment-parsing heuristics, but I just can't see us handling anything
other than English.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:51                                     ` Markus Trippelsdorf
@ 2016-09-27 12:27                                       ` Marek Polacek
  2016-09-27 12:32                                         ` Florian Weimer
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 12:27 UTC (permalink / raw)
  To: Markus Trippelsdorf
  Cc: Jakub Jelinek, Eric Botcazou, gcc-patches, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 01:46:08PM +0200, Markus Trippelsdorf wrote:
> I'm also wondering about the situation where not a single break is used
> in all of the cases. It would be best not to warn here.

This is tricky and I'm afraid all I can offer here is to use the diagnostics
pragma to suppress the warning for Duff's device-like constructs.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:15                             ` Kyrill Tkachov
@ 2016-09-27 12:31                               ` Marek Polacek
  0 siblings, 0 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 12:31 UTC (permalink / raw)
  To: Kyrill Tkachov
  Cc: Jakub Jelinek, Andreas Schwab, Joseph Myers, Jason Merrill, GCC Patches

On Tue, Sep 27, 2016 at 12:12:30PM +0100, Kyrill Tkachov wrote:
> 
> On 27/09/16 11:41, Jakub Jelinek wrote:
> > On Tue, Sep 27, 2016 at 11:32:42AM +0100, Kyrill Tkachov wrote:
> > > where the code is:
> > > 2156               /* Fall through - if the lane index isn't a constant then
> > > 2157                  the next case will error.  */
> > > 2158
> > > 2159             case NEON_ARG_CONSTANT:
> > > 
> > > 
> > > Is there supposed to be no empty line between the case statement and the comment?
> > > Or is the comment only supposed to contain "Fall through"?
> > The last comment before case or default keyword (or user label before
> > case/default) has to match one of the following regexps:
> > //-fallthrough$
> > //@fallthrough@$
> > //[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*$
> > //[ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*$
> > //[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*$
> > /\*-fallthrough\*/
> > /\*@fallthrough@\*/
> > /\*[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*\*/
> > /\*[ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*\*/
> > /\*[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*\*/
> > 
> > So, you could e.g. write:
> > 	/* If the lane index isn't a constant, then the next case will error.  */
> > 	/* Fall through.  */
> > but not what you have, free form is not accepted.
> Thanks. Given the discussion going on about the acceptable comment formats,
> is it preferable to use comments in the gcc codebase at all, or should I
> use gcc_fallthrough () (with an explanatory comment if needed)?

It's probably that the comments are preferable, but sometimes you can't use
them (if e.g. something like CASE_CONVERT or another comment or } follows).

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 12:27                                       ` Marek Polacek
@ 2016-09-27 12:32                                         ` Florian Weimer
  2016-09-27 12:42                                           ` Jakub Jelinek
  2016-09-27 12:42                                           ` Marek Polacek
  0 siblings, 2 replies; 81+ messages in thread
From: Florian Weimer @ 2016-09-27 12:32 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Markus Trippelsdorf, Jakub Jelinek, Eric Botcazou, gcc-patches,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

* Marek Polacek:

> On Tue, Sep 27, 2016 at 01:46:08PM +0200, Markus Trippelsdorf wrote:
>> I'm also wondering about the situation where not a single break is used
>> in all of the cases. It would be best not to warn here.
>
> This is tricky and I'm afraid all I can offer here is to use the diagnostics
> pragma to suppress the warning for Duff's device-like constructs.

Would it make sense to apply the fallthrough attribute to the entire
switch statement to address such scenarios?  Currently, that does not
seem supported.

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 12:32                                         ` Florian Weimer
  2016-09-27 12:42                                           ` Jakub Jelinek
@ 2016-09-27 12:42                                           ` Marek Polacek
  1 sibling, 0 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 12:42 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Markus Trippelsdorf, Jakub Jelinek, Eric Botcazou, gcc-patches,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 02:27:12PM +0200, Florian Weimer wrote:
> * Marek Polacek:
> 
> > On Tue, Sep 27, 2016 at 01:46:08PM +0200, Markus Trippelsdorf wrote:
> >> I'm also wondering about the situation where not a single break is used
> >> in all of the cases. It would be best not to warn here.
> >
> > This is tricky and I'm afraid all I can offer here is to use the diagnostics
> > pragma to suppress the warning for Duff's device-like constructs.
> 
> Would it make sense to apply the fallthrough attribute to the entire
> switch statement to address such scenarios?  Currently, that does not
> seem supported.

I've been thinking about this, too.  But I think we'd have to invent
a new attribute, e.g. no_warn_fallthrough or so.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 12:32                                         ` Florian Weimer
@ 2016-09-27 12:42                                           ` Jakub Jelinek
  2016-09-27 12:42                                           ` Marek Polacek
  1 sibling, 0 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 12:42 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Marek Polacek, Markus Trippelsdorf, Eric Botcazou, gcc-patches,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 02:27:12PM +0200, Florian Weimer wrote:
> * Marek Polacek:
> 
> > On Tue, Sep 27, 2016 at 01:46:08PM +0200, Markus Trippelsdorf wrote:
> >> I'm also wondering about the situation where not a single break is used
> >> in all of the cases. It would be best not to warn here.
> >
> > This is tricky and I'm afraid all I can offer here is to use the diagnostics
> > pragma to suppress the warning for Duff's device-like constructs.
> 
> Would it make sense to apply the fallthrough attribute to the entire
> switch statement to address such scenarios?  Currently, that does not
> seem supported.

Where the attribute is allowed or not allowed is currently intentionally
derived from where C++17 allows it.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 12:03                                         ` Jakub Jelinek
@ 2016-09-27 12:57                                           ` Segher Boessenkool
  0 siblings, 0 replies; 81+ messages in thread
From: Segher Boessenkool @ 2016-09-27 12:57 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Marek Polacek, Markus Trippelsdorf, Eric Botcazou, gcc-patches,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 01:58:54PM +0200, Jakub Jelinek wrote:
> > Any comment with text
> > 
> > ^[^_[:alnum:]]*(else )?fall(s | |-)?thr(ough|u)[^_[:alnum:]]*$
> > 
> > perhaps?  Case-insensitive.  Or allow any amount of space, or even any
> > interpunction.  Just don't allow any alphanumerics except for those
> > exact words, and there won't be many false hits at all.
> 
> Not sure we want to match FaLlS THrouGH,

Yes it's silly, but would it ever match the wrong thing?

> and [^_[:alnum:]]* isn't without a
> problem either, what if there is hebrew, or chinese, etc. text in there?

I meant in LANG=C, but it would work otherwise, too.  Nasty, of course.

> The matching shouldn't depend on the current locale IMHO, and figuring out what
> unicode entry points are letters and which are not really isn't easy without that.

Right.

> IMO before changing anything further, we want to gather some statistics what
> styles are actually used in the wild together with how often they are used,
> and then for the more common ones decide what is really supportable.

If you do not allow a lot then there will be many false negatives.


Segher

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 12:22                                             ` Marek Polacek
@ 2016-09-27 13:50                                               ` Bernd Schmidt
  2016-09-27 13:53                                                 ` Jakub Jelinek
  0 siblings, 1 reply; 81+ messages in thread
From: Bernd Schmidt @ 2016-09-27 13:50 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Richard Biener, Eric Botcazou, Jakub Jelinek, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On 09/27/2016 02:01 PM, Marek Polacek wrote:
> On Tue, Sep 27, 2016 at 01:55:22PM +0200, Bernd Schmidt wrote:
>> On 09/27/2016 01:51 PM, Marek Polacek wrote:
>>> But the C/C++ keywords are all English, too; lint tools only accept English,
>>> and so it wouldn't seem unreasonable to only accept English keywords in the
>>> comments.  And in any case, I don't see how a compiler can be expected to
>>> be able to parse non-English languages.
>>
>> It isn't. But it can also be reasonably by expected not to warn about things
>> that are valid according to the language specification and are frequently
>> used.
>
> Ok, but note that the warning is in -Wextra, not enabled by default/-Wall.

I think it's problematic enough that it needs to be removed from -Wextra 
as well. The latest ia64 backend patch shows that clearly IMO.


Bernd

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 13:50                                               ` Bernd Schmidt
@ 2016-09-27 13:53                                                 ` Jakub Jelinek
  2016-09-27 13:56                                                   ` Bernd Schmidt
  2016-09-27 14:00                                                   ` Michael Matz
  0 siblings, 2 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 13:53 UTC (permalink / raw)
  To: Bernd Schmidt
  Cc: Marek Polacek, Richard Biener, Eric Botcazou, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On Tue, Sep 27, 2016 at 03:48:07PM +0200, Bernd Schmidt wrote:
> On 09/27/2016 02:01 PM, Marek Polacek wrote:
> >On Tue, Sep 27, 2016 at 01:55:22PM +0200, Bernd Schmidt wrote:
> >>On 09/27/2016 01:51 PM, Marek Polacek wrote:
> >>>But the C/C++ keywords are all English, too; lint tools only accept English,
> >>>and so it wouldn't seem unreasonable to only accept English keywords in the
> >>>comments.  And in any case, I don't see how a compiler can be expected to
> >>>be able to parse non-English languages.
> >>
> >>It isn't. But it can also be reasonably by expected not to warn about things
> >>that are valid according to the language specification and are frequently
> >>used.
> >
> >Ok, but note that the warning is in -Wextra, not enabled by default/-Wall.
> 
> I think it's problematic enough that it needs to be removed from -Wextra as
> well. The latest ia64 backend patch shows that clearly IMO.

Just compare that to the number of real bugs the warning found in gcc
codebase.  It is really worth it for -Wextra.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 13:53                                                 ` Jakub Jelinek
@ 2016-09-27 13:56                                                   ` Bernd Schmidt
  2016-09-27 14:01                                                     ` Jakub Jelinek
  2016-09-27 14:49                                                     ` Marek Polacek
  2016-09-27 14:00                                                   ` Michael Matz
  1 sibling, 2 replies; 81+ messages in thread
From: Bernd Schmidt @ 2016-09-27 13:56 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Marek Polacek, Richard Biener, Eric Botcazou, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On 09/27/2016 03:49 PM, Jakub Jelinek wrote:
> On Tue, Sep 27, 2016 at 03:48:07PM +0200, Bernd Schmidt wrote:
>> On 09/27/2016 02:01 PM, Marek Polacek wrote:
>>> On Tue, Sep 27, 2016 at 01:55:22PM +0200, Bernd Schmidt wrote:
>>>> On 09/27/2016 01:51 PM, Marek Polacek wrote:
>>>>> But the C/C++ keywords are all English, too; lint tools only accept English,
>>>>> and so it wouldn't seem unreasonable to only accept English keywords in the
>>>>> comments.  And in any case, I don't see how a compiler can be expected to
>>>>> be able to parse non-English languages.
>>>>
>>>> It isn't. But it can also be reasonably by expected not to warn about things
>>>> that are valid according to the language specification and are frequently
>>>> used.
>>>
>>> Ok, but note that the warning is in -Wextra, not enabled by default/-Wall.
>>
>> I think it's problematic enough that it needs to be removed from -Wextra as
>> well. The latest ia64 backend patch shows that clearly IMO.
>
> Just compare that to the number of real bugs the warning found in gcc
> codebase.  It is really worth it for -Wextra.

What's the ratio of comments "fixed" to actual bugs found? IMO this is 
not something we should inflict on users unasked.


Bernd

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 13:53                                                 ` Jakub Jelinek
  2016-09-27 13:56                                                   ` Bernd Schmidt
@ 2016-09-27 14:00                                                   ` Michael Matz
  2016-09-27 14:53                                                     ` Jason Merrill
  2016-09-27 16:47                                                     ` Tom Tromey
  1 sibling, 2 replies; 81+ messages in thread
From: Michael Matz @ 2016-09-27 14:00 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Bernd Schmidt, Marek Polacek, Richard Biener, Eric Botcazou,
	GCC Patches, Markus Trippelsdorf, Jason Merrill, Rainer Orth,
	Joseph Myers, Arnaud Charlet

Hi,

On Tue, 27 Sep 2016, Jakub Jelinek wrote:

> Just compare that to the number of real bugs the warning found in gcc 
> codebase.  It is really worth it for -Wextra.

All those bugs would also have been found as well when it had simply 
accepted
  /fall.*thr/i
anywhere in the preceding comment on one line.  But all the recent 
spelling changes of comments to cater for the strictness exactly shows how 
misguided that is.  The above would accept "Don't fall through" as well.  
I say: so what?


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 13:56                                                   ` Bernd Schmidt
@ 2016-09-27 14:01                                                     ` Jakub Jelinek
  2016-09-27 14:49                                                     ` Marek Polacek
  1 sibling, 0 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 14:01 UTC (permalink / raw)
  To: Bernd Schmidt
  Cc: Marek Polacek, Richard Biener, Eric Botcazou, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On Tue, Sep 27, 2016 at 03:53:25PM +0200, Bernd Schmidt wrote:
> On 09/27/2016 03:49 PM, Jakub Jelinek wrote:
> >On Tue, Sep 27, 2016 at 03:48:07PM +0200, Bernd Schmidt wrote:
> >>On 09/27/2016 02:01 PM, Marek Polacek wrote:
> >>>On Tue, Sep 27, 2016 at 01:55:22PM +0200, Bernd Schmidt wrote:
> >>>>On 09/27/2016 01:51 PM, Marek Polacek wrote:
> >>>>>But the C/C++ keywords are all English, too; lint tools only accept English,
> >>>>>and so it wouldn't seem unreasonable to only accept English keywords in the
> >>>>>comments.  And in any case, I don't see how a compiler can be expected to
> >>>>>be able to parse non-English languages.
> >>>>
> >>>>It isn't. But it can also be reasonably by expected not to warn about things
> >>>>that are valid according to the language specification and are frequently
> >>>>used.
> >>>
> >>>Ok, but note that the warning is in -Wextra, not enabled by default/-Wall.
> >>
> >>I think it's problematic enough that it needs to be removed from -Wextra as
> >>well. The latest ia64 backend patch shows that clearly IMO.
> >
> >Just compare that to the number of real bugs the warning found in gcc
> >codebase.  It is really worth it for -Wextra.
> 
> What's the ratio of comments "fixed" to actual bugs found? IMO this is not
> something we should inflict on users unasked.

We've inflicted on users many other coding style warnings that have a
reasonably high chance to reveal real bugs, e.g. -Wmisleading-indentation which is
even enabled in -Wall, not just -Wextra.  In reality, -Wextra isn't used
that often, and the people that use it will most likely benefit from the
warning IMNSHO.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 13:56                                                   ` Bernd Schmidt
  2016-09-27 14:01                                                     ` Jakub Jelinek
@ 2016-09-27 14:49                                                     ` Marek Polacek
  1 sibling, 0 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 14:49 UTC (permalink / raw)
  To: Bernd Schmidt
  Cc: Jakub Jelinek, Richard Biener, Eric Botcazou, GCC Patches,
	Markus Trippelsdorf, Jason Merrill, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On Tue, Sep 27, 2016 at 03:53:25PM +0200, Bernd Schmidt wrote:
> What's the ratio of comments "fixed" to actual bugs found? IMO this is not
> something we should inflict on users unasked.

One might argue that users actually *asked* for this by turning on -Wextra.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 14:00                                                   ` Michael Matz
@ 2016-09-27 14:53                                                     ` Jason Merrill
  2016-09-27 14:57                                                       ` Marek Polacek
  2016-09-27 16:47                                                     ` Tom Tromey
  1 sibling, 1 reply; 81+ messages in thread
From: Jason Merrill @ 2016-09-27 14:53 UTC (permalink / raw)
  To: Michael Matz
  Cc: Jakub Jelinek, Bernd Schmidt, Marek Polacek, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Rainer Orth,
	Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 9:56 AM, Michael Matz <matz@suse.de> wrote:
> On Tue, 27 Sep 2016, Jakub Jelinek wrote:
>
>> Just compare that to the number of real bugs the warning found in gcc
>> codebase.  It is really worth it for -Wextra.
>
> All those bugs would also have been found as well when it had simply
> accepted
>   /fall.*thr/i
> anywhere in the preceding comment on one line.  But all the recent
> spelling changes of comments to cater for the strictness exactly shows how
> misguided that is.  The above would accept "Don't fall through" as well.
> I say: so what?

I agree.

Jason

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 14:53                                                     ` Jason Merrill
@ 2016-09-27 14:57                                                       ` Marek Polacek
  2016-09-27 15:10                                                         ` Jakub Jelinek
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 14:57 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Michael Matz, Jakub Jelinek, Bernd Schmidt, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Rainer Orth,
	Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 10:48:50AM -0400, Jason Merrill wrote:
> On Tue, Sep 27, 2016 at 9:56 AM, Michael Matz <matz@suse.de> wrote:
> > On Tue, 27 Sep 2016, Jakub Jelinek wrote:
> >
> >> Just compare that to the number of real bugs the warning found in gcc
> >> codebase.  It is really worth it for -Wextra.
> >
> > All those bugs would also have been found as well when it had simply
> > accepted
> >   /fall.*thr/i
> > anywhere in the preceding comment on one line.  But all the recent
> > spelling changes of comments to cater for the strictness exactly shows how
> > misguided that is.  The above would accept "Don't fall through" as well.
> > I say: so what?
> 
> I agree.

All right, I'm not opposed to making the comment parsing more benevolent.
We still should have enough time to fine-tune it.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 14:57                                                       ` Marek Polacek
@ 2016-09-27 15:10                                                         ` Jakub Jelinek
  2016-09-27 15:29                                                           ` Bernd Schmidt
  2016-09-27 15:29                                                           ` Marek Polacek
  0 siblings, 2 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 15:10 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Jason Merrill, Michael Matz, Bernd Schmidt, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Rainer Orth,
	Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 04:54:28PM +0200, Marek Polacek wrote:
> On Tue, Sep 27, 2016 at 10:48:50AM -0400, Jason Merrill wrote:
> > On Tue, Sep 27, 2016 at 9:56 AM, Michael Matz <matz@suse.de> wrote:
> > > On Tue, 27 Sep 2016, Jakub Jelinek wrote:
> > >
> > >> Just compare that to the number of real bugs the warning found in gcc
> > >> codebase.  It is really worth it for -Wextra.
> > >
> > > All those bugs would also have been found as well when it had simply
> > > accepted
> > >   /fall.*thr/i
> > > anywhere in the preceding comment on one line.  But all the recent
> > > spelling changes of comments to cater for the strictness exactly shows how
> > > misguided that is.  The above would accept "Don't fall through" as well.
> > > I say: so what?
> > 
> > I agree.
> 
> All right, I'm not opposed to making the comment parsing more benevolent.
> We still should have enough time to fine-tune it.

Perhaps we want -Wimplicit-fallthrough{,=1,=2,=3,=4}, where
=1 would match indeed /fall.*thr/i (note, it will be really costly in this
case, one will have to parse all comments in detail in the preprocessor,
so I'd be against making it the default), =2 would allow
what we do right now, perhaps with the optional else and dots (perhaps
selected other interpunction chars), =3 would only allow the standardized
lint comments and =4 would not allow any comments, just the attributes?
Then each project can choose what they want.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 15:10                                                         ` Jakub Jelinek
  2016-09-27 15:29                                                           ` Bernd Schmidt
@ 2016-09-27 15:29                                                           ` Marek Polacek
  2016-09-27 16:04                                                             ` Michael Matz
  1 sibling, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 15:29 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jason Merrill, Michael Matz, Bernd Schmidt, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Rainer Orth,
	Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 05:04:23PM +0200, Jakub Jelinek wrote:
> On Tue, Sep 27, 2016 at 04:54:28PM +0200, Marek Polacek wrote:
> > On Tue, Sep 27, 2016 at 10:48:50AM -0400, Jason Merrill wrote:
> > > On Tue, Sep 27, 2016 at 9:56 AM, Michael Matz <matz@suse.de> wrote:
> > > > On Tue, 27 Sep 2016, Jakub Jelinek wrote:
> > > >
> > > >> Just compare that to the number of real bugs the warning found in gcc
> > > >> codebase.  It is really worth it for -Wextra.
> > > >
> > > > All those bugs would also have been found as well when it had simply
> > > > accepted
> > > >   /fall.*thr/i
> > > > anywhere in the preceding comment on one line.  But all the recent
> > > > spelling changes of comments to cater for the strictness exactly shows how
> > > > misguided that is.  The above would accept "Don't fall through" as well.
> > > > I say: so what?
> > > 
> > > I agree.
> > 
> > All right, I'm not opposed to making the comment parsing more benevolent.
> > We still should have enough time to fine-tune it.
> 
> Perhaps we want -Wimplicit-fallthrough{,=1,=2,=3,=4}, where
> =1 would match indeed /fall.*thr/i (note, it will be really costly in this
> case, one will have to parse all comments in detail in the preprocessor,
> so I'd be against making it the default),

Perhaps we could use POSIX regcomp/regex functions; do you (or anyone else)
have an idea how expensive they are and if it's feasible to use them in the
preprocessor?

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 15:10                                                         ` Jakub Jelinek
@ 2016-09-27 15:29                                                           ` Bernd Schmidt
  2016-09-27 15:36                                                             ` Jakub Jelinek
  2016-09-27 15:29                                                           ` Marek Polacek
  1 sibling, 1 reply; 81+ messages in thread
From: Bernd Schmidt @ 2016-09-27 15:29 UTC (permalink / raw)
  To: Jakub Jelinek, Marek Polacek
  Cc: Jason Merrill, Michael Matz, Richard Biener, Eric Botcazou,
	GCC Patches, Markus Trippelsdorf, Rainer Orth, Joseph Myers,
	Arnaud Charlet

On 09/27/2016 05:04 PM, Jakub Jelinek wrote:
>>> On Tue, Sep 27, 2016 at 9:56 AM, Michael Matz <matz@suse.de> wrote:
>>>> All those bugs would also have been found as well when it had simply
>>>> accepted
>>>>   /fall.*thr/i
>>>> anywhere in the preceding comment on one line.  But all the recent
>>>> spelling changes of comments to cater for the strictness exactly shows how
>>>> misguided that is.  The above would accept "Don't fall through" as well.
>>>> I say: so what?

> Perhaps we want -Wimplicit-fallthrough{,=1,=2,=3,=4}, where
> =1 would match indeed /fall.*thr/i (note, it will be really costly in this
> case, one will have to parse all comments in detail in the preprocessor,
> so I'd be against making it the default), =2 would allow
> what we do right now, perhaps with the optional else and dots (perhaps
> selected other interpunction chars), =3 would only allow the standardized
> lint comments and =4 would not allow any comments, just the attributes?
> Then each project can choose what they want.

I feel that's overthinking it. I believe Michael has identified the 
correct way to think about the issue.


Bernd

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 15:29                                                           ` Bernd Schmidt
@ 2016-09-27 15:36                                                             ` Jakub Jelinek
  0 siblings, 0 replies; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-27 15:36 UTC (permalink / raw)
  To: Bernd Schmidt
  Cc: Marek Polacek, Jason Merrill, Michael Matz, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Rainer Orth,
	Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 05:19:10PM +0200, Bernd Schmidt wrote:
> On 09/27/2016 05:04 PM, Jakub Jelinek wrote:
> >>>On Tue, Sep 27, 2016 at 9:56 AM, Michael Matz <matz@suse.de> wrote:
> >>>>All those bugs would also have been found as well when it had simply
> >>>>accepted
> >>>>  /fall.*thr/i
> >>>>anywhere in the preceding comment on one line.  But all the recent
> >>>>spelling changes of comments to cater for the strictness exactly shows how
> >>>>misguided that is.  The above would accept "Don't fall through" as well.
> >>>>I say: so what?
> 
> >Perhaps we want -Wimplicit-fallthrough{,=1,=2,=3,=4}, where
> >=1 would match indeed /fall.*thr/i (note, it will be really costly in this
> >case, one will have to parse all comments in detail in the preprocessor,
> >so I'd be against making it the default), =2 would allow
> >what we do right now, perhaps with the optional else and dots (perhaps
> >selected other interpunction chars), =3 would only allow the standardized
> >lint comments and =4 would not allow any comments, just the attributes?
> >Then each project can choose what they want.
> 
> I feel that's overthinking it. I believe Michael has identified the correct
> way to think about the issue.

See above, it is very expensive at preprocessing time (look at how the
preprocessor optimizes skipping over comments, with that it is all gone),
and not everybody will want /* Don't fall through here.  */ or
/* This is fallible.  Threats are high.  */ (pick any of the hundreds+
english words with fall in them and thousands+ of words with thr in them)
to disable the warning.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 15:29                                                           ` Marek Polacek
@ 2016-09-27 16:04                                                             ` Michael Matz
  0 siblings, 0 replies; 81+ messages in thread
From: Michael Matz @ 2016-09-27 16:04 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Jakub Jelinek, Jason Merrill, Bernd Schmidt, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Rainer Orth,
	Joseph Myers, Arnaud Charlet

Hi,

On Tue, 27 Sep 2016, Marek Polacek wrote:

> > Perhaps we want -Wimplicit-fallthrough{,=1,=2,=3,=4}, where =1 would 
> > match indeed /fall.*thr/i (note, it will be really costly in this 
> > case, one will have to parse all comments in detail in the 
> > preprocessor, so I'd be against making it the default),
> 
> Perhaps we could use POSIX regcomp/regex functions; do you (or anyone 
> else) have an idea how expensive they are and if it's feasible to use 
> them in the preprocessor?

Why?  The regexp I gave was for demonstration.  Matching /fall.*thr/i 
would be done by something similar to:

  a = strcasestr(comment, "fall");
  if (!a) return;                  // no fall
  b = strcasestr(a+4, "thr");
  if (!b) return;                  // no thr
  if (memchr(a+4, '\n', b-a-4)) return; // on different lines
  foundit();

(With appropriate massaging that the comment to parse ends with 0.  
strcasestr would need addition to libiberty for where it's not available 
(or falling back to strstr there); obviously the above can be sped up by 
various tricks for ASCII and UTF-8 because of the relation of upper and 
lower case characters.  During tokenizing the comment (i.e. while 
searching for the end) one could already search for "fall" for instance to 
quickly early-out.)


Ciao,
Michael.

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 14:00                                                   ` Michael Matz
  2016-09-27 14:53                                                     ` Jason Merrill
@ 2016-09-27 16:47                                                     ` Tom Tromey
  2016-09-28 12:46                                                       ` Michael Matz
  1 sibling, 1 reply; 81+ messages in thread
From: Tom Tromey @ 2016-09-27 16:47 UTC (permalink / raw)
  To: Michael Matz
  Cc: Jakub Jelinek, Bernd Schmidt, Marek Polacek, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

>>>>> "Michael" == Michael Matz <matz@suse.de> writes:

Michael> All those bugs would also have been found as well when it had simply 
Michael> accepted
Michael>   /fall.*thr/i
Michael> anywhere in the preceding comment on one line.  But all the recent 
Michael> spelling changes of comments to cater for the strictness exactly shows how 
Michael> misguided that is.  The above would accept "Don't fall through" as well.  
Michael> I say: so what?

The point of the warning is to make code more robust.  But accepting any
comment like "Don't fall through" is not more robust, but rather an
error waiting to happen; as IIUC the user has no way to detect this
case.

I think it's better for the comment-scanning feature to be very picky
(or even just not exist at all) -- that way you know exactly what you
are getting.  Lint was traditionally picky IIRC.  And, this is a warning
that isn't default and can also be disabled, so it's not as if users
have no recourse.

Tom

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 11:46                                     ` Jakub Jelinek
  2016-09-27 11:53                                       ` Segher Boessenkool
@ 2016-09-27 17:31                                       ` Marek Polacek
  1 sibling, 0 replies; 81+ messages in thread
From: Marek Polacek @ 2016-09-27 17:31 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Markus Trippelsdorf, Eric Botcazou, gcc-patches, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

On Tue, Sep 27, 2016 at 01:31:15PM +0200, Jakub Jelinek wrote:
> On Tue, Sep 27, 2016 at 12:56:29PM +0200, Marek Polacek wrote:
> > On Tue, Sep 27, 2016 at 12:47:50PM +0200, Jakub Jelinek wrote:
> > > On Tue, Sep 27, 2016 at 12:39:41PM +0200, Markus Trippelsdorf wrote:
> > > > On 2016.09.27 at 10:46 +0200, Eric Botcazou wrote:
> > > > > > The intent has been that we catch the most common forms, but still require
> > > > > > it not to be complete free form.  Because, as experience shows, people are
> > > > > > extremely creative in these comments, and it is not very good idea to
> > > > > > support everything.  For ... fall through ... , what is the purpose of
> > > > > > those ...s?
> > > > > 
> > > > > No idea, but it has been there for a while and seems perfectly reasonable.
> > > > > IMO any sentence containing "fall" and "through/thru/etc" on the same line 
> > > > > should be accepted, otherwise it's just misplaced pickiness.
> > > > 
> > > > +1. Folks will just disable the warning if gcc is not very permissive
> > > > when paring existing comments. You cannot expect anyone to change
> > > > perfectly fine fall-through comments just to accommodate an arbitrary
> > > > gcc style.
> > > 
> > > The accepted style is already very permissive, we don't allow just one
> > > spelling as various lint tools.  I'm afraid looking for various cases of
> > > fall and through/thru possibly separated by anything and surrounded by
> > > anything is IMHO already too much, the compiler shouldn't try to try to
> > > grammar analyze the comments on what they actually talk about and whether it
> > > might be related to the switch fall through or something completely
> > > different.  Users should start using [[fallthrough]]; anyway.
> > 
> > I'm thinking perhaps we should also accept /* ... fall through ... */
> > and /* else fall through */, but accepting any sentence containing "fall" and
> > "through/thru/etc" on the same line would mean that we also accept
> > /* Don't fall through here.  */ and that is clearly not desirable.
> 
> I think it is important to think in terms of what regexps we still want to
> match, even when the matching is actually implemented in C, not using
> regexps.  And yes, you list one reason why arbitrary text with fall and
> through somewhere in it is not a good idea.  Another:
> /* XXX Really fallthru?  */
> (what we have in pch.c).
> So, if you want to allow ... fall through ... and else fall through, and
> perhaps // fall through - some explanation
> then it might be e.g.
> //-fallthrough$
> //@fallthrough@$
> /\*-fallthrough\*/
> /\*@fallthrough@\*/
> //[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?$
> //[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?$
> //[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?$
> /\*[ \t.]*(ELSE )?FALL(S | |-)?THR(OUGH|U)[ \t.]*(-.*)?\*/
> /\*[ \t.]*(Else )?Fall(s | |-)?[Tt]hr(ough|u)[ \t.]*(-.*)?\*/
> /\*[ \t.]*(else )?fall(s | |-)?thr(ough|u)[ \t.]*(-.*)?\*/
> where . would match even newlines in the last 3,
> but $ would always match just end of line?

This looks like a step in the right direction.  Apparently, it's hard
to come up with something that will make everyone happy; this might be
partly because GCC is probably the only compiler that attempts to
parse comments like this.  While clang has the implicit fallthrough
warning, they aren't even trying to parse the comments.

Jakub, do you want me to look into this (make GCC accept more), or do
you want to adjust that by yourself?

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-27 16:47                                                     ` Tom Tromey
@ 2016-09-28 12:46                                                       ` Michael Matz
  2016-09-28 15:31                                                         ` Tom Tromey
  2016-09-28 19:28                                                         ` Bernd Schmidt
  0 siblings, 2 replies; 81+ messages in thread
From: Michael Matz @ 2016-09-28 12:46 UTC (permalink / raw)
  To: Tom Tromey
  Cc: Jakub Jelinek, Bernd Schmidt, Marek Polacek, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

Hi,

On Tue, 27 Sep 2016, Tom Tromey wrote:

> The point of the warning is to make code more robust.  But accepting any 
> comment like "Don't fall through" is not more robust, but rather an 
> error waiting to happen; as IIUC the user has no way to detect this 
> case.
> 
> I think it's better for the comment-scanning feature to be very picky 
> (or even just not exist at all) -- that way you know exactly what you 
> are getting.  Lint was traditionally picky IIRC.  And, this is a warning 
> that isn't default and can also be disabled, so it's not as if users 
> have no recourse.

Not accepting
  /* And here we intentionally fall through because ... */
and forcing users to replace this by:
  /* fallthrough */
is not robust either.  It's actually actively lowering robustness of code, 
it creates work for programmers that will be regarded as pointless (and 
rightly so) and will merely lead to everybody disabling the warning (see 
our generated files) at which point we could just as well not have 
implemented it (which would be a shame because I think it's genuinely 
useful).

The point of warnings is to make code robust under the condition of not 
being a pain by giving zillions of false positives.  In this specific case 
the chance of giving false positives by being picky in how to disable the 
warning is very high.  On the other hand the chance of unintentionally 
disabling the warning by a negative comment like "Don't fall through here" 
is low, because presumably the one adding that comment (and hence thinking 
about that part of the code) also in fact put in the "break;" afterwards.

The argument with lint being picky would apply only if GCC would have 
added this warning maybe 20 years ago, not now where nearly nobody even 
knows what lint is, which lead to a large existing code base not having 
comments that would be accepted by lint but comments that do specify the 
intent of falling through.


Ciao,
Michael.
P.S.: Initially I even wanted to argue that the mere existence of _any_ 
comment before a case label would disable the warning.  I don't have the 
numbers but I bet even that version would have found the very same bugs 
that the picky version has.

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-28 12:46                                                       ` Michael Matz
@ 2016-09-28 15:31                                                         ` Tom Tromey
  2016-09-28 19:13                                                           ` Jakub Jelinek
  2016-09-28 19:28                                                         ` Bernd Schmidt
  1 sibling, 1 reply; 81+ messages in thread
From: Tom Tromey @ 2016-09-28 15:31 UTC (permalink / raw)
  To: Michael Matz
  Cc: Tom Tromey, Jakub Jelinek, Bernd Schmidt, Marek Polacek,
	Richard Biener, Eric Botcazou, GCC Patches, Markus Trippelsdorf,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

>>>>> "Michael" == Michael Matz <matz@suse.de> writes:

Michael> Not accepting
Michael>   /* And here we intentionally fall through because ... */
Michael> and forcing users to replace this by:
Michael>   /* fallthrough */
Michael> is not robust either.  It's actually actively lowering robustness of code, 
Michael> it creates work for programmers that will be regarded as pointless (and 
Michael> rightly so) and will merely lead to everybody disabling the warning (see 
Michael> our generated files)

We can't control what programmers might do.  My point is that accepting
too much is actively bad -- it hides errors.  If this somehow makes some
programmer fall down a slippery slope, well, that's their error, not
gcc's.

TBH I think it would be better not to parse comments at all.  Heuristics
are generally bad and this case and ensuing discussion is a great
demonstration of that.

The other day I built gdb with -Wimplicit-fallthrough.  I was surprised
to find that gcc rejected this:

	default:
	  {
	    complaint (&symfile_complaints,
		       _("Storage class %d not recognized during scan"),
		       sclass);
	  }
	  /* FALLTHROUGH */

	  /* C_FCN is .bf and .ef symbols.  I think it is sufficient
	     to handle only the C_FUN and C_EXT.  */
	case C_FCN:

Presumably without the comment heuristic, this would be accepted.

Michael> The point of warnings is to make code robust under the condition of not 
Michael> being a pain by giving zillions of false positives.

My experience so far is that it's not so bad.  gdb actually had comments
in most spots, they just required a quick pass to clean them up:

    https://sourceware.org/ml/gdb-patches/2016-09/msg00375.html

And, code bases in more dire straights can just disable the warning after all.

Tom

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-28 15:31                                                         ` Tom Tromey
@ 2016-09-28 19:13                                                           ` Jakub Jelinek
  2016-09-29  2:40                                                             ` Tom Tromey
  0 siblings, 1 reply; 81+ messages in thread
From: Jakub Jelinek @ 2016-09-28 19:13 UTC (permalink / raw)
  To: Tom Tromey
  Cc: Michael Matz, Bernd Schmidt, Marek Polacek, Richard Biener,
	Eric Botcazou, GCC Patches, Markus Trippelsdorf, Jason Merrill,
	Rainer Orth, Joseph Myers, Arnaud Charlet

On Wed, Sep 28, 2016 at 09:29:01AM -0600, Tom Tromey wrote:
> >>>>> "Michael" == Michael Matz <matz@suse.de> writes:
> 
> Michael> Not accepting
> Michael>   /* And here we intentionally fall through because ... */
> Michael> and forcing users to replace this by:
> Michael>   /* fallthrough */
> Michael> is not robust either.  It's actually actively lowering robustness of code, 
> Michael> it creates work for programmers that will be regarded as pointless (and 
> Michael> rightly so) and will merely lead to everybody disabling the warning (see 
> Michael> our generated files)
> 
> We can't control what programmers might do.  My point is that accepting
> too much is actively bad -- it hides errors.  If this somehow makes some
> programmer fall down a slippery slope, well, that's their error, not
> gcc's.
> 
> TBH I think it would be better not to parse comments at all.  Heuristics
> are generally bad and this case and ensuing discussion is a great
> demonstration of that.
> 
> The other day I built gdb with -Wimplicit-fallthrough.  I was surprised
> to find that gcc rejected this:
> 
> 	default:
> 	  {
> 	    complaint (&symfile_complaints,
> 		       _("Storage class %d not recognized during scan"),
> 		       sclass);
> 	  }
> 	  /* FALLTHROUGH */
> 
> 	  /* C_FCN is .bf and .ef symbols.  I think it is sufficient
> 	     to handle only the C_FUN and C_EXT.  */
> 	case C_FCN:
> 
> Presumably without the comment heuristic, this would be accepted.

Is complaint a noreturn call?  If not, then it would certainly warn, unless
there is [[fallthrough]]; or __attribute__((fallthrough)); etc. (or the
comment).  For the comment, /* FALLTHROUGH */ is the recognized spelling of
the comment, but right now we only look for such comments immediately before
a case/default keyword or user label; if there is another comment in
between, it is ignored.  This is something we are considering to change,
exactly because often the /* FALLTHRU */ comment appears after some case and
then there is unrelated comment before the next case about what that case
handles.

	Jakub

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-28 12:46                                                       ` Michael Matz
  2016-09-28 15:31                                                         ` Tom Tromey
@ 2016-09-28 19:28                                                         ` Bernd Schmidt
  1 sibling, 0 replies; 81+ messages in thread
From: Bernd Schmidt @ 2016-09-28 19:28 UTC (permalink / raw)
  To: Michael Matz, Tom Tromey
  Cc: Jakub Jelinek, Marek Polacek, Richard Biener, Eric Botcazou,
	GCC Patches, Markus Trippelsdorf, Jason Merrill, Rainer Orth,
	Joseph Myers, Arnaud Charlet

On 09/28/2016 02:15 PM, Michael Matz wrote:
> P.S.: Initially I even wanted to argue that the mere existence of _any_
> comment before a case label would disable the warning.  I don't have the
> numbers but I bet even that version would have found the very same bugs
> that the picky version has.

Sounds like a pretty good idea to me for a default setting. If we really 
want to have multiple levels of the warning. I agree that it's likely to 
find the majority of problems, and it no longer depends on language and 
spelling of the comment.


Bernd

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-28 19:13                                                           ` Jakub Jelinek
@ 2016-09-29  2:40                                                             ` Tom Tromey
  0 siblings, 0 replies; 81+ messages in thread
From: Tom Tromey @ 2016-09-29  2:40 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Tom Tromey, Michael Matz, Bernd Schmidt, Marek Polacek,
	Richard Biener, Eric Botcazou, GCC Patches, Markus Trippelsdorf,
	Jason Merrill, Rainer Orth, Joseph Myers, Arnaud Charlet

>>>>> "Jakub" == Jakub Jelinek <jakub@redhat.com> writes:

>> default:
>> {
>> complaint (&symfile_complaints,
>> _("Storage class %d not recognized during scan"),
>> sclass);
>> }
>> /* FALLTHROUGH */
>> 
>> /* C_FCN is .bf and .ef symbols.  I think it is sufficient
>> to handle only the C_FUN and C_EXT.  */
>> case C_FCN:

Jakub> Is complaint a noreturn call?

Nope.

Jakub> but right now we only look for such comments immediately before a
Jakub> case/default keyword or user label; if there is another comment
Jakub> in between, it is ignored.  This is something we are considering
Jakub> to change, exactly because often the /* FALLTHRU */ comment
Jakub> appears after some case and then there is unrelated comment
Jakub> before the next case about what that case handles.

Make sense.  Thanks.

Tom

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-09-26 20:36                         ` Rainer Orth
@ 2016-10-08 17:04                           ` Eric Botcazou
  2016-10-09  9:20                             ` Marek Polacek
  0 siblings, 1 reply; 81+ messages in thread
From: Eric Botcazou @ 2016-10-08 17:04 UTC (permalink / raw)
  To: Rainer Orth
  Cc: gcc-patches, Jakub Jelinek, Marek Polacek, Joseph Myers,
	Jason Merrill, Arnaud Charlet

[-- Attachment #1: Type: text/plain, Size: 1937 bytes --]

> testing completed successfully, so I've installed the patch with this
> ChangeLog entry:
> 
> 2016-09-26  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
> 
> 	gcc:
> 	* config/i386/i386.c (ix86_print_operand)
> 	[HAVE_AS_IX86_CMOV_SUN_SYNTAX]: Add gcc_fallthrough.
> 	* config/sparc/sparc.c (check_pic): Add fallthrough comment.
> 	(epilogue_renumber): Likewise.
> 
> 	gcc/ada:
> 	* gcc-interface/decl.c: Fix fall through comment formatting.
> 	* gcc-interface/misc.c: Likewise.
> 	* gcc-interface/trans.c: Likewise.
> 	* gcc-interface/utils.c: Likewise.
> 	* gcc-interface/utils2.c: Likewise.

This is a revealing example of how excessive pickiness in warnings can be 
counter-productive: after Jakub's latest patches (thanks!) accepting the 
original formatting of gcc-interface, I reverted part #2 of the above patch... 
only to discover that bootstrap was still broken because of a -Wimplicit-
fallthrough warning, but this time for a missing break:

Index: gcc-interface/utils.c
===================================================================
--- gcc-interface/utils.c	(revision 324591)
+++ gcc-interface/utils.c	(working copy)
@@ -4289,6 +4289,7 @@ convert (tree type, tree expr)
 	  TREE_TYPE (expr) = type;
 	  return expr;
 	}
+      break;
 
     case CONSTRUCTOR:
       /* If we are converting a CONSTRUCTOR to a mere type variant, or to

So the issue went unnoticed among the slew of false positives the first time 
and a genuine error was overlooked...

Tested on x86_64-suse-linux, applied on the mainline.


2016-10-08  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/utils.c (convert) <VECTOR_CST>: Add missing break.

	Revert
	2016-09-26  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	* gcc-interface/decl.c: Fix fall through comment formatting.
	* gcc-interface/misc.c: Likewise.
	* gcc-interface/trans.c: Likewise.
	* gcc-interface/utils.c: Likewise.
	* gcc-interface/utils2.c: Likewise.


-- 
Eric Botcazou

[-- Attachment #2: p.diff --]
[-- Type: text/x-patch, Size: 8817 bytes --]

Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 240888)
+++ gcc-interface/decl.c	(working copy)
@@ -596,7 +596,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	gnu_expr
 	  = gnat_to_gnu_external (Expression (Declaration_Node (gnat_entity)));
 
-      /* fall through */
+      /* ... fall through ... */
 
     case E_Exception:
     case E_Loop_Parameter:
@@ -3369,7 +3369,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	  break;
 	}
 
-      /* fall through */
+      /* ... fall through ... */
 
     case E_Record_Subtype:
       /* If Cloned_Subtype is Present it means this record subtype has
@@ -3804,7 +3804,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	    break;
 	}
 
-      /* fall through */
+      /* ... fall through ... */
 
     case E_Allocator_Type:
     case E_Access_Type:
@@ -6882,7 +6882,7 @@ choices_to_gnu (tree operand, Node_Id ch
 	      break;
 	    }
 
-	  /* fall through */
+	  /* ... fall through ... */
 
 	case N_Character_Literal:
 	case N_Integer_Literal:
@@ -8089,7 +8089,7 @@ annotate_value (tree gnu_size)
       else
 	return Uint_Minus_1;
 
-      /* fall through */
+      /* Fall through... */
 
     default:
       return No_Uint;
Index: gcc-interface/misc.c
===================================================================
--- gcc-interface/misc.c	(revision 240888)
+++ gcc-interface/misc.c	(working copy)
@@ -157,7 +157,7 @@ gnat_handle_option (size_t scode, const
     case OPT_gant:
       warning (0, "%<-gnat%> misspelled as %<-gant%>");
 
-      /* fall through */
+      /* ... fall through ... */
 
     case OPT_gnat:
     case OPT_gnatO:
@@ -485,13 +485,13 @@ gnat_print_type (FILE *file, tree node,
       else
 	print_node (file, "index type", TYPE_INDEX_TYPE (node), indent + 4);
 
-      /* fall through */
+      /* ... fall through ... */
 
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
       print_node_brief (file, "RM size", TYPE_RM_SIZE (node), indent + 4);
 
-      /* fall through */
+      /* ... fall through ... */
 
     case REAL_TYPE:
       print_node_brief (file, "RM min", TYPE_RM_MIN_VALUE (node), indent + 4);
Index: gcc-interface/trans.c
===================================================================
--- gcc-interface/trans.c	(revision 240888)
+++ gcc-interface/trans.c	(working copy)
@@ -844,7 +844,7 @@ lvalue_required_p (Node_Id gnat_node, tr
 		 && Ekind (Entity (gnat_temp)) == E_Enumeration_Literal))
 	  return 1;
 
-      /* fall through */
+      /* ... fall through ... */
 
     case N_Slice:
       /* Only the array expression can require an lvalue.  */
@@ -890,7 +890,7 @@ lvalue_required_p (Node_Id gnat_node, tr
 	if (!constant)
 	  return 1;
 
-      /* fall through */
+      /* ... fall through ... */
 
     case N_Type_Conversion:
     case N_Qualified_Expression:
@@ -914,7 +914,7 @@ lvalue_required_p (Node_Id gnat_node, tr
 				  get_unpadded_type (Etype (gnat_parent)),
 				  true, false, true);
 
-      /* fall through */
+      /* ... fall through ... */
 
     default:
       return 0;
@@ -1681,7 +1681,7 @@ Attribute_to_gnu (Node_Id gnat_node, tre
 	  break;
 	}
 
-      /* fall through */
+      /* ... fall through ... */
 
     case Attr_Access:
     case Attr_Unchecked_Access:
@@ -1938,7 +1938,7 @@ Attribute_to_gnu (Node_Id gnat_node, tre
 	  break;
 	}
 
-      /* fall through */
+      /* ... fall through ... */
 
     case Attr_Length:
       {
@@ -2393,7 +2393,7 @@ Attribute_to_gnu (Node_Id gnat_node, tre
       /* We treat Model as identical to Machine.  This is true for at least
 	 IEEE and some other nice floating-point systems.  */
 
-      /* fall through */
+      /* ... fall through ... */
 
     case Attr_Machine:
       /* The trick is to force the compiler to store the result in memory so
@@ -2537,7 +2537,7 @@ Case_Statement_to_gnu (Node_Id gnat_node
 		  break;
 		}
 
-	      /* fall through */
+	      /* ... fall through ... */
 
 	    case N_Character_Literal:
 	    case N_Integer_Literal:
@@ -4007,7 +4007,7 @@ node_is_atomic (Node_Id gnat_node)
 	  && Has_Atomic_Components (Entity (Prefix (gnat_node))))
 	return true;
 
-      /* fall through */
+      /* ... fall through ... */
 
     case N_Explicit_Dereference:
       return Is_Atomic (Etype (gnat_node));
@@ -4123,7 +4123,7 @@ atomic_access_required_p (Node_Id gnat_n
       /* Nothing to do if we are the prefix of an attribute, since we do not
 	 want an atomic access for things like 'Size.  */
 
-      /* fall through */
+      /* ... fall through ... */
 
     case N_Reference:
       /* The N_Reference node is like an attribute.  */
@@ -6580,7 +6580,7 @@ gnat_to_gnu (Node_Id gnat_node)
 	  break;
 	}
 
-      /* fall through */
+      /* ... fall through ... */
 
     case N_Op_Eq:
     case N_Op_Ne:
@@ -6747,7 +6747,7 @@ gnat_to_gnu (Node_Id gnat_node)
 	  break;
 	}
 
-      /* fall through */
+      /* ... fall through ... */
 
     case N_Op_Minus:
     case N_Op_Abs:
@@ -8344,7 +8344,7 @@ gnat_gimplify_expr (tree *expr_p, gimple
 	    break;
 	  }
 
-      /* fall through */
+      /* ... fall through ... */
 
     default:
       return GS_UNHANDLED;
@@ -9867,7 +9867,7 @@ set_gnu_expr_location_from_node (tree no
       if (EXPR_P (TREE_OPERAND (node, 1)))
 	set_gnu_expr_location_from_node (TREE_OPERAND (node, 1), gnat_node);
 
-      /* fall through */
+      /* ... fall through ... */
 
     default:
       if (!REFERENCE_CLASS_P (node) && !EXPR_HAS_LOCATION (node))
Index: gcc-interface/utils.c
===================================================================
--- gcc-interface/utils.c	(revision 240888)
+++ gcc-interface/utils.c	(working copy)
@@ -3166,7 +3166,7 @@ create_subprog_decl (tree name, tree asm
 				    NULL_TREE, NULL_TREE),
 			 ATTR_FLAG_TYPE_IN_PLACE);
 
-      /* fall through */
+      /* ... fall through ... */
 
     case is_enabled:
       DECL_DECLARED_INLINE_P (subprog_decl) = 1;
@@ -4270,8 +4270,7 @@ convert (tree type, tree expr)
 	  TREE_TYPE (expr) = type;
 	  return expr;
 	}
-
-      /* fall through */
+      break;
 
     case CONSTRUCTOR:
       /* If we are converting a CONSTRUCTOR to a mere type variant, or to
@@ -4510,7 +4509,7 @@ convert (tree type, tree expr)
 					  convert (TREE_TYPE (type),
 						   TYPE_MIN_VALUE (type))));
 
-      /* fall through */
+      /* ... fall through ... */
 
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
@@ -4587,7 +4586,7 @@ convert (tree type, tree expr)
 	  return gnat_build_constructor (type, v);
 	}
 
-      /* fall through */
+      /* ... fall through ... */
 
     case ARRAY_TYPE:
       /* In these cases, assume the front-end has validated the conversion.
@@ -4703,7 +4702,7 @@ convert_to_index_type (tree expr)
 	  break;
       }
 
-      /* fall through */
+      /* ... fall through ... */
 
     case NON_LVALUE_EXPR:
       return fold_build1 (code, sizetype,
Index: gcc-interface/utils2.c
===================================================================
--- gcc-interface/utils2.c	(revision 240888)
+++ gcc-interface/utils2.c	(working copy)
@@ -180,7 +180,7 @@ known_alignment (tree exp)
 	  return known_alignment (t);
       }
 
-      /* fall through */
+      /* ... fall through ... */
 
     default:
       /* For other pointer expressions, we assume that the pointed-to object
@@ -1011,7 +1011,7 @@ build_binary_op (enum tree_code op_code,
       if (!operation_type)
 	operation_type = TREE_TYPE (left_type);
 
-      /* fall through */
+      /* ... fall through ... */
 
     case ARRAY_RANGE_REF:
       /* First look through conversion between type variants.  Note that
@@ -1230,7 +1230,7 @@ build_binary_op (enum tree_code op_code,
 	op_code = MINUS_EXPR;
       modulus = NULL_TREE;
 
-      /* fall through */
+      /* ... fall through ... */
 
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -1244,7 +1244,7 @@ build_binary_op (enum tree_code op_code,
 	  = gnat_type_for_mode (TYPE_MODE (operation_type),
 				TYPE_UNSIGNED (operation_type));
 
-      /* fall through */
+      /* ... fall through ... */
 
     default:
     common:
@@ -1466,7 +1466,7 @@ build_unary_op (enum tree_code op_code,
 	    return build_unary_op (ADDR_EXPR, result_type,
 				   TREE_OPERAND (operand, 0));
 
-	  /* fallthru */
+	  /* ... fallthru ... */
 
 	case VIEW_CONVERT_EXPR:
 	  /* If this just a variant conversion or if the conversion doesn't
@@ -1487,7 +1487,7 @@ build_unary_op (enum tree_code op_code,
 	case CONST_DECL:
 	  operand = DECL_CONST_CORRESPONDING_VAR (operand);
 
-	  /* fall through */
+	  /* ... fall through ... */
 
 	default:
 	common:
@@ -1648,7 +1648,7 @@ build_unary_op (enum tree_code op_code,
 	  }
       }
 
-      /* fall through */
+      /* ... fall through ... */
 
     default:
       gcc_assert (operation_type == base_type);

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-10-08 17:04                           ` Eric Botcazou
@ 2016-10-09  9:20                             ` Marek Polacek
  2016-10-09  9:43                               ` Eric Botcazou
  0 siblings, 1 reply; 81+ messages in thread
From: Marek Polacek @ 2016-10-09  9:20 UTC (permalink / raw)
  To: Eric Botcazou
  Cc: Rainer Orth, gcc-patches, Jakub Jelinek, Joseph Myers,
	Jason Merrill, Arnaud Charlet

On Sat, Oct 08, 2016 at 07:04:41PM +0200, Eric Botcazou wrote:
> > testing completed successfully, so I've installed the patch with this
> > ChangeLog entry:
> > 
> > 2016-09-26  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
> > 
> > 	gcc:
> > 	* config/i386/i386.c (ix86_print_operand)
> > 	[HAVE_AS_IX86_CMOV_SUN_SYNTAX]: Add gcc_fallthrough.
> > 	* config/sparc/sparc.c (check_pic): Add fallthrough comment.
> > 	(epilogue_renumber): Likewise.
> > 
> > 	gcc/ada:
> > 	* gcc-interface/decl.c: Fix fall through comment formatting.
> > 	* gcc-interface/misc.c: Likewise.
> > 	* gcc-interface/trans.c: Likewise.
> > 	* gcc-interface/utils.c: Likewise.
> > 	* gcc-interface/utils2.c: Likewise.
> 
> This is a revealing example of how excessive pickiness in warnings can be 
> counter-productive: after Jakub's latest patches (thanks!) accepting the 
> original formatting of gcc-interface, I reverted part #2 of the above patch... 
> only to discover that bootstrap was still broken because of a -Wimplicit-
> fallthrough warning, but this time for a missing break:

I really really don't see why anyone would think that those '...' bring
any additional information.  Since Rainer has changed this, I see zero
point in changing it back.

> Index: gcc-interface/utils.c
> ===================================================================
> --- gcc-interface/utils.c	(revision 324591)
> +++ gcc-interface/utils.c	(working copy)
> @@ -4289,6 +4289,7 @@ convert (tree type, tree expr)
>  	  TREE_TYPE (expr) = type;
>  	  return expr;
>  	}
> +      break;
>  
>      case CONSTRUCTOR:
>        /* If we are converting a CONSTRUCTOR to a mere type variant, or to
> 
> So the issue went unnoticed among the slew of false positives the first time 
> and a genuine error was overlooked...

It wasn't overlooked, there was a bug that I've fixed already which caused
missing warnings.

	Marek

^ permalink raw reply	[flat|nested] 81+ messages in thread

* Re: Implement -Wimplicit-fallthrough (version 9)
  2016-10-09  9:20                             ` Marek Polacek
@ 2016-10-09  9:43                               ` Eric Botcazou
  0 siblings, 0 replies; 81+ messages in thread
From: Eric Botcazou @ 2016-10-09  9:43 UTC (permalink / raw)
  To: Marek Polacek
  Cc: gcc-patches, Rainer Orth, Jakub Jelinek, Joseph Myers,
	Jason Merrill, Arnaud Charlet

> I really really don't see why anyone would think that those '...' bring
> any additional information.  Since Rainer has changed this, I see zero
> point in changing it back.

Yet doing it revealed an oversight in the first patch...

> It wasn't overlooked, there was a bug that I've fixed already which caused
> missing warnings.

Nope, see this hunk in the first patch:

@@ -4271,6 +4271,8 @@ convert (tree type, tree expr)
          return expr;
        }
 
+      /* fall through */
+
     case CONSTRUCTOR:
       /* If we are converting a CONSTRUCTOR to a mere type variant, or to
         another padding type around the same type, just make a new one in

It's plain wrong, it should have been a break instead, but this was overlooked 
by everyone because of the bunch of false positives.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 81+ messages in thread

end of thread, other threads:[~2016-10-09  9:43 UTC | newest]

Thread overview: 81+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-20 15:49 Implement -Wimplicit-fallthrough (version 9) Marek Polacek
2016-09-20 16:29 ` Jason Merrill
2016-09-21 13:19   ` Marek Polacek
2016-09-21 14:22     ` Jason Merrill
2016-09-21 19:25       ` Marek Polacek
2016-09-21 19:40         ` Jason Merrill
2016-09-22 14:24           ` Marek Polacek
2016-09-23 14:11             ` Marek Polacek
2016-09-23 14:26             ` Jason Merrill
2016-09-23 14:27               ` Jakub Jelinek
2016-09-23 14:34                 ` Marek Polacek
2016-09-23 14:31               ` Marek Polacek
2016-09-24  0:19                 ` Joseph Myers
2016-09-24 13:32                   ` Marek Polacek
2016-09-26 13:41                     ` Rainer Orth
2016-09-26 13:53                       ` Jakub Jelinek
2016-09-26 20:36                         ` Rainer Orth
2016-10-08 17:04                           ` Eric Botcazou
2016-10-09  9:20                             ` Marek Polacek
2016-10-09  9:43                               ` Eric Botcazou
2016-09-26 13:56                       ` Marek Polacek
2016-09-26 21:01                         ` Rainer Orth
2016-09-26 15:22                       ` Arnaud Charlet
2016-09-26 15:55                       ` Jason Merrill
2016-09-27  7:47                         ` Eric Botcazou
2016-09-27  8:01                           ` Eric Botcazou
2016-09-27  8:02                             ` Fix bootstrap failure in combine.c and i386.c due to -Wimplicit-fallthrough Jakub Jelinek
2016-09-27  8:13                               ` Richard Biener
2016-09-27  9:41                                 ` Jakub Jelinek
2016-09-27 10:32                                   ` Richard Biener
2016-09-27  8:32                           ` Implement -Wimplicit-fallthrough (version 9) Jakub Jelinek
2016-09-27  9:40                             ` Eric Botcazou
2016-09-27 10:42                               ` Markus Trippelsdorf
2016-09-27 10:53                                 ` Jakub Jelinek
2016-09-27 10:56                                   ` Jakub Jelinek
2016-09-27 10:58                                   ` Marek Polacek
2016-09-27 11:46                                     ` Jakub Jelinek
2016-09-27 11:53                                       ` Segher Boessenkool
2016-09-27 12:03                                         ` Jakub Jelinek
2016-09-27 12:57                                           ` Segher Boessenkool
2016-09-27 17:31                                       ` Marek Polacek
2016-09-27 11:51                                     ` Markus Trippelsdorf
2016-09-27 12:27                                       ` Marek Polacek
2016-09-27 12:32                                         ` Florian Weimer
2016-09-27 12:42                                           ` Jakub Jelinek
2016-09-27 12:42                                           ` Marek Polacek
2016-09-27 11:08                                   ` Eric Botcazou
2016-09-27 11:12                                     ` Richard Biener
2016-09-27 11:52                                       ` Bernd Schmidt
2016-09-27 11:55                                         ` Marek Polacek
2016-09-27 12:01                                           ` Bernd Schmidt
2016-09-27 12:22                                             ` Marek Polacek
2016-09-27 13:50                                               ` Bernd Schmidt
2016-09-27 13:53                                                 ` Jakub Jelinek
2016-09-27 13:56                                                   ` Bernd Schmidt
2016-09-27 14:01                                                     ` Jakub Jelinek
2016-09-27 14:49                                                     ` Marek Polacek
2016-09-27 14:00                                                   ` Michael Matz
2016-09-27 14:53                                                     ` Jason Merrill
2016-09-27 14:57                                                       ` Marek Polacek
2016-09-27 15:10                                                         ` Jakub Jelinek
2016-09-27 15:29                                                           ` Bernd Schmidt
2016-09-27 15:36                                                             ` Jakub Jelinek
2016-09-27 15:29                                                           ` Marek Polacek
2016-09-27 16:04                                                             ` Michael Matz
2016-09-27 16:47                                                     ` Tom Tromey
2016-09-28 12:46                                                       ` Michael Matz
2016-09-28 15:31                                                         ` Tom Tromey
2016-09-28 19:13                                                           ` Jakub Jelinek
2016-09-29  2:40                                                             ` Tom Tromey
2016-09-28 19:28                                                         ` Bernd Schmidt
2016-09-27  7:55                     ` Gerald Pfeifer
2016-09-27  9:44                       ` Marek Polacek
2016-09-27  8:17                     ` Andreas Schwab
2016-09-27  8:27                       ` Jakub Jelinek
2016-09-27  8:46                         ` Richard Biener
2016-09-27 10:15                       ` Marek Polacek
2016-09-27 10:39                         ` Kyrill Tkachov
2016-09-27 10:48                           ` Jakub Jelinek
2016-09-27 11:15                             ` Kyrill Tkachov
2016-09-27 12:31                               ` Marek Polacek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).