Hi! The following patch does a few things: 1) fixes -Wimplicit-fallthrough -C (with -C the PREV_FALLTHROUGH flag is on the CPP_COMMENT token, we need to propagate it to the C/C++ token's flags in the FEs) 2) it accepts a comment in between /* FALLTHRU */ comment and the case/default keyword or user label, people often write: ... /* FALLTHRU */
/* Rationale or description of what the following code does. */ case ...: and forcing users to move their comments after the labels or after the first label might be too annoying 3) it adds support for some common FALLTHRU comment styles that appeared in GCC sources, or in Linux kernel etc., e.g.: /*lint -fallthrough */ /* ... falls through ... */ /* else fall-through */ /* Intentional fall through. */ /* FALLTHRU - some explanation why. */ 4) it attempts to precisely document what is supported in the documentation 5) some libcpp fixes in the fallthrough_comment_p routine, in particular some even previously documented coment styles could be rejected in C++ style comments if there wasn't any whitespace after them 6) testcase covering various forms Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-09-29 Jakub Jelinek <ja...@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): Extend to handle more common FALLTHRU comment styles. (_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-27 09:46:07.000000000 +0200 +++ gcc/c-family/c-lex.c 2016-09-29 12:11:30.633532650 +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-27 09:46:07.000000000 +0200 +++ gcc/doc/invoke.texi 2016-09-29 13:19:41.046697347 +0200 @@ -4156,10 +4156,28 @@ 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{lint -fallthrough ?} + +@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.!]*([Ee]lse |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?} + +@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-26 12:06:49.000000000 +0200 +++ libcpp/lex.c 2016-09-29 13:54:12.703757398 +0200 @@ -2059,41 +2059,102 @@ fallthrough_comment_p (cpp_reader *pfile 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]* + 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 "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 (all_upper) + return false; 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)) @@ -2102,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 == '*') @@ -2398,7 +2477,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 +2506,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 +2615,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 +2702,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-29 12:13:39.648906685 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-22.c 2016-09-29 14:23:00.782386042 +0200 @@ -0,0 +1,231 @@ +/* { 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 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 ... */ + /* 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*/ + case 16: + bar (16); + break; + case 17: + bar (17); /* { dg-bogus "this statement may \[laf]* through" } */ + /*@fallthrough@*/ + 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*/ + 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 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 ... + // 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 + case 16: + bar (16); + break; + case 17: + bar (17); /* { dg-bogus "this statement may \[laf]* through" } */ + //@fallthrough@ + 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 + 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-29 12:16:28.848774281 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-23.c 2016-09-29 12:16:50.750498256 +0200 @@ -0,0 +1,4 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough -C" } */ + +#include "Wimplicit-fallthrough-22.c" Jakub