[clang] [analyzer] Resolve lambda captures for explicit object parameters (PR #219726)
Benedek Kaibas via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 29 14:05:44 PDT 2026
https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/219726
>From cd800a911d402fafe1f32e4ff2709d5061732e08 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sat, 29 Aug 2026 22:41:18 +0200
Subject: [PATCH 1/3] [analyzer] Resolve lambda captures for explicit object
parameters
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 26 +++++++++--
.../test/Analysis/explicit-lambda-capture.cpp | 43 +++++++++++++++++++
2 files changed, 65 insertions(+), 4 deletions(-)
create mode 100644 clang/test/Analysis/explicit-lambda-capture.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index e6349eb4eba2a..01e05924a2537 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3040,12 +3040,30 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
// Sema follows a sequence of complex rules to determine whether the
// variable should be captured.
if (const FieldDecl *FD = LambdaCaptureFields[VD]) {
- Loc CXXThis = svalBuilder.getCXXThis(MD, SF);
- SVal CXXThisVal = state->getSVal(CXXThis);
- return std::make_pair(state->getLValue(FD, CXXThisVal), FD->getType());
+ if (MD->isImplicitObjectMemberFunction()) {
+ Loc CXXThis = svalBuilder.getCXXThis(MD, SF);
+ SVal CXXThisVal = state->getSVal(CXXThis);
+ return std::make_pair(state->getLValue(FD, CXXThisVal),
+ FD->getType());
+ }
+ const ParmVarDecl *PVD = MD->getParamDecl(0);
+ if (const Expr *CallSite = SF->getCallSite()) {
+ unsigned Idx = PVD->getFunctionScopeIndex();
+ const ParamVarRegion *PVR =
+ state->getStateManager().getRegionManager().getParamVarRegion(
+ CallSite, Idx, SF);
+ const Expr *SelfArgExpr = cast<CallExpr>(CallSite)->getArg(0);
+ state =
+ state->bindLoc(loc::MemRegionVal(PVR),
+ state->getSVal(SelfArgExpr, SF->getParent()), SF);
+ SVal ParamSVal = state->getSVal(loc::MemRegionVal(PVR));
+ if (!PVD->getType()->isReferenceType())
+ return std::make_pair(state->getLValue(FD, loc::MemRegionVal(PVR)),
+ FD->getType());
+ return std::make_pair(state->getLValue(FD, ParamSVal), FD->getType());
+ }
}
}
-
return std::nullopt;
};
diff --git a/clang/test/Analysis/explicit-lambda-capture.cpp b/clang/test/Analysis/explicit-lambda-capture.cpp
new file mode 100644
index 0000000000000..2d98b80ce9637
--- /dev/null
+++ b/clang/test/Analysis/explicit-lambda-capture.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -analyze -std=c++23 -analyzer-checker=core.DivideZero -verify %s
+
+int implicit_capture_by_value() {
+ int d = 0;
+ auto lam = [d]() { return 1 / d; }; // expected-warning {{Division by zero}}
+ return lam();
+}
+
+int explicit_rvalue_self_capture_by_reference() {
+ int d = 0;
+ auto lam = [&d](this auto &&self) { return 1 / d; }; // expected-warning {{Division by zero}}
+ return lam();
+}
+
+int gh218708_explicit_rvalue_self() {
+ int d = 0;
+ auto lam = [d](this auto &&self) { return 1 / d; }; // expected-warning {{Division by zero}}
+ return lam();
+}
+
+int gh218708_explicit_lvalue_self() {
+ int d = 0;
+ auto lam = [d](this auto &self) { return 1 / d; }; // expected-warning {{Division by zero}}
+ return lam();
+}
+
+int gh218708_explicit_by_value_self() {
+ int d = 0;
+ auto lam = [d](this auto self) { return 1 / d; }; // expected-warning {{Division by zero}}
+ return lam();
+}
+
+int explicit_rvalue_no_error() {
+ int d = 5;
+ auto lam = [d](this auto &&self) { return 1 / d; }; // 'd' is non-zero so there is no division by zero error.
+ return lam();
+}
+
+int explicit_by_value_no_error() {
+ int d = 9;
+ auto lam = [d](this auto self) { return 1 / d; }; // 'd' is non-zero so there is no division by zero error.
+ return lam();
+}
>From 14f335aaecfcfe15de5aa0550c210b97e20a5283 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sat, 29 Aug 2026 22:58:50 +0200
Subject: [PATCH 2/3] Fix unconditional compute for the reference type
construction.
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 01e05924a2537..0ab2d22b87fe2 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3053,14 +3053,15 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
state->getStateManager().getRegionManager().getParamVarRegion(
CallSite, Idx, SF);
const Expr *SelfArgExpr = cast<CallExpr>(CallSite)->getArg(0);
- state =
- state->bindLoc(loc::MemRegionVal(PVR),
- state->getSVal(SelfArgExpr, SF->getParent()), SF);
- SVal ParamSVal = state->getSVal(loc::MemRegionVal(PVR));
- if (!PVD->getType()->isReferenceType())
- return std::make_pair(state->getLValue(FD, loc::MemRegionVal(PVR)),
+ if (PVD->getType()->isReferenceType()) {
+ state = state->bindLoc(loc::MemRegionVal(PVR),
+ state->getSVal(SelfArgExpr, SF->getParent()),
+ SF);
+ SVal ParamSVal = state->getSVal(loc::MemRegionVal(PVR));
+ return std::make_pair(state->getLValue(FD, ParamSVal),
FD->getType());
- return std::make_pair(state->getLValue(FD, ParamSVal), FD->getType());
+ }
+ return std::make_pair(state->getLValue(FD, loc::MemRegionVal(PVR)), FD->getType());
}
}
}
>From 19674e6cff8045269ef8655cd4e16816127af6f4 Mon Sep 17 00:00:00 2001
From: benedekaibas <kaibas01 at allegheny.edu>
Date: Sat, 29 Aug 2026 23:05:25 +0200
Subject: [PATCH 3/3] Fix formatting issue
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 0ab2d22b87fe2..c503d686fb407 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -3061,7 +3061,8 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
return std::make_pair(state->getLValue(FD, ParamSVal),
FD->getType());
}
- return std::make_pair(state->getLValue(FD, loc::MemRegionVal(PVR)), FD->getType());
+ return std::make_pair(state->getLValue(FD, loc::MemRegionVal(PVR)),
+ FD->getType());
}
}
}
More information about the cfe-commits
mailing list