[clang] [Clang] Fix false-positive fallthrough warning (#230802) (PR #234848)

Adinesh Reddy via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 25 05:25:04 PDT 2026


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 <cs24btech11026 at iith.ac.in>
Date: Fri, 23 Oct 2026 10:19:03 +0530
Subject: [PATCH 1/5] [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 <cs24btech11026 at iith.ac.in>
Date: Fri, 23 Oct 2026 15:07:00 +0530
Subject: [PATCH 2/5] 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 at +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 <cs24btech11026 at iith.ac.in>
Date: Fri, 23 Oct 2026 15:45:47 +0530
Subject: [PATCH 3/5] 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:

>From 5e19877e17bb1f4d8a3cd8d2438a75d8c7d31faf Mon Sep 17 00:00:00 2001
From: Adinesh Reddy <cs24btech11026 at iith.ac.in>
Date: Sun, 25 Oct 2026 17:21:30 +0530
Subject: [PATCH 4/5] [Clang] Add release note for fallthrough warning fix

---
 clang/docs/ReleaseNotes.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7d3f0eb702553d..a0af970d08aa6a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -408,6 +408,8 @@ features cannot lower the translation-unit ABI level;
 
 ### Improvements to Clang's diagnostics
 
+- Clang no longer emits a false-positive `-Wimplicit-fallthrough` warning when consecutive switch labels share a body and are annotated with attributes like `[[unlikely]]`. (#GH230802)
+
 - Fixed spurious `-Wimplicit-void-ptr-cast` warnings in C for parenthesized
   null pointer macros such as `(NULL)`. (#GH171874)
 

>From 6a058b472ab3ae55bc624272321b922f25149478 Mon Sep 17 00:00:00 2001
From: Adinesh Reddy <cs24btech11026 at iith.ac.in>
Date: Sun, 25 Oct 2026 17:54:53 +0530
Subject: [PATCH 5/5] ReleaseNotes fix

---
 clang/docs/ReleaseNotes.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index c7ab1f9e0a31f1..dabd0c3d241457 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -458,9 +458,9 @@ documentation](CIR/index.md) for more information regarding ClangIR's status and
 
 ### Improvements to Clang's diagnostics
 
-- Clang no longer emits a false-positive `-Wimplicit-fallthrough` warning 
-   when consecutive switch labels share a body and are annotated with attributes like 
-   `[[unlikely]]`. (#GH230802)
+- Fixed a false-positive `-Wimplicit-fallthrough` warning when
+  consecutive switch labels share a body and are annotated with
+  attributes like `[[unlikely]]`. (#GH230802)
  
 - Fixed missing `-Wuninitialized-explicit-init` warnings for C file-scope
   tentative definitions of structure types which contain a field marked with



More information about the cfe-commits mailing list