diff mbox

Fix -Wimplicit-fallthrough -C, handle some more comment styles and comments in between FALLTHRU comment and label

Message ID 20160930200557.GG7282@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Sept. 30, 2016, 8:05 p.m. UTC
On Fri, Sep 30, 2016 at 11:26:27AM +0200, Marek Polacek wrote:
> I haven't gone over the patch in detail yet, but I wonder if we should
> also accept /* Else, fall through.  */ (to be found e.g. in aarch64-simd.md).

Here is the patch split into a series of 3 patches (the later patches depend
on the earlier ones):
1) the first patch fixes some bugs and fixes also -Wimplicit-fallthrough -C
2) the second patch adds the else and intentional/ly etc.
3) the third one adds the optional comma between else and fall

Bootstrapped/regtested on x86_64-linux and i686-linux, ok?

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

	* c-lex.c (c_lex_with_flags) <case CPP_COMMENT>: For CPP_COMMENT
	token with PREV_FALLTHROUGH, skip all following CPP_PADDING and
	CPP_COMMENT tokens and set add_flags to PREV_FALLTHROUGH afterwards.

	* doc/invoke.texi (-Wimplicit-fallthrough): Document the accepted
	FALLTHRU comment styles.

	* lex.c (fallthrough_comment_p): Fix off-by-one size comparison
	errors, cleanup.
	(_cpp_lex_direct): Allow arbitrary comments in between
	fallthrough_comment_p comment and following token.

	* c-c++-common/Wimplicit-fallthrough-22.c: New test.
	* c-c++-common/Wimplicit-fallthrough-23.c: New test.
2016-09-30  Jakub Jelinek  <jakub@redhat.com>

	* doc/invoke.texi (-Wimplicit-fallthrough): Document FALLTHRU comment
	style changes.

	* lex.c (fallthrough_comment_p): Extend to handle more common FALLTHRU
	comment styles.

	* c-c++-common/Wimplicit-fallthrough-22.c (foo): Add further tests.

--- gcc/doc/invoke.texi.jj	2016-09-30 17:21:11.743575991 +0200
+++ gcc/doc/invoke.texi	2016-09-30 17:39:41.838766235 +0200
@@ -4166,11 +4166,13 @@ should match one of the following regula
 
 @item @code{@@fallthrough@@}
 
-@item @code{[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*}
+@item @code{lint -fallthrough ?}
 
-@item @code{[ \t]*Fall((s | |-)[Tt]|t)hr(ough|u)\.?[ \t]*}
+@item @code{[ \t.!]*(ELSE |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?}
 
-@item @code{[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*}
+@item @code{[ \t.!]*(Else |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?}
+
+@item @code{[ \t.!]*([Ee]lse |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?}
 
 @end itemize
 
--- libcpp/lex.c.jj	2016-09-30 17:20:46.959884436 +0200
+++ libcpp/lex.c	2016-09-30 17:39:38.854803331 +0200
@@ -2059,22 +2059,86 @@ fallthrough_comment_p (cpp_reader *pfile
       from += 1 + len;
     }
   /* Whole comment contents (regex):
-     [ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*
-     [ \t]*Fall((s | |-)[Tt]|t)hr(ough|u)\.?[ \t]*
-     [ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*
+     lint -fallthrough ?
+   */
+  else if (*from == 'l')
+    {
+      size_t len = sizeof "int -fallthrough" - 1;
+      if ((size_t) (pfile->buffer->cur - from - 1) < len)
+	return false;
+      if (memcmp (from + 1, "int -fallthrough", len))
+        return false;
+      from += 1 + len;
+      if (*from == ' ')
+        from++;
+    }
+  /* Whole comment contents (regex):
+     [ \t.!]*(ELSE |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?
+     [ \t.!]*(Else |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?
+     [ \t.!]*([Ee]lse |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?
    */
   else
     {
-      while (*from == ' ' || *from == '\t')
+      while (*from == ' ' || *from == '\t' || *from == '.' || *from == '!')
 	from++;
       unsigned char f = *from;
+      bool all_upper = false;
+      if (f == 'E' || f == 'e')
+        {
+          if ((size_t) (pfile->buffer->cur - from)
+	      < sizeof "else fallthru" - 1)
+	    return false;
+	  if (f == 'E' && memcmp (from + 1, "LSE F", sizeof "LSE F" - 1) == 0)
+	    all_upper = true;
+	  else if (memcmp (from + 1, "lse ", sizeof "lse " - 1))
+	    return false;
+	  from += sizeof "else " - 1;
+	  if (f == 'e' && *from == 'F')
+	    return false;
+	  f = *from;
+        }
+      else if (f == 'I' || f == 'i')
+        {
+          if ((size_t) (pfile->buffer->cur - from)
+	      < sizeof "intentional fallthru" - 1)
+	    return false;
+	  if (f == 'I' && memcmp (from + 1, "NTENTIONAL",
+				  sizeof "NTENTIONAL" - 1) == 0)
+	    all_upper = true;
+	  else if (memcmp (from + 1, "ntentional",
+			   sizeof "ntentional" - 1))
+	    return false;
+	  from += sizeof "intentional" - 1;
+	  if (*from == ' ')
+	    {
+	      from++;
+	      if (all_upper && *from == 'f')
+		return false;
+	    }
+	  else if (all_upper)
+	    {
+	      if (memcmp (from, "LY F", sizeof "LY F" - 1))
+		return false;
+	      from += sizeof "LY " - 1;
+	    }
+	  else
+	    {
+	      if (memcmp (from, "ly ", sizeof "ly " - 1))
+		return false;
+	      from += sizeof "ly " - 1;
+	    }
+	  if (f == 'i' && *from == 'F')
+	    return false;
+	  f = *from;
+        }
       if (f != 'F' && f != 'f')
 	return false;
       if ((size_t) (pfile->buffer->cur - from) < sizeof "fallthru" - 1)
 	return false;
-      bool all_upper = false;
       if (f == 'F' && memcmp (from + 1, "ALL", sizeof "ALL" - 1) == 0)
 	all_upper = true;
+      else if (all_upper)
+	return false;
       else if (memcmp (from + 1, "all", sizeof "all" - 1))
 	return false;
       from += sizeof "fall" - 1;
@@ -2099,10 +2163,28 @@ fallthrough_comment_p (cpp_reader *pfile
 	}
       else
 	from += sizeof "thru" - 1;
-      if (*from == '.')
-	from++;
-      while (*from == ' ' || *from == '\t')
+      while (*from == ' ' || *from == '\t' || *from == '.' || *from == '!')
 	from++;
+      if (*from == '-')
+	{
+	  from++;
+	  if (*comment_start == '*')
+	    {
+	      do
+		{
+		  while (*from && *from != '*'
+			 && *from != '\n' && *from != '\r')
+		    from++;
+		  if (*from != '*' || from[1] == '/')
+		    break;
+		  from++;
+		}
+	      while (1);
+	    }
+	  else
+	    while (*from && *from != '\n' && *from != '\r')
+	      from++;
+	}
     }
   /* C block comment.  */
   if (*comment_start == '*')
--- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-22.c.jj	2016-09-30 17:35:47.908674464 +0200
+++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-22.c	2016-09-30 17:39:41.833766297 +0200
@@ -21,15 +21,39 @@ foo (int i)
     case 4:
       bar (4);
       break;
+    case 5:
+      bar (5);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* Else Fall-Thru!  */
+    case 6:
+      bar (6);
+      break;
     case 7:
       bar (7);			/* { dg-bogus "this statement may \[laf]* through" } */
       /* Some comment.  */
-      /* fallthrough.  */
+      /* ... fallthrough ...  */
       /* Some other comment.  */
       /* And yet another.  */
     case 8:
       bar (8);
       break;
+    case 9:
+      bar (9);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* Intentional Fallthru */
+    case 10:
+      bar (10);
+      break;
+    case 11:
+      bar (11);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* intentionally fall through  */
+    case 12:
+      bar (12);
+      break;
+    case 13:
+      bar (13);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* Falls Through - for reasons known only to the author.  */
+    case 14:
+      bar (14);
+      break;
     case 15:
       bar (15);			/* { dg-bogus "this statement may \[laf]* through" } */
       /*-fallthrough*/
@@ -42,12 +66,42 @@ foo (int i)
     case 18:
       bar (18);
       break;
+    case 19:
+      bar (19);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*lint -fallthrough*/
+    case 20:
+      bar (20);
+      break;
+    case 21:
+      bar (21);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*lint -fallthrough */
+    case 22:
+      bar (22);
+      break;
     case 23:
       bar (23);			/* { dg-bogus "this statement may \[laf]* through" } */
       /*fallthru*/
     case 24:
       bar (24);
       break;
+    case 25:
+      bar (25);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*Else fallthru*/
+    case 26:
+      bar (26);
+      break;
+    case 27:
+      bar (27);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*Intentional fallthru*/
+    case 28:
+      bar (28);
+      break;
+    case 29:
+      bar (29);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*Intentionally fallthru*/
+    case 30:
+      bar (30);
+      break;
     case 31:
       bar (31);			/* { dg-bogus "this statement may \[laf]* through" } */
       /*Falls thru*/
@@ -78,15 +132,39 @@ foo (int i)
     case 4:
       bar (4);
       break;
+    case 5:
+      bar (5);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // Else Fall-Thru!
+    case 6:
+      bar (6);
+      break;
     case 7:
       bar (7);			/* { dg-bogus "this statement may \[laf]* through" } */
       // Some comment.
-      // fallthrough
+      // ... fallthrough ...
       // Some other comment.
       // And yet another.
     case 8:
       bar (8);
       break;
+    case 9:
+      bar (9);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // Intentional Fallthru
+    case 10:
+      bar (10);
+      break;
+    case 11:
+      bar (11);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // intentionally fall through 
+    case 12:
+      bar (12);
+      break;
+    case 13:
+      bar (13);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // Falls Through - for reasons known only to the author.
+    case 14:
+      bar (14);
+      break;
     case 15:
       bar (15);			/* { dg-bogus "this statement may \[laf]* through" } */
       //-fallthrough
@@ -99,12 +177,42 @@ foo (int i)
     case 18:
       bar (18);
       break;
+    case 19:
+      bar (19);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //lint -fallthrough
+    case 20:
+      bar (20);
+      break;
+    case 21:
+      bar (21);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //lint -fallthrough 
+    case 22:
+      bar (22);
+      break;
     case 23:
       bar (23);			/* { dg-bogus "this statement may \[laf]* through" } */
       //fallthru
     case 24:
       bar (24);
       break;
+    case 25:
+      bar (25);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //Else fallthru
+    case 26:
+      bar (26);
+      break;
+    case 27:
+      bar (27);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //Intentional fallthru
+    case 28:
+      bar (28);
+      break;
+    case 29:
+      bar (29);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //Intentionally fallthru
+    case 30:
+      bar (30);
+      break;
     case 31:
       bar (31);			/* { dg-bogus "this statement may \[laf]* through" } */
       //Falls thru
2016-09-30  Jakub Jelinek  <jakub@redhat.com>

	* doc/invoke.texi: Document accepting Else, fallthrough.

	* lex.c (fallthrough_comment_p): Accept Else, fallthrough.

	* c-c++-common/Wimplicit-fallthrough-22.c (foo): Add further tests.

--- gcc/doc/invoke.texi.jj	2016-09-30 17:09:37.170216652 +0200
+++ gcc/doc/invoke.texi	2016-09-30 16:27:10.565840611 +0200
@@ -4168,11 +4168,11 @@ should match one of the following regula
 
 @item @code{lint -fallthrough ?}
 
-@item @code{[ \t.!]*(ELSE |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?}
+@item @code{[ \t.!]*(ELSE,? |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?}
 
-@item @code{[ \t.!]*(Else |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?}
+@item @code{[ \t.!]*(Else,? |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?}
 
-@item @code{[ \t.!]*([Ee]lse |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?}
+@item @code{[ \t.!]*([Ee]lse,? |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?}
 
 @end itemize
 
--- libcpp/lex.c.jj	2016-09-30 17:09:37.171216639 +0200
+++ libcpp/lex.c	2016-09-30 16:30:52.048091615 +0200
@@ -2073,9 +2073,9 @@ fallthrough_comment_p (cpp_reader *pfile
         from++;
     }
   /* Whole comment contents (regex):
-     [ \t.!]*(ELSE |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?
-     [ \t.!]*(Else |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?
-     [ \t.!]*([Ee]lse |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?
+     [ \t.!]*(ELSE,? |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?
+     [ \t.!]*(Else,? |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?
+     [ \t.!]*([Ee]lse,? |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?
    */
   else
     {
@@ -2088,11 +2088,18 @@ fallthrough_comment_p (cpp_reader *pfile
           if ((size_t) (pfile->buffer->cur - from)
 	      < sizeof "else fallthru" - 1)
 	    return false;
-	  if (f == 'E' && memcmp (from + 1, "LSE F", sizeof "LSE F" - 1) == 0)
+	  if (f == 'E' && memcmp (from + 1, "LSE", sizeof "LSE" - 1) == 0)
 	    all_upper = true;
-	  else if (memcmp (from + 1, "lse ", sizeof "lse " - 1))
+	  else if (memcmp (from + 1, "lse", sizeof "lse" - 1))
+	    return false;
+	  from += sizeof "else" - 1;
+	  if (*from == ',')
+	    from++;
+          if (*from != ' ')
+	    return false;
+	  from++;
+	  if (all_upper && *from == 'f')
 	    return false;
-	  from += sizeof "else " - 1;
 	  if (f == 'e' && *from == 'F')
 	    return false;
 	  f = *from;
--- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-22.c.jj	2016-09-30 17:09:37.172216627 +0200
+++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-22.c	2016-09-30 16:32:20.866989186 +0200
@@ -114,6 +114,12 @@ foo (int i)
     case 34:
       bar (34);
       break;
+    case 35:
+      bar (35);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* Else, fall-through. */
+    case 36:
+      bar (36);
+      break;
     default:
       break;
     }
@@ -225,6 +231,12 @@ foo (int i)
     case 34:
       bar (34);
       break;
+    case 35:
+      bar (35);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // Else, fall-through
+    case 36:
+      bar (36);
+      break;
     default:
       break;
     }

Comments

Marek Polacek Oct. 8, 2016, 9:37 a.m. UTC | #1
On Fri, Sep 30, 2016 at 10:05:57PM +0200, Jakub Jelinek wrote:
> On Fri, Sep 30, 2016 at 11:26:27AM +0200, Marek Polacek wrote:
> > I haven't gone over the patch in detail yet, but I wonder if we should
> > also accept /* Else, fall through.  */ (to be found e.g. in aarch64-simd.md).
> 
> Here is the patch split into a series of 3 patches (the later patches depend
> on the earlier ones):
> 1) the first patch fixes some bugs and fixes also -Wimplicit-fallthrough -C
> 2) the second patch adds the else and intentional/ly etc.
> 3) the third one adds the optional comma between else and fall
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok?
> 
> 	Jakub

> 2016-09-30  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* c-lex.c (c_lex_with_flags) <case CPP_COMMENT>: For CPP_COMMENT
> 	token with PREV_FALLTHROUGH, skip all following CPP_PADDING and
> 	CPP_COMMENT tokens and set add_flags to PREV_FALLTHROUGH afterwards.
> 
> 	* doc/invoke.texi (-Wimplicit-fallthrough): Document the accepted
> 	FALLTHRU comment styles.
> 
> 	* lex.c (fallthrough_comment_p): Fix off-by-one size comparison
> 	errors, cleanup.
> 	(_cpp_lex_direct): Allow arbitrary comments in between
> 	fallthrough_comment_p comment and following token.
> 
> 	* c-c++-common/Wimplicit-fallthrough-22.c: New test.
> 	* c-c++-common/Wimplicit-fallthrough-23.c: New test.
> 
> --- gcc/c-family/c-lex.c.jj	2016-09-30 18:16:26.303336781 +0200
> +++ gcc/c-family/c-lex.c	2016-09-30 18:26:14.650999215 +0200
> @@ -598,7 +598,18 @@ c_lex_with_flags (tree *value, location_
>  
>      /* CPP_COMMENT will appear when compiling with -C and should be
>         ignored.  */
> -     case CPP_COMMENT:
> +    case CPP_COMMENT:
> +      if (tok->flags & PREV_FALLTHROUGH)
> +	{
> +	  do
> +	    {
> +	      tok = cpp_get_token_with_location (parse_in, loc);
> +	      type = tok->type;
> +	    }
> +	  while (type == CPP_PADDING || type == CPP_COMMENT);
> +	  add_flags = PREV_FALLTHROUGH;

Wouldn't |= be safer?

> +	  goto retry_after_at;
> +	}

And the comment is not really true anymore; I think let's say that we
want to set PREV_FALLTHROUGH on the token following the comment.

Otherwise I'm ok with the first patch, just please rename the 
-22 test to -24, since I've added -22.c and -23.c.

	Marek
diff mbox

Patch

--- gcc/c-family/c-lex.c.jj	2016-09-30 18:16:26.303336781 +0200
+++ gcc/c-family/c-lex.c	2016-09-30 18:26:14.650999215 +0200
@@ -598,7 +598,18 @@  c_lex_with_flags (tree *value, location_
 
     /* CPP_COMMENT will appear when compiling with -C and should be
        ignored.  */
-     case CPP_COMMENT:
+    case CPP_COMMENT:
+      if (tok->flags & PREV_FALLTHROUGH)
+	{
+	  do
+	    {
+	      tok = cpp_get_token_with_location (parse_in, loc);
+	      type = tok->type;
+	    }
+	  while (type == CPP_PADDING || type == CPP_COMMENT);
+	  add_flags = PREV_FALLTHROUGH;
+	  goto retry_after_at;
+	}
        goto retry;
 
     default:
--- gcc/doc/invoke.texi.jj	2016-09-30 18:16:26.308336719 +0200
+++ gcc/doc/invoke.texi	2016-09-30 18:26:33.288766793 +0200
@@ -4157,10 +4157,26 @@  C++17 provides a standard way to suppres
 warning using @code{[[fallthrough]];} instead of the GNU attribute.  In C++11
 or C++14 users can use @code{[[gnu::fallthrough]];}, which is a GNU extension.
 Instead of the these attributes, it is also possible to add a "falls through"
-comment to silence the warning.  GCC accepts a wide range of such comments,
-for example all of "Falls through.", "fallthru", "FALLS-THROUGH" work.  This
-comment needs to consist of two words merely, optionally followed by periods
-or whitespaces.
+comment to silence the warning.  The whole body of the C or C++ style comment
+should match one of the following regular expressions:
+
+@itemize @bullet
+
+@item @code{-fallthrough}
+
+@item @code{@@fallthrough@@}
+
+@item @code{[ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*}
+
+@item @code{[ \t]*Fall((s | |-)[Tt]|t)hr(ough|u)\.?[ \t]*}
+
+@item @code{[ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*}
+
+@end itemize
+
+and the comment needs to be followed after optional whitespace and other comments
+by @code{case} or @code{default} keywords or by a user label that preceeds some
+@code{case} or @code{default} label.
 
 @smallexample
 @group
--- libcpp/lex.c.jj	2016-09-30 18:16:22.987378137 +0200
+++ libcpp/lex.c	2016-09-30 18:26:33.289766781 +0200
@@ -2060,7 +2060,7 @@  fallthrough_comment_p (cpp_reader *pfile
     }
   /* Whole comment contents (regex):
      [ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]*
-     [ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]*
+     [ \t]*Fall((s | |-)[Tt]|t)hr(ough|u)\.?[ \t]*
      [ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]*
    */
   else
@@ -2070,30 +2070,27 @@  fallthrough_comment_p (cpp_reader *pfile
       unsigned char f = *from;
       if (f != 'F' && f != 'f')
 	return false;
-      if ((size_t) (pfile->buffer->cur - from) < sizeof "fallthrough")
+      if ((size_t) (pfile->buffer->cur - from) < sizeof "fallthru" - 1)
 	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'))
+      from += sizeof "fall" - 1;
+      if (*from == (all_upper ? 'S' : 's') && from[1] == ' ')
+	from += 2;
+      else if (*from == ' ' || *from == '-')
+	from++;
+      else if (*from != (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")
+      if ((size_t) (pfile->buffer->cur - from) < sizeof "thru" - 1)
 	return false;
       if (memcmp (from + 1, all_upper ? "HRU" : "hru", sizeof "hru" - 1))
 	{
-	  if ((size_t) (pfile->buffer->cur - from) < sizeof "through")
+	  if ((size_t) (pfile->buffer->cur - from) < sizeof "through" - 1)
 	    return false;
 	  if (memcmp (from + 1, all_upper ? "HROUGH" : "hrough",
 		      sizeof "hrough" - 1))
@@ -2398,7 +2395,8 @@  _cpp_lex_direct (cpp_reader *pfile)
 {
   cppchar_t c;
   cpp_buffer *buffer;
-  const unsigned char *comment_start = NULL;
+  const unsigned char *comment_start;
+  bool fallthrough_comment = false;
   cpp_token *result = pfile->cur_token++;
 
  fresh_line:
@@ -2426,7 +2424,7 @@  _cpp_lex_direct (cpp_reader *pfile)
 	  return result;
 	}
       if (buffer != pfile->buffer)
-	comment_start = NULL;
+	fallthrough_comment = false;
       if (!pfile->keep_tokens)
 	{
 	  pfile->cur_run = &pfile->base_run;
@@ -2535,8 +2533,7 @@  _cpp_lex_direct (cpp_reader *pfile)
 	}
 
       /* Signal FALLTHROUGH comment followed by another token.  */
-      if (comment_start
-	  && fallthrough_comment_p (pfile, comment_start))
+      if (fallthrough_comment)
 	result->flags |= PREV_FALLTHROUGH;
       break;
 
@@ -2623,13 +2620,16 @@  _cpp_lex_direct (cpp_reader *pfile)
 	  break;
 	}
 
+      if (fallthrough_comment_p (pfile, comment_start))
+	fallthrough_comment = true;
+
       if (!pfile->state.save_comments)
 	{
 	  result->flags |= PREV_WHITE;
 	  goto update_tokens_line;
 	}
 
-      if (fallthrough_comment_p (pfile, comment_start))
+      if (fallthrough_comment)
 	result->flags |= PREV_FALLTHROUGH;
 
       /* Save the comment as a token in its own right.  */
--- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-22.c.jj	2016-09-30 18:16:26.293336906 +0200
+++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-22.c	2016-09-30 18:26:33.289766781 +0200
@@ -0,0 +1,123 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wimplicit-fallthrough" } */
+
+void bar (int);
+
+void
+foo (int i)
+{
+  switch (i)
+    {
+    case 1:
+      bar (1);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* FALLTHROUGH */
+    case 2:
+      bar (2);
+      break;
+    case 3:
+      bar (3);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* FALLS THRU.  */
+      /* Some other comment.  */
+    case 4:
+      bar (4);
+      break;
+    case 7:
+      bar (7);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /* Some comment.  */
+      /* fallthrough.  */
+      /* Some other comment.  */
+      /* And yet another.  */
+    case 8:
+      bar (8);
+      break;
+    case 15:
+      bar (15);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*-fallthrough*/
+    case 16:
+      bar (16);
+      break;
+    case 17:
+      bar (17);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*@fallthrough@*/
+    case 18:
+      bar (18);
+      break;
+    case 23:
+      bar (23);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*fallthru*/
+    case 24:
+      bar (24);
+      break;
+    case 31:
+      bar (31);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*Falls thru*/
+    case 32:
+      bar (32);
+      break;
+    case 33:
+      bar (33);			/* { dg-bogus "this statement may \[laf]* through" } */
+      /*Fall-through*/
+    case 34:
+      bar (34);
+      break;
+    default:
+      break;
+    }
+  switch (i)
+    {
+    case 1:
+      bar (1);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // FALLTHROUGH
+    case 2:
+      bar (2);
+      break;
+    case 3:
+      bar (3);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // FALLS THRU.  
+      // Some other comment.
+    case 4:
+      bar (4);
+      break;
+    case 7:
+      bar (7);			/* { dg-bogus "this statement may \[laf]* through" } */
+      // Some comment.
+      // fallthrough
+      // Some other comment.
+      // And yet another.
+    case 8:
+      bar (8);
+      break;
+    case 15:
+      bar (15);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //-fallthrough
+    case 16:
+      bar (16);
+      break;
+    case 17:
+      bar (17);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //@fallthrough@
+    case 18:
+      bar (18);
+      break;
+    case 23:
+      bar (23);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //fallthru
+    case 24:
+      bar (24);
+      break;
+    case 31:
+      bar (31);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //Falls thru
+    case 32:
+      bar (32);
+      break;
+    case 33:
+      bar (33);			/* { dg-bogus "this statement may \[laf]* through" } */
+      //Fall-through
+    case 34:
+      bar (34);
+      break;
+    default:
+      break;
+    }
+}
--- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-23.c.jj	2016-09-30 18:16:26.298336844 +0200
+++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-23.c	2016-09-30 18:26:14.659999103 +0200
@@ -0,0 +1,4 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wimplicit-fallthrough -C" } */
+
+#include "Wimplicit-fallthrough-22.c"