[clang-tools-extra] [clang-tidy] Do not diagnose continue of outer loop (PR #222485)

Junior Rantila via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 10 07:03:13 PDT 2026


https://github.com/juniorrantila updated https://github.com/llvm/llvm-project/pull/222485

>From 4a9900b139598537a563e81c232bb83820d4d64e Mon Sep 17 00:00:00 2001
From: Junior Rantila <junior.rantila at gmail.com>
Date: Thu, 10 Sep 2026 02:05:52 +0200
Subject: [PATCH] [clang-tidy] Do not diagnose continue of outer loop

This patch ensures that "readability-redundant-control-flow"
does not trigger a diagnostic when continuing an outer loop
at the end of an inner loop.

```
int robin = 0;
next_client: for (;;) {
  int client = accept(sock);

  for (int i = 0; i < worker_count; i++) {
    robin = (robin + 1) % worker_count;
    Worker* worker = &workers[robin];
    if (worker->is_full())
      continue;
    worker->push(client);
    continue next_client; // This would previously emit diagnostic.
  }

  handle_request(client);
}

```
---
 .../readability/RedundantControlFlowCheck.cpp | 12 +++++++++++-
 .../readability/redundant-control-flow.cpp    | 19 +++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
index 46cbaa1f70301..48d99db2ee79a 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
@@ -39,7 +39,8 @@ void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
       this);
   Finder->addMatcher(mapAnyOf(forStmt, cxxForRangeStmt, whileStmt, doStmt)
                          .with(hasBody(compoundStmt(
-                             hasFinalStmt(continueStmt().bind("stmt"))))),
+                             hasFinalStmt(continueStmt().bind("stmt")))))
+                         .bind("loop"),
                      this);
 }
 
@@ -50,6 +51,15 @@ void RedundantControlFlowCheck::check(const MatchFinder::MatchResult &Result) {
   if (StmtRange.getBegin().isMacroID())
     return;
 
+  if (const auto *Continue = dyn_cast<ContinueStmt>(&RedundantStmt)) {
+    if (const auto *Label = Continue->getLabelDecl()) {
+      const auto *Loop = Result.Nodes.getNodeAs<Stmt>("loop");
+      const auto *ContinueLoop = Label->getStmt()->getSubStmt();
+      if (Loop != ContinueLoop)
+        return;
+    }
+  }
+
   const auto RemovedRange = CharSourceRange::getCharRange(
       StmtRange.getBegin(),
       Lexer::findLocationAfterToken(StmtRange.getEnd(), tok::semi,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-control-flow.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-control-flow.cpp
index e157e99c5bf0b..0b1755e306a49 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-control-flow.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-control-flow.cpp
@@ -272,3 +272,22 @@ void semicolon_far_from_continue() {
 // CHECK-MESSAGES: :[[@LINE-5]]:5: warning: redundant continue statement at the end of loop statement
 // CHECK-FIXES:      for (int i = 0; i < 20; ++i) {
 // CHECK-FIXES-NEXT: }
+
+void continue_labeled_loop() {
+  loop:
+  for (int i = 0; i < 10; ++i) {
+    continue loop;
+  }
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:5: warning: redundant continue statement at the end of loop statement
+// CHECK-FIXES:      for (int i = 0; i < 10; ++i) {
+// CHECK-FIXES-NEXT: }
+
+void continue_outer_labeled_loop() {
+  outer:
+  for (int i = 0; i < 10; ++i) {
+    for (int j = 0; j < 10; ++j) {
+      continue outer;
+    }
+  }
+}



More information about the cfe-commits mailing list