https://github.com/Adinesh-Reddy created https://github.com/llvm/llvm-project/pull/234848
## Summary This PR fixes issue #230802, where Clang can report a false-positive `-Wimplicit-fallthrough` warning for consecutive switch labels when an attributed statement is present. ## What was the problem? While checking whether execution falls through from one switch case to another, Clang compares statements with switch labels. However, when a label is wrapped inside an `AttributedStmt`, the comparison may fail because Clang sees the wrapper instead of the actual statement. This can cause Clang to report a fallthrough warning even when the cases are consecutive labels and no actual fallthrough occurs. ## What did I change? - Added a helper function to skip `AttributedStmt` wrappers and access the underlying statement. - Used this helper in the fallthrough analysis where Clang checks switch labels and their relationships. - Added regression tests to cover the issue and check that genuine fallthrough warnings are still reported. ## Testing - Ran `clang/test/SemaCXX/switch-implicit-fallthrough.cpp` using `llvm-lit`. - Ran `clang/test/Sema/attr-likelihood.c` to check that the changes do not break related tests. - Tested additional cases involving consecutive labels and genuine fallthrough. All the above tests passed. Fixes #230802. >From 0ac141c1a3c92a11dba23021efddd9b1163edd0d Mon Sep 17 00:00:00 2001 From: Adinesh Reddy <[email protected]> Date: Fri, 23 Oct 2026 10:19:03 +0530 Subject: [PATCH] [Clang] Fix false-positive fallthrough warning (#230802) --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 14 ++++++++--- .../SemaCXX/switch-implicit-fallthrough.cpp | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 21af6ed5527ffc..718e45a9ccb572 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1276,11 +1276,13 @@ class FallthroughMapper : public DynamicRecursiveASTVisitor { continue; // Switch statement, good. const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel()); - if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end()) + if (SW && stripAttributedStmts(SW->getSubStmt()) == B.getLabel() && + P->begin() == P->end()) continue; // Previous case label has no statements, good. const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel()); - if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) + if (L && stripAttributedStmts(L->getSubStmt()) == B.getLabel() && + P->begin() == P->end()) continue; // Case label is preceded with a normal label, good. if (!ReachableBlocks.count(P)) { @@ -1355,6 +1357,12 @@ class FallthroughMapper : public DynamicRecursiveASTVisitor { private: + static const Stmt *stripAttributedStmts(const Stmt *S) { + while (const auto *AS = dyn_cast_or_null<AttributedStmt>(S)) + S = AS->getSubStmt(); + return S; + } + static const AttributedStmt *asFallThroughAttr(const Stmt *S) { if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) { if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs())) @@ -1373,7 +1381,7 @@ class FallthroughMapper : public DynamicRecursiveASTVisitor { // case X: {} case Y: // case X: ; case Y: if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel())) - if (!isa<SwitchCase>(SW->getSubStmt())) + if (!isa<SwitchCase>(stripAttributedStmts(SW->getSubStmt()))) return SW->getSubStmt(); return nullptr; diff --git a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp index 750663717b66a4..5ca4eeb9ac9473 100644 --- a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp +++ b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -255,6 +255,30 @@ int fallthrough_covered_enums(Enum e) { // Fallthrough annotations in local classes used to generate "fallthrough // annotation does not directly precede switch label" warning. + +int fallthrough_attributed_labels(int n) { + switch (n) { + [[unlikely]] case 0: + [[unlikely]] case 1: + [[likely]] case 2: + case 3: + [[unlikely]] default: + return 1; + } + switch (n) { + case 4: + n++; + [[unlikely]] case 5: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}} + n++; + break; + [[unlikely]] case 6: + n++; + [[unlikely]] default: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}} + return 2; + } + return n; +} + void fallthrough_in_local_class() { class C { void f(int x) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
