Hi! The following patch introduces difference warning levels for -Wimplicit-fallthrough warning, so projects can choose if they want to honor only attributes (-Wimplicit-fallthrough=5), or what kind of comments. =4 is very picky and accepts only very small amount of comments, =3 is what we had before this patch, =2 looks case insensitively for falls?[ \t-]*thr(u|ough) anywhere in the comment, =1 accepts any comment, =0 is the same as -Wno-implicit-fallthrough - disables the warning.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? The patch keeps as the default the current forms, I'm not against changing it to =2 if there is consensus on it, but would strongly prefer doing that incrementally, as e.g. we'll need to adjust the testsuite for that, and perhaps also use =3 as the warning for gcc bootstraps when we are already =3 mode clear. 2016-10-11 Jakub Jelinek <ja...@redhat.com> gcc/ * common.opt (Wimplicit-fallthrough) Turn into alias to -Wimplicit-fallthrough=3. Remove EnabledBy. (Wimplicit-fallthrough=): New option. * gimplify.c (warn_implicit_fallthrough_r): Use OPT_Wimplicit_fallthrough_ instead of OPT_Wimplicit_fallthrough. * doc/invoke.texi (-Wimplicit-fallthrough): Document as alias to -Wimplicit-fallthrough=3. (-Wimplicit-fallthrough=): Document. gcc/c-family/ * c.opt (Wextra): Add as C/C++/ObjC/ObjC++ option. (Wimplicit-fallthrough=): Enable for these languages by -Wextra. * c-opts.c (sanitize_cpp_opts): Initialize cpp_opts->cpp_warn_implicit_fallthrough. gcc/testsuite/ * c-c++-common/Wimplicit-fallthrough-25.c: New test. * c-c++-common/Wimplicit-fallthrough-26.c: New test. * c-c++-common/Wimplicit-fallthrough-27.c: New test. * c-c++-common/Wimplicit-fallthrough-28.c: New test. * c-c++-common/Wimplicit-fallthrough-29.c: New test. * c-c++-common/Wimplicit-fallthrough-30.c: New test. * c-c++-common/Wimplicit-fallthrough-31.c: New test. * c-c++-common/Wimplicit-fallthrough-32.c: New test. * c-c++-common/Wimplicit-fallthrough-33.c: New test. libcpp/ * include/cpplib.h (struct cpp_options): Add cpp_warn_implicit_fallthrough. * init.c (cpp_create_reader): Initialize it to 0. * lex.c (fallthrough_comment_p): Handle different cpp_warn_implicit_fallthrough levels. Whitespace fixes. --- gcc/common.opt.jj 2016-10-01 00:44:48.000000000 +0200 +++ gcc/common.opt 2016-10-11 17:57:15.361670576 +0200 @@ -602,7 +602,10 @@ 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) +Common Alias(Wimplicit-fallthrough=,3,0) Warning + +Wimplicit-fallthrough= +Common Var(warn_implicit_fallthrough) RejectNegative Joined UInteger Warning Warn when a switch case falls through. Winline --- gcc/gimplify.c.jj 2016-10-09 13:19:09.000000000 +0200 +++ gcc/gimplify.c 2016-10-11 17:29:13.280800199 +0200 @@ -1918,7 +1918,7 @@ warn_implicit_fallthrough_r (gimple_stmt 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, + 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 @@ -1926,7 +1926,7 @@ warn_implicit_fallthrough_r (gimple_stmt && gimple_stmt_may_fallthru (prev) && gimple_has_location (prev)) warned_p = warning_at (gimple_location (prev), - OPT_Wimplicit_fallthrough, + OPT_Wimplicit_fallthrough_, "this statement may fall through"); if (warned_p) inform (gimple_location (next), "here"); --- gcc/doc/invoke.texi.jj 2016-10-09 13:17:42.000000000 +0200 +++ gcc/doc/invoke.texi 2016-10-11 20:19:33.322117754 +0200 @@ -273,8 +273,8 @@ Objective-C and Objective-C++ Dialects}. -Wformat-security -Wformat-signedness -Wformat-y2k -Wframe-address @gol -Wframe-larger-than=@var{len} -Wno-free-nonheap-object -Wjump-misses-init @gol -Wignored-qualifiers -Wignored-attributes -Wincompatible-pointer-types @gol --Wimplicit -Wimplicit-fallthrough -Wimplicit-function-declaration @gol --Wimplicit-int @gol +-Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n} @gol +-Wimplicit-function-declaration -Wimplicit-int @gol -Winit-self -Winline -Wno-int-conversion -Wint-in-bool-context @gol -Wno-int-to-pointer-cast -Winvalid-memory-model -Wno-invalid-offsetof @gol -Winvalid-pch -Wlarger-than=@var{len} @gol @@ -3734,7 +3734,7 @@ name is still supported, but the newer n @gccoptlist{-Wclobbered @gol -Wempty-body @gol -Wignored-qualifiers @gol --Wimplicit-fallthrough @gol +-Wimplicit-fallthrough=3 @gol -Wmissing-field-initializers @gol -Wmissing-parameter-type @r{(C only)} @gol -Wold-style-declaration @r{(C only)} @gol @@ -4106,6 +4106,12 @@ This warning is enabled by @option{-Wall @item -Wimplicit-fallthrough @opindex Wimplicit-fallthrough @opindex Wno-implicit-fallthrough +@option{-Wimplicit-fallthrough} is the same as @option{-Wimplicit-fallthrough=3} +and @option{-Wno-implicit-fallthrough} is the same as +@option{-Wimplicit-fallthrough=0}. + +@item -Wimplicit-fallthrough=@var{n} +@opindex Wimplicit-fallthrough= Warn when a switch case falls through. For example: @smallexample @@ -4126,7 +4132,7 @@ switch (cond) This warning does not warn when the last statement of a case cannot fall through, e.g. when there is a return statement or a call to function -declared with the noreturn attribute. @option{-Wimplicit-fallthrough} +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.@: @@ -4169,9 +4175,23 @@ switch (cond) 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" +Instead of the these attributes, it is also possible to add a fallthrough comment to silence the warning. The whole body of the C or C++ style comment -should match one of the following regular expressions: +should match the given regular expressions listed below. The option argument +@var{n} specifies what kind of comments are accepted: + +@itemize @bullet + +@item @option{-Wimplicit-fallthrough=0} disables the warning altogether. + +@item @option{-Wimplicit-fallthrough=1} matches @code{.*} regular +expression, any comment is used as fallthrough comment. + +@item @option{-Wimplicit-fallthrough=2} case insensitively matches +@code{.*falls?[ \t-]*thr(ough|u).*} regular expression. + +@item @option{-Wimplicit-fallthrough=3} case sensitively matches one of the +following regular expressions: @itemize @bullet @@ -4179,17 +4199,37 @@ should match one of the following regula @item @code{@@fallthrough@@} -@item @code{lint -fallthrough ?} +@item @code{lint -fallthrough[ \t]*} + +@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 | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)?} +@item @code{[ \t.!]*([Ee]lse,? |[Ii]ntentional(ly)? )?@*fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?} + +@end itemize -@item @code{[ \t.!]*(Else,? |Intentional(ly)? )?Fall((s | |-)[Tt]|t)hr(ough|u)[ \t.!]*(-[^\n\r]*)?} +@item @option{-Wimplicit-fallthrough=4} case sensitively matches one of the +following regular expressions: + +@itemize @bullet + +@item @code{-fallthrough} + +@item @code{@@fallthrough@@} + +@item @code{lint -fallthrough[ \t]*} + +@item @code{[ \t]*FALLTHR(OUGH|U)[ \t]*} + +@end itemize -@item @code{[ \t.!]*([Ee]lse,? |[Ii]ntentional(ly)? )?fall(s | |-)?thr(ough|u)[ \t.!]*(-[^\n\r]*)?} +@item @option{-Wimplicit-fallthrough=5} doesn't recognize any comments as +fallthrough comments, only attributes disable the warning. @end itemize -and the comment needs to be followed after optional whitespace and other comments +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. @@ -4206,7 +4246,7 @@ switch (cond) @end group @end smallexample -This warning is enabled by @option{-Wextra}. +The @option{-Wimplicit-fallthrough=3} warning is enabled by @option{-Wextra}. @item -Wignored-qualifiers @r{(C and C++ only)} @opindex Wignored-qualifiers --- gcc/c-family/c.opt.jj 2016-09-29 22:53:53.000000000 +0200 +++ gcc/c-family/c.opt 2016-10-11 19:03:50.316364851 +0200 @@ -462,6 +462,10 @@ Werror-implicit-function-declaration C ObjC RejectNegative Warning Alias(Werror=, implicit-function-declaration) This switch is deprecated; use -Werror=implicit-function-declaration instead. +Wextra +C ObjC C++ ObjC++ Warning +; in common.opt + Wfloat-conversion C ObjC C++ ObjC++ Var(warn_float_conversion) Warning LangEnabledBy(C ObjC C++ ObjC++,Wconversion) Warn for implicit type conversions that cause loss of floating point precision. @@ -536,6 +540,10 @@ Wimplicit C ObjC Var(warn_implicit) Warning LangEnabledBy(C ObjC,Wall) Warn about implicit declarations. +Wimplicit-fallthrough= +LangEnabledBy(C ObjC C++ ObjC++,Wextra,3,0) +; in common.opt + Wdouble-promotion C ObjC C++ ObjC++ Var(warn_double_promotion) Warning Warn about implicit conversions from \"float\" to \"double\". --- gcc/c-family/c-opts.c.jj 2016-09-29 22:53:53.000000000 +0200 +++ gcc/c-family/c-opts.c 2016-10-11 17:17:30.150632637 +0200 @@ -1279,6 +1279,11 @@ sanitize_cpp_opts (void) if (flag_working_directory == -1) flag_working_directory = (debug_info_level != DINFO_LEVEL_NONE); + if (warn_implicit_fallthrough < 5) + cpp_opts->cpp_warn_implicit_fallthrough = warn_implicit_fallthrough; + else + cpp_opts->cpp_warn_implicit_fallthrough = 0; + if (cpp_opts->directives_only) { if (cpp_warn_unused_macros) --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-25.c.jj 2016-10-11 18:35:49.430545561 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-25.c 2016-10-11 18:37:14.325475034 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wextra" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-26.c.jj 2016-10-11 18:38:55.087204425 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-26.c 2016-10-11 18:37:30.973265104 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-27.c.jj 2016-10-11 18:38:58.172165524 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-27.c 2016-10-11 18:38:08.283794618 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough=1" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-28.c.jj 2016-10-11 18:39:01.235126900 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-28.c 2016-10-11 18:38:50.014268395 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough=2" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-29.c.jj 2016-10-11 18:39:57.641415615 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-29.c 2016-10-11 18:40:03.191345630 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough=3" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-30.c.jj 2016-10-11 18:40:13.065221120 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-30.c 2016-10-11 18:40:34.762947511 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough=4" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-31.c.jj 2016-10-11 18:40:43.659835321 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-31.c 2016-10-11 18:41:04.397573818 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough=5" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-warning "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-32.c.jj 2016-10-11 19:05:56.158779524 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-32.c 2016-10-11 19:06:11.438587033 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough=0" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- gcc/testsuite/c-c++-common/Wimplicit-fallthrough-33.c.jj 2016-10-11 19:06:26.541396772 +0200 +++ gcc/testsuite/c-c++-common/Wimplicit-fallthrough-33.c 2016-10-11 19:06:33.660307090 +0200 @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-implicit-fallthrough" } */ + +void bar (int); + +void +foo (int i) +{ + switch (i) + { + case 1: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (1); + case 2: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (2); + /* Some comment. */ + case 3: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (3); + /* Here we really do want to fALl tHRoUgh and we mean it! */ + case 4: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (4); + /* Intentionally fall through. */ + case 5: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (5); + /* FALLTHROUGH */ + case 6: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (6); + __attribute__((fallthrough)); + case 7: /* { dg-bogus "this statement may \[fla\]* through" "" { target *-*-* } .+1 } */ + bar (7); + default: + break; + } +} --- libcpp/include/cpplib.h.jj 2016-09-26 12:06:48.000000000 +0200 +++ libcpp/include/cpplib.h 2016-10-11 17:17:09.641890203 +0200 @@ -395,6 +395,9 @@ struct cpp_options explicitly undefined. */ unsigned char warn_builtin_macro_redefined; + /* Different -Wimplicit-fallthrough= levels. */ + unsigned char cpp_warn_implicit_fallthrough; + /* Nonzero means we should look for header.gcc files that remap file names. */ unsigned char remap; --- libcpp/init.c.jj 2016-06-24 12:59:32.000000000 +0200 +++ libcpp/init.c 2016-10-11 17:16:57.423043538 +0200 @@ -189,6 +189,7 @@ cpp_create_reader (enum c_lang lang, cpp CPP_OPTION (pfile, warn_dollars) = 1; CPP_OPTION (pfile, warn_variadic_macros) = 1; CPP_OPTION (pfile, warn_builtin_macro_redefined) = 1; + CPP_OPTION (pfile, cpp_warn_implicit_fallthrough) = 0; /* By default, track locations of tokens resulting from macro expansion. The '2' means, track the locations with the highest accuracy. Read the comments for struct --- libcpp/lex.c.jj 2016-10-08 12:53:25.000000000 +0200 +++ libcpp/lex.c 2016-10-11 17:17:05.726939332 +0200 @@ -2040,6 +2040,64 @@ static bool fallthrough_comment_p (cpp_reader *pfile, const unsigned char *comment_start) { const unsigned char *from = comment_start + 1; + + switch (CPP_OPTION (pfile, cpp_warn_implicit_fallthrough)) + { + /* For both -Wimplicit-fallthrough=0 and -Wimplicit-fallthrough=5 we + don't recognize any comments. The latter only checks attributes, + the former doesn't warn. */ + case 0: + default: + return false; + /* -Wimplicit-fallthrough=1 considers any comment, no matter what + content it has. */ + case 1: + return true; + case 2: + /* -Wimplicit-fallthrough=2 looks for (case insensitive) + .*falls?[ \t-]*thr(u|ough).* regex. */ + for (; (size_t) (pfile->buffer->cur - from) >= sizeof "fallthru" - 1; + from++) + { + /* Is there anything like strpbrk with upper boundary, or + memchr looking for 2 characters rather than just one? */ + if (from[0] != 'f' && from[0] != 'F') + continue; + if (from[1] != 'a' && from[1] != 'A') + continue; + if (from[2] != 'l' && from[2] != 'L') + continue; + if (from[3] != 'l' && from[3] != 'L') + continue; + from += sizeof "fall" - 1; + if (from[0] == 's' || from[0] == 'S') + from++; + while (*from == ' ' || *from == '\t' || *from == '-') + from++; + if (from[0] != 't' && from[0] != 'T') + continue; + if (from[1] != 'h' && from[1] != 'H') + continue; + if (from[2] != 'r' && from[2] != 'R') + continue; + if (from[3] == 'u' || from[3] == 'U') + return true; + if (from[3] != 'o' && from[3] != 'O') + continue; + if (from[4] != 'u' && from[4] != 'U') + continue; + if (from[5] != 'g' && from[5] != 'G') + continue; + if (from[6] != 'h' && from[6] != 'H') + continue; + return true; + } + return false; + case 3: + case 4: + break; + } + /* Whole comment contents: -fallthrough @fallthrough@ @@ -2060,7 +2118,7 @@ fallthrough_comment_p (cpp_reader *pfile from += 1 + len; } /* Whole comment contents (regex): - lint -fallthrough ? + lint -fallthrough[ \t]* */ else if (*from == 'l') { @@ -2068,10 +2126,33 @@ fallthrough_comment_p (cpp_reader *pfile if ((size_t) (pfile->buffer->cur - from - 1) < len) return false; if (memcmp (from + 1, "int -fallthrough", len)) - return false; + return false; from += 1 + len; - if (*from == ' ') - from++; + while (*from == ' ' || *from == '\t') + from++; + } + /* Whole comment contents (regex): + [ \t]*FALLTHR(U|OUGH)[ \t]* + */ + else if (CPP_OPTION (pfile, cpp_warn_implicit_fallthrough) == 4) + { + while (*from == ' ' || *from == '\t') + from++; + if ((size_t) (pfile->buffer->cur - from) < sizeof "FALLTHRU" - 1) + return false; + if (memcmp (from, "FALLTHR", sizeof "FALLTHR" - 1)) + return false; + from += sizeof "FALLTHR" - 1; + if (*from == 'U') + from++; + else if ((size_t) (pfile->buffer->cur - from) < sizeof "OUGH" - 1) + return false; + else if (memcmp (from, "OUGH", sizeof "OUGH" - 1)) + return false; + else + from += sizeof "OUGH" - 1; + while (*from == ' ' || *from == '\t') + from++; } /* Whole comment contents (regex): [ \t.!]*(ELSE,? |INTENTIONAL(LY)? )?FALL(S | |-)?THR(OUGH|U)[ \t.!]*(-[^\n\r]*)? @@ -2085,8 +2166,8 @@ fallthrough_comment_p (cpp_reader *pfile unsigned char f = *from; bool all_upper = false; if (f == 'E' || f == 'e') - { - if ((size_t) (pfile->buffer->cur - from) + { + if ((size_t) (pfile->buffer->cur - from) < sizeof "else fallthru" - 1) return false; if (f == 'E' && memcmp (from + 1, "LSE", sizeof "LSE" - 1) == 0) @@ -2096,7 +2177,7 @@ fallthrough_comment_p (cpp_reader *pfile from += sizeof "else" - 1; if (*from == ',') from++; - if (*from != ' ') + if (*from != ' ') return false; from++; if (all_upper && *from == 'f') @@ -2104,10 +2185,10 @@ fallthrough_comment_p (cpp_reader *pfile if (f == 'e' && *from == 'F') return false; f = *from; - } + } else if (f == 'I' || f == 'i') - { - if ((size_t) (pfile->buffer->cur - from) + { + if ((size_t) (pfile->buffer->cur - from) < sizeof "intentional fallthru" - 1) return false; if (f == 'I' && memcmp (from + 1, "NTENTIONAL", @@ -2138,7 +2219,7 @@ fallthrough_comment_p (cpp_reader *pfile 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) Jakub