This is an archive of the discontinued LLVM Phabricator instance.

[clang] Expose unreachable fallthrough annotation warning
ClosedPublic

Authored by nathanchance on Aug 11 2021, 3:23 PM.

Details

Summary

The Linux kernel has a macro called IS_ENABLED(), which evaluates to a
constant 1 or 0 based on Kconfig selections, allowing C code to be
unconditionally enabled or disabled at build time. For example:

int foo(struct *a, int b) {
    switch (b) {
    case 1:
        if (a->flag || !IS_ENABLED(CONFIG_64BIT))
            return 1;
        __attribute__((fallthrough));
    case 2:
        return 2;
    default:
        return 3;
    }
}

There is an unreachable warning about the fallthrough annotation in the
first case because !IS_ENABLED(CONFIG_64BIT) can be evaluated to 1,
which looks like

return 1;
__attribute__((fallthrough));

to clang.

This type of warning is pointless for the Linux kernel because it does
this trick all over the place due to the sheer number of configuration
options that it has.

Add -Wunreachable-code-fallthrough, enabled under -Wunreachable-code, so
that projects that want to warn on unreachable code get this warning but
projects that do not care about unreachable code can still use
-Wimplicit-fallthrough without having to make changes to their code
base.

Fixes PR51094.

Diff Detail

Event Timeline

nathanchance requested review of this revision.Aug 11 2021, 3:23 PM
nathanchance created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptAug 11 2021, 3:23 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript
clang/test/SemaCXX/switch-implicit-fallthrough.cpp
211–214

These 4 lines don't add anything to the test coverage. Remove them?

GCC does not warn (with common -Wall) for this case, right? I think Clang should not as well.

ImplicitFallthroughUnreachable could be enabled with -Wunreachable-code, if you think we should have it.

GCC does not warn (with common -Wall) for this case, right? I think Clang should not as well.

ImplicitFallthroughUnreachable could be enabled with -Wunreachable-code, if you think we should have it.

Yeah, some of that was discussed on the bug: https://bugs.llvm.org/show_bug.cgi?id=51094 & I'd still be in favor of that sort of direction. I might go so far as to say: Maybe we should drop this warning flag (and/or move it under -Wunreachable-code - questionable, I don't think anyone's really using that, it's pretty noisy still, I think) entirely even if no one's willing to reimplement it more robustly... not sure.

GCC does not warn (with common -Wall) for this case, right? I think Clang should not as well.

Correct, GCC does not warn at all about unreachable fallthrough annotations as far as I am aware.

ImplicitFallthroughUnreachable could be enabled with -Wunreachable-code, if you think we should have it.

Yeah, some of that was discussed on the bug: https://bugs.llvm.org/show_bug.cgi?id=51094 & I'd still be in favor of that sort of direction. I might go so far as to say: Maybe we should drop this warning flag (and/or move it under -Wunreachable-code - questionable, I don't think anyone's really using that, it's pretty noisy still, I think) entirely even if no one's willing to reimplement it more robustly... not sure.

The kernel does not use -Wunreachable-code for this reason and several others; we have explored it in the past and found that there were pretty much no instances where the warnings indicated a bug and kernel maintainers were irritated with some of the patches sent. So moving this warning under there (as -Wunreachable-code-fallthrough?) would work for us. I do not have a strong opinion though. I am more than happy to remove the warning entirely as well.

I think we should just move it, not delete it.

So something more along the lines of

diff
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 1555a9ee2465..0aa9a82e3d11 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -823,10 +823,12 @@ def UnreachableCode : DiagGroup<"unreachable-code",
                                 [UnreachableCodeLoopIncrement]>;
 def UnreachableCodeBreak : DiagGroup<"unreachable-code-break">;
 def UnreachableCodeReturn : DiagGroup<"unreachable-code-return">;
+def UnreachableCodeFallthrough : DiagGroup<"unreachable-code-fallthrough">;
 def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive",
                                     [UnreachableCode,
                                      UnreachableCodeBreak,
-                                     UnreachableCodeReturn]>;
+                                     UnreachableCodeReturn,
+                                     UnreachableCodeFallthrough]>;

 // Aggregation warning settings.

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bf857f58951b..f533076a6c77 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -682,6 +682,9 @@ def warn_unreachable_return : Warning<
 def warn_unreachable_loop_increment : Warning<
   "loop will run at most once (loop increment never executed)">,
   InGroup<UnreachableCodeLoopIncrement>, DefaultIgnore;
+def warn_unreachable_fallthrough_attr : Warning<
+  "fallthrough annotation in unreachable code">,
+  InGroup<UnreachableCodeFallthrough>, DefaultIgnore;
 def note_unreachable_silence : Note<
   "silence by adding parentheses to mark code as explicitly dead">;

@@ -9578,9 +9581,6 @@ def err_fallthrough_attr_outside_switch : Error<
   "fallthrough annotation is outside switch statement">;
 def err_fallthrough_attr_invalid_placement : Error<
   "fallthrough annotation does not directly precede switch label">;
-def warn_fallthrough_attr_unreachable : Warning<
-  "fallthrough annotation in unreachable code">,
-  InGroup<ImplicitFallthrough>, DefaultIgnore;

 def warn_unreachable_default : Warning<
   "default label in switch which covers all enumeration values">,
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index aa2602c8d925..99ce143d3559 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1125,7 +1125,7 @@ namespace {
                 // unreachable in all instantiations of the template.
                 if (!IsTemplateInstantiation)
                   S.Diag(AS->getBeginLoc(),
-                         diag::warn_fallthrough_attr_unreachable);
+                         diag::warn_unreachable_fallthrough_attr);
                 markFallthroughVisited(AS);
                 ++AnnotatedCnt;
                 break;

if I understand correctly?

Yes, something like that, plus I think you want put UnreachableCodeFallthrough into group UnreachableCode as well.

Probably still worth fixing the bug too? (though maybe not a priority once it's moved out into -Wunreachable-code) - though the general fix, as discussed on the bug (comment 18 and 19 about why this doesn't already produce an unreachable-code warning), may require a significant amount of work.

Yes, something like that, plus I think you want put UnreachableCodeFallthrough into group UnreachableCode as well.

So you would recommend adding it to UnreachableCode rather than UnreachableCodeAggressive?

Probably still worth fixing the bug too? (though maybe not a priority once it's moved out into -Wunreachable-code) - though the general fix, as discussed on the bug (comment 18 and 19 about why this doesn't already produce an unreachable-code warning), may require a significant amount of work.

I guess not warning on fallthrough attributes that are preceded by an if statement with an integer constant would remove all problematic instances in the kernel I believe. I am just not sure how to put that into code :)

Yes, something like that, plus I think you want put UnreachableCodeFallthrough into group UnreachableCode as well.

So you would recommend adding it to UnreachableCode rather than UnreachableCodeAggressive?

I would recommend adding it to UnreachableCode as I don't see this being a particularly aggressive unreachable warning. FWIW, I would be opposed to dropping the diagnostic entirely as the standard recommends diagnosing an unreachable fallthrough statement (https://eel.is/c++draft/dcl.attr.fallthrough#2.sentence-2 and the similar wording in C2x 6.7.11.5p3.

Yes, something like that, plus I think you want put UnreachableCodeFallthrough into group UnreachableCode as well.

So you would recommend adding it to UnreachableCode rather than UnreachableCodeAggressive?

I would recommend adding it to UnreachableCode as I don't see this being a particularly aggressive unreachable warning. FWIW, I would be opposed to dropping the diagnostic entirely as the standard recommends diagnosing an unreachable fallthrough statement (https://eel.is/c++draft/dcl.attr.fallthrough#2.sentence-2 and the similar wording in C2x 6.7.11.5p3.

(totally not to derail this, but... - I'm not sure that wording in the spec is especially informative/worth worrying about too much. If we have a warning we know isn't especially informative and is off-by-default, I'm not sure it makes too much difference whether we have it all. The spec doesn't have a lot of practice spec'ing warnings, which have a bunch of nuance that the spec doesn't usually have to deal with)

  • -Wimplicit-fallthrough-unreachable -> -Wunreachable-code-fallthrough, enabled under -Wunreachable-code (Dávid, Aaron).
  • Drop "case 225" from new test, as it does not add to test coverage (Nick).
  • Add -Wunreachable-code-fallthrough to PR30636 test command, as it is explicitly testing that there is no unreachable warning with template function instantiation.
nathanchance marked an inline comment as done.Aug 13 2021, 3:30 PM
nathanchance added inline comments.
clang/test/SemaCXX/switch-implicit-fallthrough.cpp
211–214

Done.

aaron.ballman accepted this revision.Aug 16 2021, 8:42 AM

LGTM, I think this is incremental progress.

This revision is now accepted and ready to land.Aug 16 2021, 8:42 AM

Patch description probably needs an update - looks like it's out of date ("Add -Wimplicit-fallthrough-unreachable, which is default enabled with -Wimplicit-fallthrough" should read, I guess "Add -Wunreachable-code-fallthrough, which is default enabled with -Wunreachable-code" - also, I might avoid using the "default enabled" as it may lead to some confusion/sound like it's suggesting that "this subwarning is on by default as it's grouped under this other on-by-default warning", which isn't the case - maybe "which is enabled with -Wunreachable-code" would suffice? or "which is part of the -Wunreachable-code group")

nathanchance marked an inline comment as not done.
nathanchance edited the summary of this revision. (Show Details)
  • Update commit message (forgot to use arc diff --edit --verbatim) [David]
nickdesaulniers accepted this revision.Aug 16 2021, 1:44 PM