[clang] 5e706e1 - [Clang] enhance loop analysis to handle variable changes inside lambdas (#135573)

via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 13 07:09:51 PST 2026


Author: Oleksandr Tarasiuk
Date: 2026-02-13T17:09:45+02:00
New Revision: 5e706e1b4ba428fa21cbd51f1e41e01ade2310a7

URL: https://github.com/llvm/llvm-project/commit/5e706e1b4ba428fa21cbd51f1e41e01ade2310a7
DIFF: https://github.com/llvm/llvm-project/commit/5e706e1b4ba428fa21cbd51f1e41e01ade2310a7.diff

LOG: [Clang] enhance loop analysis to handle variable changes inside lambdas (#135573)

Fixes #132038 

--- 

This PR extends `-Wloop-analysis` to handle variable modifications
inside lambda expressions.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaStmt.cpp
    clang/test/SemaCXX/warn-loop-analysis.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 110761081e796..4f732ba81d78f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -239,6 +239,9 @@ Improvements to Clang's diagnostics
 - Added a missing space to the FixIt for the ``implicit-int`` group of diagnostics and 
   made sure that only one such diagnostic and FixIt is emitted per declaration group. (#GH179354)
 
+- The ``-Wloop-analysis`` warning has been extended to catch more cases of
+  variable modification inside lambda expressions (#GH132038).
+
 Improvements to Clang's time-trace
 ----------------------------------
 

diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index ba5ba80d6a0bc..b74af55d1bea1 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1996,9 +1996,33 @@ namespace {
     }
 
     void VisitDeclRefExpr(DeclRefExpr *E) {
-      if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
+      if (const auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
         if (Decls.count(VD))
           FoundDecl = true;
+      } else if (const auto *MD = dyn_cast<CXXMethodDecl>(E->getDecl());
+                 MD && isLambdaCallOperator(MD)) {
+        // FIXME: This has limitations handling updates to the loop control
+        // variable that occur indirectly inside a lambda called from the loop
+        // body. For example:
+        //
+        //   int a = 0;
+        //   int *c = &a;
+        //   auto incr_c = [c]() { ++*c; };
+        //   for (a = 10; a <= 20; incr_c())
+        //     foo(a);
+        for (const auto &Capture : MD->getParent()->captures()) {
+          if (!Capture.capturesVariable())
+            continue;
+
+          LambdaCaptureKind CK = Capture.getCaptureKind();
+          if (CK != LCK_ByRef)
+            continue;
+
+          const auto *VD = dyn_cast<VarDecl>(Capture.getCapturedVar());
+          if (VD && Decls.count(VD))
+            FoundDecl = true;
+        }
+      }
     }
 
     void VisitPseudoObjectExpr(PseudoObjectExpr *POE) {

diff  --git a/clang/test/SemaCXX/warn-loop-analysis.cpp b/clang/test/SemaCXX/warn-loop-analysis.cpp
index 324dd386292ac..7773bef0cd238 100644
--- a/clang/test/SemaCXX/warn-loop-analysis.cpp
+++ b/clang/test/SemaCXX/warn-loop-analysis.cpp
@@ -299,3 +299,45 @@ void test10() {
   for (auto[i, j, k] = arr; i < a; ++i) { }
   for (auto[i, j, k] = arr; i < a; ++arr[0]) { }
 };
+
+namespace GH132038 {
+extern void foo(int);
+void test1() {
+  int a = 0;
+  auto incr_a = [&a]() { ++a; };
+
+  for (int b = 10; a <= b; incr_a())
+    foo(a);
+
+  for (int b = 10; a <= b;)
+    incr_a();
+
+  for (int b = 10; a <= b; [&a]() { ++a; }()) { }
+  for (int b = 10; a <= b; [&a]() { }()) { }
+}
+
+void test2() {
+  int a = 0;
+  int *c = &a;
+
+  auto incr_a = [a]() {  };
+  auto incr_b = [](int b) { };
+  auto incr_c = [c]() { ++*c; };
+
+  for (int b = 10; a <= b; incr_a()) // expected-warning {{variables 'a' and 'b' used in loop condition not modified in loop body}}
+    foo(a);
+
+  for (int b = 10; a <= b;) // expected-warning {{variables 'a' and 'b' used in loop condition not modified in loop body}}
+    incr_a();
+
+  for (int b = 10; a <= b; incr_b(b)) // expected-warning {{variables 'a' and 'b' used in loop condition not modified in loop body}}
+    foo(a);
+
+  for (int b = 10; a <= b;) // expected-warning {{variables 'a' and 'b' used in loop condition not modified in loop body}}
+    incr_b(b);
+
+  // FIXME: handle modification of loop control variable inside lambda body
+  for (a = 10; a <= 20; incr_c()) // expected-warning {{variable 'a' used in loop condition not modified in loop body}}
+    foo(a);
+}
+}


        


More information about the cfe-commits mailing list