diff mbox

Implement -Wimplicit-fallthrough (version 7)

Message ID 20160829115847.GZ11131@redhat.com
State New
Headers show

Commit Message

Marek Polacek Aug. 29, 2016, 11:58 a.m. UTC
Tobias tried my latest version and reported some ICEs.  They should all be
fixed in this version (the only change since version 6 is the cp/pt.c hunk).

At this point I'd like to ask Jason and Joseph to review the C/C++ parts
and someone to review the ME parts so that I can finally wrap this thing
up.  This warning found a couple of bugs in our codebase and I suspect it
will find some in other codebases, too.

Does anyone have any concerns that I haven't addressed yet?

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

2016-08-29  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.
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.
	(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-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/warn/Wimplicit-fallthrough-1.C: New test.
	* g++.dg/warn/Wimplicit-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.


	Marek

Comments

Eric Gallager Aug. 29, 2016, 1:32 p.m. UTC | #1
On 8/29/16, Marek Polacek <polacek@redhat.com> wrote:
> Tobias tried my latest version and reported some ICEs.  They should all be
> fixed in this version (the only change since version 6 is the cp/pt.c
> hunk).
>
> At this point I'd like to ask Jason and Joseph to review the C/C++ parts
> and someone to review the ME parts so that I can finally wrap this thing
> up.  This warning found a couple of bugs in our codebase and I suspect it
> will find some in other codebases, too.
>
> Does anyone have any concerns that I haven't addressed yet?
>
> Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for trunk?
>


I tried v6 on my binutils-gdb fork, and it printed A LOT of
warnings... After this patch goes in, the main question I'd have would
be about the carets: it seems like it would make more sense for me for
the location of the warning to be swapped with that of the fixit
hint(s)? With the fixit pointing to the case label before the
statement that's warned about, it makes it look like it's suggesting
to put the fallthrough attribute or the break before the rest of the
content of the case, which, with the break, could lead to dead code.
I'd think it'd make more sense to point to after the body of the case
statement instead...

Eric
David Malcolm Aug. 29, 2016, 1:54 p.m. UTC | #2
On Mon, 2016-08-29 at 09:32 -0400, Eric Gallager wrote:
> On 8/29/16, Marek Polacek <polacek@redhat.com> wrote:
> > Tobias tried my latest version and reported some ICEs.  They should
> > all be
> > fixed in this version (the only change since version 6 is the
> > cp/pt.c
> > hunk).
> > 
> > At this point I'd like to ask Jason and Joseph to review the C/C++
> > parts
> > and someone to review the ME parts so that I can finally wrap this
> > thing
> > up.  This warning found a couple of bugs in our codebase and I
> > suspect it
> > will find some in other codebases, too.
> > 
> > Does anyone have any concerns that I haven't addressed yet?
> > 
> > Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for
> > trunk?
> > 
> 
> 
> I tried v6 on my binutils-gdb fork, and it printed A LOT of
> warnings... After this patch goes in, the main question I'd have
> would
> be about the carets: it seems like it would make more sense for me
> for
> the location of the warning to be swapped with that of the fixit
> hint(s)? With the fixit pointing to the case label before the
> statement that's warned about, it makes it look like it's suggesting
> to put the fallthrough attribute or the break before the rest of the
> content of the case, which, with the break, could lead to dead code.
> I'd think it'd make more sense to point to after the body of the case
> statement instead...

Interesting.  Please can you post an example of the output that you're
referring to?

I'm working on improvements to how we print fix-its, so I'm wondering
if this is an issue with the fix-it data, or with the presentation of
it.

Thanks
Dave
Eric Gallager Aug. 29, 2016, 2:04 p.m. UTC | #3
On 8/29/16, David Malcolm <dmalcolm@redhat.com> wrote:
> On Mon, 2016-08-29 at 09:32 -0400, Eric Gallager wrote:
>> On 8/29/16, Marek Polacek <polacek@redhat.com> wrote:
>> > Tobias tried my latest version and reported some ICEs.  They should
>> > all be
>> > fixed in this version (the only change since version 6 is the
>> > cp/pt.c
>> > hunk).
>> >
>> > At this point I'd like to ask Jason and Joseph to review the C/C++
>> > parts
>> > and someone to review the ME parts so that I can finally wrap this
>> > thing
>> > up.  This warning found a couple of bugs in our codebase and I
>> > suspect it
>> > will find some in other codebases, too.
>> >
>> > Does anyone have any concerns that I haven't addressed yet?
>> >
>> > Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for
>> > trunk?
>> >
>>
>>
>> I tried v6 on my binutils-gdb fork, and it printed A LOT of
>> warnings... After this patch goes in, the main question I'd have
>> would
>> be about the carets: it seems like it would make more sense for me
>> for
>> the location of the warning to be swapped with that of the fixit
>> hint(s)? With the fixit pointing to the case label before the
>> statement that's warned about, it makes it look like it's suggesting
>> to put the fallthrough attribute or the break before the rest of the
>> content of the case, which, with the break, could lead to dead code.
>> I'd think it'd make more sense to point to after the body of the case
>> statement instead...
>
> Interesting.  Please can you post an example of the output that you're
> referring to?
>
> I'm working on improvements to how we print fix-its, so I'm wondering
> if this is an issue with the fix-it data, or with the presentation of
> it.
>
> Thanks
> Dave
>

Sure, an example of the warning looks like this for me:

./cli/cli-setshow.c: In function ‘do_setshow_command’:
./cli/cli-setshow.c:353:7: warning: this statement may fall through
[-Wimplicit-fallthrough]
    if (*(unsigned int *)c->var == UINT_MAX)
       ^
./cli/cli-setshow.c:359:2: note: insert ‘__attribute__
((fallthrough));’ to silence this warning
  case var_zinteger:
  ^~~~
  __attribute__ ((fallthrough));
./cli/cli-setshow.c:359:2: note: insert ‘break;’ to avoid fall-through
  case var_zinteger:
  ^~~~
  break;

Eric
David Malcolm Aug. 29, 2016, 2:41 p.m. UTC | #4
On Mon, 2016-08-29 at 10:04 -0400, Eric Gallager wrote:
> On 8/29/16, David Malcolm <dmalcolm@redhat.com> wrote:
> > On Mon, 2016-08-29 at 09:32 -0400, Eric Gallager wrote:
> > > On 8/29/16, Marek Polacek <polacek@redhat.com> wrote:
> > > > Tobias tried my latest version and reported some ICEs.  They
> > > > should
> > > > all be
> > > > fixed in this version (the only change since version 6 is the
> > > > cp/pt.c
> > > > hunk).
> > > > 
> > > > At this point I'd like to ask Jason and Joseph to review the
> > > > C/C++
> > > > parts
> > > > and someone to review the ME parts so that I can finally wrap
> > > > this
> > > > thing
> > > > up.  This warning found a couple of bugs in our codebase and I
> > > > suspect it
> > > > will find some in other codebases, too.
> > > > 
> > > > Does anyone have any concerns that I haven't addressed yet?
> > > > 
> > > > Bootstrapped/regtested on x86_64-linux and ppc64-linux, ok for
> > > > trunk?
> > > > 
> > > 
> > > 
> > > I tried v6 on my binutils-gdb fork, and it printed A LOT of
> > > warnings... After this patch goes in, the main question I'd have
> > > would
> > > be about the carets: it seems like it would make more sense for
> > > me
> > > for
> > > the location of the warning to be swapped with that of the fixit
> > > hint(s)? With the fixit pointing to the case label before the
> > > statement that's warned about, it makes it look like it's
> > > suggesting
> > > to put the fallthrough attribute or the break before the rest of
> > > the
> > > content of the case, which, with the break, could lead to dead
> > > code.
> > > I'd think it'd make more sense to point to after the body of the
> > > case
> > > statement instead...
> > 
> > Interesting.  Please can you post an example of the output that
> > you're
> > referring to?
> > 
> > I'm working on improvements to how we print fix-its, so I'm
> > wondering
> > if this is an issue with the fix-it data, or with the presentation
> > of
> > it.
> > 
> > Thanks
> > Dave
> > 
> 
> Sure, an example of the warning looks like this for me:
> 
> ./cli/cli-setshow.c: In function ‘do_setshow_command’:
> ./cli/cli-setshow.c:353:7: warning: this statement may fall through
> [-Wimplicit-fallthrough]
>     if (*(unsigned int *)c->var == UINT_MAX)
>        ^
> ./cli/cli-setshow.c:359:2: note: insert ‘__attribute__
> ((fallthrough));’ to silence this warning
>   case var_zinteger:
>   ^~~~
>   __attribute__ ((fallthrough));
> ./cli/cli-setshow.c:359:2: note: insert ‘break;’ to avoid fall
> -through
>   case var_zinteger:
>   ^~~~
>   break;

Thanks.  So presumably you have something like:

...     case something:
353       if (*(unsigned int *)c->var == UINT_MAX)
354        {
355
356            /* various code here */
357        }
358
359     case var_zinteger:
360        /* etc  */

and hence the new warning is complaining about the fallthrough to line
359.

If so, I agree that the fix-it as it's currently printed is misleading.

Insertion fix-its appear immediately before the text at the caret, so
the result of applying the fix-its (using my -fdiagnostics-generate
-patch patchkit) would be:

359     __attribute__ ((fallthrough));case var_zinteger:

and:

359     break;case var_zinteger:

It looks like the fix-it data is technically correct, but the end-result doesn't resemble normal formatting.

In fact, -fdiagnostics-generate-patch doesn't know about "apply this OR apply that", so the generated patch would probably look like this:

@@ -354,5 +354,5
         }

-     case var_zinteger:
+     __attribute__ ((fallthrough));break;case var_zinteger:
         /* etc */

The text inserted by the fixits probably ought to be on lines to themselves, with appropriate indentation, so that the generated patch would then look something like this:

@@ -354,5 +354,6
         }

+     __attribute__ ((fallthrough));
      case var_zinteger:
         /* etc */

and:

@@ -354,5 +354,6
         }

+        break;
      case var_zinteger:
         /* etc */


This is non-trivial for two reasons:

(a) there are various places in the fixit handling-code that aren't yet expecting newlines in fixit text; in particular, printing the fix-its.
Also, diagnostics_show_locus also will currently only print fixits on lines that are touched by a range within the diagnostic.

(b) figuring out the appropriate indentation may be hard

These issues are fixable, but seem something of a digression.  I think the best course of action here is for Marek to remove the fix-it hints for now, so it doesn't block getting the warning into trunk, and for us to work on adding the fixits as follow-up work once the less ambitious version of the patch is approved.  I believe that the "note" diagnostics make sense to print even without the fixit hints, so that those could be kept for now.

Marek, others: does this sound like a good course of action?


Dave
Marek Polacek Aug. 29, 2016, 3:23 p.m. UTC | #5
On Mon, Aug 29, 2016 at 10:41:57AM -0400, David Malcolm wrote:
> Thanks.  So presumably you have something like:
> 
> ...     case something:
> 353       if (*(unsigned int *)c->var == UINT_MAX)
> 354        {
> 355
> 356            /* various code here */
> 357        }
> 358
> 359     case var_zinteger:
> 360        /* etc  */
> 
> and hence the new warning is complaining about the fallthrough to line
> 359.
 
From the very beginning, my intent was to show *what* falls through *where*,
so I think the locations are precise as they are and I wouldn't want to
change them.

> If so, I agree that the fix-it as it's currently printed is misleading.
> 
> Insertion fix-its appear immediately before the text at the caret, so
> the result of applying the fix-its (using my -fdiagnostics-generate
> -patch patchkit) would be:
> 
> 359     __attribute__ ((fallthrough));case var_zinteger:
> 
> and:
> 
> 359     break;case var_zinteger:
> 
> It looks like the fix-it data is technically correct, but the end-result doesn't resemble normal formatting.
> 
> In fact, -fdiagnostics-generate-patch doesn't know about "apply this OR apply that", so the generated patch would probably look like this:
> 
> @@ -354,5 +354,5
>          }
> 
> -     case var_zinteger:
> +     __attribute__ ((fallthrough));break;case var_zinteger:
>          /* etc */
> 
> The text inserted by the fixits probably ought to be on lines to themselves, with appropriate indentation, so that the generated patch would then look something like this:
> 
> @@ -354,5 +354,6
>          }
> 
> +     __attribute__ ((fallthrough));
>       case var_zinteger:
>          /* etc */
> 
> and:
> 
> @@ -354,5 +354,6
>          }
> 
> +        break;
>       case var_zinteger:
>          /* etc */
> 
> 
> This is non-trivial for two reasons:
> 
> (a) there are various places in the fixit handling-code that aren't yet expecting newlines in fixit text; in particular, printing the fix-its.
> Also, diagnostics_show_locus also will currently only print fixits on lines that are touched by a range within the diagnostic.
> 
> (b) figuring out the appropriate indentation may be hard
> 
> These issues are fixable, but seem something of a digression.  I think the best course of action here is for Marek to remove the fix-it hints for now, so it doesn't block getting the warning into trunk, and for us to work on adding the fixits as follow-up work once the less ambitious version of the patch is approved.  I believe that the "note" diagnostics make sense to print even without the fixit hints, so that those could be kept for now.
> 
> Marek, others: does this sound like a good course of action?

Yeah, I appreciate this isn't easy.  Given fix-it hints shouldn't be considered
a blocker for a patch like this, I can simply resort to what I had in the
early phase, that is say something like

q.c:7:8: warning: this statement may fall through [-Wimplicit-fallthrough]
       b++;
       ~^~
q.c:8:5: note: here
     case 1:
     ^~~~

and we can improve things incrementally.

Thanks,

	Marek
Jason Merrill Aug. 29, 2016, 8:02 p.m. UTC | #6
On Mon, Aug 29, 2016 at 7:58 AM, Marek Polacek <polacek@redhat.com> wrote:
> --- gcc/gcc/cp/parser.c
> +++ gcc/gcc/cp/parser.c
> @@ -5135,6 +5135,31 @@ 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 (attr != NULL_TREE
> +               && is_attribute_p ("fallthrough", get_attribute_name (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 used");

Let's say "can be applied to a null statement".

> @@ -10585,15 +10610,26 @@ 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
> +         && is_attribute_p ("fallthrough", get_attribute_name (std_attrs))
> +         && statement == NULL_TREE)
> +       {
> +         tree fn = build_call_expr_internal_loc (statement_location,
> +                                                 IFN_FALLTHROUGH,
> +                                                 void_type_node, 0);

Let's use the 'statement' variable rather than a new variable fn so
that we set the call's location below.  Let's also warn here about
[[fallthrough]] on non-null expression statements.

> +         finish_expr_stmt (fn);

Let's clear std_attrs here...

> +       }

>    /* 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.  */
> -  if (std_attrs != NULL_TREE)
> +  /* Allow "[[fallthrough]];", but warn otherwise.  */
> +  if (std_attrs != NULL_TREE
> +      && !is_attribute_p ("fallthrough", get_attribute_name (std_attrs)))

...so we don't need to check for fallthrough here.

> @@ -24114,6 +24164,16 @@ cp_parser_std_attribute (cp_parser *parser)
>                      " use %<gnu::deprecated%>");
>           TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
>         }
> +      /* C++17 fallthrough attribute is equivalent to GNU's.  */
> +      else if (cxx_dialect >= cxx11

There's no point checking this, here or for attribute deprecated; if
we're in this function, we must be in C++11 or above.  Let's drop the
check in both places.

Jason
Marek Polacek Aug. 30, 2016, 8:52 a.m. UTC | #7
On Mon, Aug 29, 2016 at 09:32:04AM -0400, Eric Gallager wrote:
> I tried v6 on my binutils-gdb fork, and it printed A LOT of
> warnings...

BTW, why is that so?  Does binutils-gdb not use various FALLTHRU comments?

	Marek
Eric Gallager Aug. 30, 2016, 11:38 a.m. UTC | #8
On 8/30/16, Marek Polacek <polacek@redhat.com> wrote:
> On Mon, Aug 29, 2016 at 09:32:04AM -0400, Eric Gallager wrote:
>> I tried v6 on my binutils-gdb fork, and it printed A LOT of
>> warnings...
>
> BTW, why is that so?  Does binutils-gdb not use various FALLTHRU comments?
>
> 	Marek
>


There are a lot of comments mentioning fallthroughs, but they mostly
need to be rewritten to be recognized properly. There's just so many
different ways of writing them. For example, one I've seen a lot
writes it as "Drop through" instead of "Fall through" or something.
Other examples of comments mentioning fallthroughs:

/* else fall through */
/* else fallthrough to: */
/* FALL THRU into number case.  */
/* ObjC NSString constant: fall through and parse like STRING. */
/* Fall through, pretend it is global.  */
/* Fall through into normal member function.  */
/* fall in for static symbols that do NOT start with '.' */
/* >>> !! else fall through !! <<< */
/* ... fall through for unsigned ints ... */
/* fall thru to manual case */

Also, at second glance, it's actually not quite as many warnings as I
thought it was at first, it mostly just looked that way since each
-Wimplicit-fallthrough warning takes up 12 lines due to the
double-fixits. FWIW, Aldy's -Walloca-larger-than patch actually was
noisier in the GDB portion at least. (The Binutils portion was already
clean on its alloca usage since it already used the -Wstack-usage
warning.)
Oh, and one other thing I discovered:
__attribute__((fallthrough)) triggers -Wdeclaration-after-statement:

In file included from ./defs.h:124:0,
                 from ./cli/cli-setshow.c:20:
./cli/cli-setshow.c: In function ‘do_setshow_command’:
./../include/ansidecl.h:505:33: warning: ISO C90 forbids mixed
declarations and code [-Wdeclaration-after-statement]
 #  define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough))
                                 ^
./cli/cli-setshow.c:359:4: note: in expansion of macro ‘ATTRIBUTE_FALLTHROUGH’
    ATTRIBUTE_FALLTHROUGH;
    ^~~~~~~~~~~~~~~~~~~~~

Which doesn't really make sense to me.
Marek Polacek Aug. 30, 2016, 2:25 p.m. UTC | #9
On Mon, Aug 29, 2016 at 04:02:33PM -0400, Jason Merrill wrote:
> On Mon, Aug 29, 2016 at 7:58 AM, Marek Polacek <polacek@redhat.com> wrote:
> > --- gcc/gcc/cp/parser.c
> > +++ gcc/gcc/cp/parser.c
> > @@ -5135,6 +5135,31 @@ 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 (attr != NULL_TREE
> > +               && is_attribute_p ("fallthrough", get_attribute_name (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 used");
> 
> Let's say "can be applied to a null statement".
 
Fixed.

> > @@ -10585,15 +10610,26 @@ 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
> > +         && is_attribute_p ("fallthrough", get_attribute_name (std_attrs))
> > +         && statement == NULL_TREE)
> > +       {
> > +         tree fn = build_call_expr_internal_loc (statement_location,
> > +                                                 IFN_FALLTHROUGH,
> > +                                                 void_type_node, 0);
> 
> Let's use the 'statement' variable rather than a new variable fn so
> that we set the call's location below.  Let's also warn here about
> [[fallthrough]] on non-null expression statements.

Done.  But I couldn't figure out a testcase where the warning would trigger, so
not sure how important that is.

> > +         finish_expr_stmt (fn);
> 
> Let's clear std_attrs here...
> 
> > +       }
> 
> >    /* 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.  */
> > -  if (std_attrs != NULL_TREE)
> > +  /* Allow "[[fallthrough]];", but warn otherwise.  */
> > +  if (std_attrs != NULL_TREE
> > +      && !is_attribute_p ("fallthrough", get_attribute_name (std_attrs)))
> 
> ...so we don't need to check for fallthrough here.
 
Ok, done.

> > @@ -24114,6 +24164,16 @@ cp_parser_std_attribute (cp_parser *parser)
> >                      " use %<gnu::deprecated%>");
> >           TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
> >         }
> > +      /* C++17 fallthrough attribute is equivalent to GNU's.  */
> > +      else if (cxx_dialect >= cxx11
> 
> There's no point checking this, here or for attribute deprecated; if
> we're in this function, we must be in C++11 or above.  Let's drop the
> check in both places.

Makes sense, fixed.

Thanks for looking into this.  I'll post another version once it passes
testing.

	Marek
Marek Polacek Aug. 30, 2016, 4:06 p.m. UTC | #10
On Tue, Aug 30, 2016 at 07:38:18AM -0400, Eric Gallager wrote:
> On 8/30/16, Marek Polacek <polacek@redhat.com> wrote:
> > On Mon, Aug 29, 2016 at 09:32:04AM -0400, Eric Gallager wrote:
> >> I tried v6 on my binutils-gdb fork, and it printed A LOT of
> >> warnings...
> >
> > BTW, why is that so?  Does binutils-gdb not use various FALLTHRU comments?
> >
> > 	Marek
> >
> 
> 
> There are a lot of comments mentioning fallthroughs, but they mostly
> need to be rewritten to be recognized properly. There's just so many
> different ways of writing them. For example, one I've seen a lot
> writes it as "Drop through" instead of "Fall through" or something.
> Other examples of comments mentioning fallthroughs:
> 
> /* else fall through */
> /* else fallthrough to: */
> /* FALL THRU into number case.  */
> /* ObjC NSString constant: fall through and parse like STRING. */
> /* Fall through, pretend it is global.  */
> /* Fall through into normal member function.  */
> /* fall in for static symbols that do NOT start with '.' */
> /* >>> !! else fall through !! <<< */
> /* ... fall through for unsigned ints ... */
> /* fall thru to manual case */
 
Thanks, this is interesting.  I wonder if we should also recognize
"else fall through"; I've seen that in our codebase a few times.

But why would anyone write something as ugly as ">>> !! else fall through !! <<<"
is beyond me.

> Also, at second glance, it's actually not quite as many warnings as I
> thought it was at first, it mostly just looked that way since each
> -Wimplicit-fallthrough warning takes up 12 lines due to the
> double-fixits. FWIW, Aldy's -Walloca-larger-than patch actually was
> noisier in the GDB portion at least. (The Binutils portion was already
> clean on its alloca usage since it already used the -Wstack-usage
> warning.)

That's nice to hear.  The latest version of the patch doesn't have the fix-it
hints, it just says in an inform note where a statement falls through to,
so it's going to be less verbose.

> Oh, and one other thing I discovered:
> __attribute__((fallthrough)) triggers -Wdeclaration-after-statement:
> 
> In file included from ./defs.h:124:0,
>                  from ./cli/cli-setshow.c:20:
> ./cli/cli-setshow.c: In function ‘do_setshow_command’:
> ./../include/ansidecl.h:505:33: warning: ISO C90 forbids mixed
> declarations and code [-Wdeclaration-after-statement]
>  #  define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough))
>                                  ^
> ./cli/cli-setshow.c:359:4: note: in expansion of macro ‘ATTRIBUTE_FALLTHROUGH’
>     ATTRIBUTE_FALLTHROUGH;
>     ^~~~~~~~~~~~~~~~~~~~~
> 
> Which doesn't really make sense to me.

Yes, I think this is a bug.  I'm pondering how to fix this.

Thanks a lot Eric!

	Marek
Jason Merrill Aug. 30, 2016, 5:08 p.m. UTC | #11
On Tue, Aug 30, 2016 at 10:25 AM, Marek Polacek <polacek@redhat.com> wrote:
>> > @@ -10585,15 +10610,26 @@ 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
>> > +         && is_attribute_p ("fallthrough", get_attribute_name (std_attrs))
>> > +         && statement == NULL_TREE)
>> > +       {
>> > +         tree fn = build_call_expr_internal_loc (statement_location,
>> > +                                                 IFN_FALLTHROUGH,
>> > +                                                 void_type_node, 0);
>>
>> Let's use the 'statement' variable rather than a new variable fn so
>> that we set the call's location below.  Let's also warn here about
>> [[fallthrough]] on non-null expression statements.
>
> Done.  But I couldn't figure out a testcase where the warning would trigger, so
> not sure how important that is.

What happens for

[[fallthrough]] 42;

?  What ought to happen is a warning that the attribute only applies
to null statements.

Jason
Marek Polacek Aug. 31, 2016, 9:06 a.m. UTC | #12
On Tue, Aug 30, 2016 at 01:08:22PM -0400, Jason Merrill wrote:
> On Tue, Aug 30, 2016 at 10:25 AM, Marek Polacek <polacek@redhat.com> wrote:
> >> > @@ -10585,15 +10610,26 @@ 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
> >> > +         && is_attribute_p ("fallthrough", get_attribute_name (std_attrs))
> >> > +         && statement == NULL_TREE)
> >> > +       {
> >> > +         tree fn = build_call_expr_internal_loc (statement_location,
> >> > +                                                 IFN_FALLTHROUGH,
> >> > +                                                 void_type_node, 0);
> >>
> >> Let's use the 'statement' variable rather than a new variable fn so
> >> that we set the call's location below.  Let's also warn here about
> >> [[fallthrough]] on non-null expression statements.
> >
> > Done.  But I couldn't figure out a testcase where the warning would trigger, so
> > not sure how important that is.
> 
> What happens for
> 
> [[fallthrough]] 42;
> 
> ?  What ought to happen is a warning that the attribute only applies
> to null statements.

This:
q.C: In function ‘void f(int)’:
q.C:8:8: error: expected identifier before ‘[’ token
       [[fallthrough]] 42;
        ^
q.C: In lambda function:
q.C:8:23: error: expected ‘{’ before numeric constant
       [[fallthrough]] 42;
                       ^~

And the same with e.g. [[unused]].  G++ 6 behaves exactly the same,
so it isn't something my patch changed.  It seems we never even reach
the code in question, at least std_attrs is null.

It seems g++ is trying to parse a lambda expression.

	Marek
diff mbox

Patch

diff --git gcc/gcc/c-family/c-common.c gcc/gcc/c-family/c-common.c
index 001070d..bb30ed5 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 }
 };
 
@@ -9836,6 +9839,19 @@  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 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/c-parser.c gcc/gcc/c/c-parser.c
index fe0c95f..9f7fa53 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;
@@ -1618,6 +1621,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
@@ -1749,6 +1754,14 @@  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
+	       && is_attribute_p ("fallthrough",
+				  get_attribute_name (specs->attrs)))
+	{
+	  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
@@ -4967,6 +4980,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;
@@ -5013,6 +5031,10 @@  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;
       if (c_parser_next_tokens_start_declaration (parser))
 	{
 	  error_at (c_parser_peek_token (parser)->location,
@@ -5066,6 +5088,9 @@  c_parser_label (c_parser *parser)
    jump-statement:
      goto * expression ;
 
+   expression-statement:
+     attributes ;
+
    Objective-C:
 
    statement:
@@ -5327,6 +5352,27 @@  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 (attrs != NULL_TREE
+		&& is_attribute_p ("fallthrough", get_attribute_name (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 used");
+	    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 fd1ac87..d87b8fe 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 5d97a4b..da35ac8 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:
@@ -4838,6 +4839,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 d54cf8a..45e2de5 100644
--- gcc/gcc/cp/parser.c
+++ gcc/gcc/cp/parser.c
@@ -5135,6 +5135,31 @@  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 (attr != NULL_TREE
+		&& is_attribute_p ("fallthrough", get_attribute_name (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 used");
+		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,15 +10610,26 @@  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
+	  && is_attribute_p ("fallthrough", get_attribute_name (std_attrs))
+	  && statement == NULL_TREE)
+	{
+	  tree fn = build_call_expr_internal_loc (statement_location,
+						  IFN_FALLTHROUGH,
+						  void_type_node, 0);
+	  finish_expr_stmt (fn);
+	}
     }
 
   /* 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.  */
-  if (std_attrs != NULL_TREE)
+  /* Allow "[[fallthrough]];", but warn otherwise.  */
+  if (std_attrs != NULL_TREE
+      && !is_attribute_p ("fallthrough", get_attribute_name (std_attrs)))
     warning_at (attrs_location,
 		OPT_Wattributes,
 		"attributes at the beginning of statement are ignored");
@@ -10628,6 +10664,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 +10699,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 +10716,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 +10728,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;
     }
 
@@ -24114,6 +24164,16 @@  cp_parser_std_attribute (cp_parser *parser)
 		     " use %<gnu::deprecated%>");
 	  TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
 	}
+      /* C++17 fallthrough attribute is equivalent to GNU's.  */
+      else if (cxx_dialect >= cxx11
+	       && 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))
@@ -24172,11 +24232,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 b0f0664..60c5d43 100644
--- gcc/gcc/cp/pt.c
+++ gcc/gcc/cp/pt.c
@@ -16556,7 +16556,9 @@  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)
+	  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 +22789,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 8cb93ab..0aee327 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 87da1f1..693ef51 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
@@ -3667,6 +3667,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
@@ -3953,6 +3954,91 @@  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 of a 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.
+
+@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 4715332..9bbc399 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,413 @@  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));
+	return last_stmt_in_scope (stmt);
+      }
+
+    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;
+	}
+
+      /* If's are tricky.  */
+      if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_COND)
+	{
+	  gcond *cond_stmt = as_a <gcond *> (gsi_stmt (*gsi_p));
+	  tree false_lab = gimple_cond_false_label (cond_stmt);
+	  location_t if_loc = gimple_location (cond_stmt);
+
+	  /* If we have e.g.
+	       if (i > 1) goto <D.2259>; else goto D;
+	     we can't do much with the else-branch.  */
+	  if (!DECL_ARTIFICIAL (false_lab))
+	    break;
+
+	  /* Go on until the false label, then one step back.  */
+	  for (; !gsi_end_p (*gsi_p); gsi_next (gsi_p))
+	    {
+	      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)
+	      {
+		/* Suggestion one: add attribute fallthrough.  */
+		rich_location rloc_attr (line_table, gimple_location (next));
+		/* For C++17, we'd recommend [[fallthrough]];, but we're not
+		   there yet.  For C++11, recommend [[gnu::fallthrough]];.  */
+		if (strncmp (lang_hooks.name, "GNU C++14", 9) == 0
+		    || strncmp (lang_hooks.name, "GNU C++11", 9) == 0)
+		  {
+		    rloc_attr.add_fixit_insert (gimple_location (next),
+						"[[gnu::fallthrough]];");
+		    inform_at_rich_loc (&rloc_attr,
+					"insert %qs to silence this warning",
+					"[[gnu::fallthrough]];");
+		  }
+		else
+		  {
+		    /* Otherwise, recommend __attribute__ ((fallthrough));.  */
+		    rloc_attr.add_fixit_insert (gimple_location (next),
+						"__attribute__ "
+						"((fallthrough));");
+		    inform_at_rich_loc (&rloc_attr,
+					"insert %qs to silence this warning",
+					"__attribute__ ((fallthrough));");
+		  }
+		/* Suggestion two: add "break;".  */
+		rich_location rloc_break (line_table, gimple_location (next));
+		rloc_break.add_fixit_insert (gimple_location (next), "break;");
+		inform_at_rich_loc (&rloc_break,
+				    "insert %qs to avoid fall-through",
+				    "break;");
+	      }
+
+	    /* 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;
+	  else if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL
+		   || (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_GOTO
+		       && !gimple_has_location (gsi_stmt (*gsi_p))))
+	    /* This usage is OK.  */;
+	  else
+	    warning_at (gimple_location (stmt), 0,
+			"%<__attribute__ ((fallthrough))%> not preceding "
+			"a label");
+	}
+      break;
+    default:
+      break;
+    }
+  return NULL_TREE;
+}
+
+/* Expand all FALLTHROUGH () calls in SEQ.  */
+
+static void
+expand_FALLTHROUGH (gimple_seq *seq_p)
+{
+  struct walk_stmt_info wi;
+  memset (&wi, 0, sizeof (wi));
+  walk_gimple_seq_mod (seq_p, expand_FALLTHROUGH_r, NULL, &wi);
+}
+
 
 /* Gimplify a SWITCH_EXPR, and collect the vector of labels it can
    branch to.  */
@@ -1660,10 +2068,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 innermost 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 +2109,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 +2141,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);
 
@@ -10746,11 +11177,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 cd4b625..8b10076 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 3256a9d..c12fdc9 100644
--- gcc/gcc/langhooks.c
+++ gcc/gcc/langhooks.c
@@ -717,3 +717,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 44c258e..157300e 100644
--- gcc/gcc/langhooks.h
+++ gcc/gcc/langhooks.h
@@ -537,5 +537,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-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..31c52d7 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:
+      {
+	int a[i]; /* { dg-warning "statement may fall through" } */
+      }
+    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..12aebc2 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));
+    __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..44f449c 100644
--- gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
+++ gcc/gcc/testsuite/c-c++-common/attr-fallthrough-2.c
@@ -0,0 +1,47 @@ 
+/* 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 a label" "" { 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")));
+  case 7:
+    bar (1);
+    __attribute__((fallthrough, fallthrough));
+  case 8:
+    bar (1);
+    __attribute__((fallthrough));
+  case 9:
+    __attribute__((fallthrough)); /* { dg-error "label" "" { target c } } */
+    /* { dg-warning "not preceding a label" "" { target *-*-* } 41 } */
+    bar (1);
+  default:
+    bar (99);
+  }
+}
diff --git gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C gcc/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C
index e69de29..e1f2d9e 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]];
+    [[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/g++.dg/warn/Wimplicit-fallthrough-1.C gcc/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-1.C
index e69de29..9988801 100644
--- gcc/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-1.C
+++ gcc/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-1.C
@@ -0,0 +1,33 @@ 
+/* PR c/7652 */
+/* { dg-do compile { target { ! c++11 } } } */
+/* { dg-options "-Wimplicit-fallthrough -fdiagnostics-show-caret" } */
+
+/* Test fixit notes.  */
+
+extern int bar (int);
+
+void
+fn (int i)
+{
+  switch (i)
+  {
+  case 0:
+    bar (0);
+/* { dg-warning "this statement may fall through" "" { target *-*-* } 15 } */
+/*
+{ dg-begin-multiline-output "" }
+     bar (0);
+            ^
+   case 1:
+   ^~~~
+   __attribute__ ((fallthrough));
+   case 1:
+   ^~~~
+   break;
+{ dg-end-multiline-output "" }
+*/
+  case 1:
+    bar (1);
+    break;
+  }
+}
diff --git gcc/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C gcc/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C
index e69de29..61262da 100644
--- gcc/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C
+++ gcc/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C
@@ -0,0 +1,33 @@ 
+/* PR c/7652 */
+/* { dg-do compile { target { c++11 } } } */
+/* { dg-options "-Wimplicit-fallthrough -fdiagnostics-show-caret" } */
+
+/* Test fixit notes.  */
+
+extern int bar (int);
+
+void
+fn (int i)
+{
+  switch (i)
+  {
+  case 0:
+    bar (0);
+/* { dg-warning "this statement may fall through" "" { target *-*-* } 15 } */
+/*
+{ dg-begin-multiline-output "" }
+     bar (0);
+            ^
+   case 1:
+   ^~~~
+   [[gnu::fallthrough]];
+   case 1:
+   ^~~~
+   break;
+{ dg-end-multiline-output "" }
+*/
+  case 1:
+    bar (1);
+    break;
+  }
+}
diff --git gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
index e69de29..355a774 100644
--- gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
+++ gcc/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c
@@ -0,0 +1,33 @@ 
+/* PR c/7652 */
+/* { dg-do compile } */
+/* { dg-options "-Wimplicit-fallthrough -fdiagnostics-show-caret" } */
+
+/* Test fixit notes.  */
+
+extern int bar (int);
+
+void
+fn (int i)
+{
+  switch (i)
+  {
+  case 0:
+    bar (0);
+/* { dg-warning "this statement may fall through" "" { target *-*-* } 15 } */
+/*
+{ dg-begin-multiline-output "" }
+     bar (0);
+     ^~~~~~~
+   case 1:
+   ^~~~
+   __attribute__ ((fallthrough));
+   case 1:
+   ^~~~
+   break;
+{ dg-end-multiline-output "" }
+*/
+  case 1:
+    bar (1);
+    break;
+  }
+}
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;