https://github.com/Adinesh-Reddy updated https://github.com/llvm/llvm-project/pull/234848
>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 1/3] [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) { >From d9487e795c236ff30bac89686f302540f040d557 Mon Sep 17 00:00:00 2001 From: Adinesh Reddy <[email protected]> Date: Fri, 23 Oct 2026 15:07:00 +0530 Subject: [PATCH 2/3] Add fallthrough regression tests --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +- .../SemaCXX/switch-implicit-fallthrough.cpp | 70 ++++++++++++++++--- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 718e45a9ccb572..41a8eb8a66129e 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1381,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>(stripAttributedStmts(SW->getSubStmt()))) + if (!isa<SwitchCase>(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 5ca4eeb9ac9473..cb0e34d57d4a71 100644 --- a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp +++ b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -253,17 +253,16 @@ int fallthrough_covered_enums(Enum e) { return n; } -// Fallthrough annotations in local classes used to generate "fallthrough -// annotation does not directly precede switch label" warning. - +// Attributes on consecutive switch labels should not introduce false fallthrough. int fallthrough_attributed_labels(int n) { switch (n) { - [[unlikely]] case 0: - [[unlikely]] case 1: - [[likely]] case 2: - case 3: - [[unlikely]] default: - return 1; + [[unlikely]] case 0: + [[unlikely]] case 1: + [[likely]] case 2: + case 3: + return 0; + [[unlikely]] default: + return 1; } switch (n) { case 4: @@ -279,6 +278,59 @@ int fallthrough_attributed_labels(int n) { return n; } +// Consecutive ordinary labels do not introduce fallthrough. +int fallthrough_ordinary_labels(int n) { + switch (n) { + case 0: + case 1: + return 0; + case 2: + return 1; + default: + return 2; + } +} + +// An explicit fallthrough annotation should suppress the warning. +int fallthrough_explicit_annotation(int n) { + switch (n) { + case 0: + ++n; + [[clang::fallthrough]]; + case 1: + return 0; + default: + return 1; + } +} + +// Genuine fallthrough without an annotation should warn. +int fallthrough_without_annotation(int n) { + switch (n) { + case 0: + ++n; + // expected-warning@+1 {{unannotated fall-through between switch labels}} + case 1: // expected-note 2 {{insert}} + return 0; + default: + return 1; + } +} + +// An attributed case label immediately follows an ordinary label. +int fallthrough_label_attributed_case(int n) { + switch (n) { + case 0: + ordinary_label: + [[likely]] case 1: + return 0; + default: + return 1; + } +} + +// Fallthrough annotations in local classes used to generate "fallthrough +// annotation does not directly precede switch label" warning. void fallthrough_in_local_class() { class C { void f(int x) { >From 6180dab32ae13718dc624adc3b906efa8bcd7ac8 Mon Sep 17 00:00:00 2001 From: Adinesh Reddy <[email protected]> Date: Fri, 23 Oct 2026 15:45:47 +0530 Subject: [PATCH 3/3] Preserve original fallthrough reproducer --- clang/test/SemaCXX/switch-implicit-fallthrough.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp index cb0e34d57d4a71..c07f68f4fe8e58 100644 --- a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp +++ b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -260,9 +260,9 @@ int fallthrough_attributed_labels(int n) { [[unlikely]] case 1: [[likely]] case 2: case 3: - return 0; + [[unlikely]] case 4: [[unlikely]] default: - return 1; + return -1; } switch (n) { case 4: _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
