[clang] [libclang]Visit lambda init-capture as VarDeclaration (PR #174116)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 2 07:55:06 PST 2026
Martin =?utf-8?q?Bednár?= <martin at serafean.cz>,
Martin =?utf-8?q?Bednár?= <martin at serafean.cz>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/174116 at github.com>
https://github.com/Serafean updated https://github.com/llvm/llvm-project/pull/174116
>From 3cae349bfa67a555d1021fdeb9c20e2b6109f3ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Bedn=C3=A1r?= <martin at serafean.cz>
Date: Wed, 31 Dec 2025 17:27:30 +0100
Subject: [PATCH 1/3] [libclang]Visit lambda init-capture as vardecl
int foo(){
int i = 42;
int j = 43;
auto l1 = [x = i, &j ](){};
}
in the lambda capture:
- x is visited as VariableRef (referencing an unvisited VarDecl at the same location)
- i is visited as DelcRefExpr (same as in an assignment)
- j is visited as VariableRef
Visit x as a VarDecl, and stop visiting it as a VariableRef, as it makes
no sense (referencing itself at an unvisited cursor).
---
clang/docs/ReleaseNotes.rst | 1 +
clang/test/Index/cxx14-lambdas.cpp | 4 ++--
clang/tools/libclang/CIndex.cpp | 25 ++++++++++++-------------
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92731326ca1bf..8e3ddca5eb637 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -383,6 +383,7 @@ clang-format
libclang
--------
+- visit identifier initializers in lambda capture as VarDecl
Code Completion
---------------
diff --git a/clang/test/Index/cxx14-lambdas.cpp b/clang/test/Index/cxx14-lambdas.cpp
index 0c9aaec6c88e5..dfcf812ae3016 100644
--- a/clang/test/Index/cxx14-lambdas.cpp
+++ b/clang/test/Index/cxx14-lambdas.cpp
@@ -17,9 +17,9 @@ struct X {
// CHECK-LOAD: cxx14-lambdas.cpp:7:19: CallExpr= Extent=[7:19 - 9:6]
// CHECK-LOAD: cxx14-lambdas.cpp:7:19: UnexposedExpr= Extent=[7:19 - 9:6]
// CHECK-LOAD: cxx14-lambdas.cpp:7:19: LambdaExpr= Extent=[7:19 - 9:6]
-// CHECK-LOAD: cxx14-lambdas.cpp:7:20: VariableRef=ptr:7:20 Extent=[7:20 - 7:23]
-// CHECK-LOAD: cxx14-lambdas.cpp:7:35: VariableRef=copy:7:35 Extent=[7:35 - 7:39]
+// CHECK-LOAD: cxx14-lambdas.cpp:7:20: VarDecl=ptr:7:20 (Definition) Extent=[7:20 - 7:33]
// CHECK-LOAD: cxx14-lambdas.cpp:7:27: DeclRefExpr=localA:6:9 Extent=[7:27 - 7:33]
+// CHECK-LOAD: cxx14-lambdas.cpp:7:35: VarDecl=copy:7:35 (Definition) Extent=[7:35 - 7:48]
// CHECK-LOAD: cxx14-lambdas.cpp:7:42: DeclRefExpr=localB:6:17 Extent=[7:42 - 7:48]
// CHECK-LOAD: cxx14-lambdas.cpp:7:59: ParmDecl=x:7:59 (Definition) Extent=[7:51 - 7:60]
// CHECK-LOAD: cxx14-lambdas.cpp:7:51: TypeRef=Integer:3:13 Extent=[7:51 - 7:58]
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 15eec87652451..d1b5cb8ebff87 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -3901,19 +3901,18 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
CEnd = E->explicit_capture_end();
C != CEnd; ++C) {
- if (!C->capturesVariable())
- continue;
- // TODO: handle structured bindings here ?
- if (!isa<VarDecl>(C->getCapturedVar()))
- continue;
- if (Visit(MakeCursorVariableRef(cast<VarDecl>(C->getCapturedVar()),
- C->getLocation(), TU)))
- return true;
- }
- // Visit init captures
- for (auto InitExpr : E->capture_inits()) {
- if (InitExpr && Visit(InitExpr))
- return true;
+
+ if (const auto *CV = C->getCapturedVar(); CV && isa<VarDecl>(CV)) {
+ if (CV->isInitCapture()) {
+ // Init capture is a declaration, create VarDecl cursor
+ if (Visit(MakeCXCursor(cast<VarDecl>(CV), TU, RegionOfInterest)))
+ return true;
+ } else
+ // Non init capture is a VariableRef
+ if (Visit(MakeCursorVariableRef(cast<VarDecl>(CV), C->getLocation(),
+ TU)))
+ return true;
+ }
}
TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
>From 05f9b493a84a7cbaa63367313562c2c48ceae0e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Bedn=C3=A1r?= <martin at serafean.cz>
Date: Mon, 2 Mar 2026 16:45:59 +0100
Subject: [PATCH 2/3] Review changes and assertion fix
---
clang/tools/libclang/CIndex.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index d1b5cb8ebff87..03d0f5ca3c662 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -3902,14 +3902,17 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
CEnd = E->explicit_capture_end();
C != CEnd; ++C) {
- if (const auto *CV = C->getCapturedVar(); CV && isa<VarDecl>(CV)) {
+ if (!C->capturesVariable())
+ continue;
+
+ if (const auto *CV = dyn_cast_or_null<VarDecl>(C->getCapturedVar())) {
if (CV->isInitCapture()) {
// Init capture is a declaration, create VarDecl cursor
- if (Visit(MakeCXCursor(cast<VarDecl>(CV), TU, RegionOfInterest)))
+ if (Visit(MakeCXCursor(CV, TU, RegionOfInterest)))
return true;
} else
// Non init capture is a VariableRef
- if (Visit(MakeCursorVariableRef(cast<VarDecl>(CV), C->getLocation(),
+ if (Visit(MakeCursorVariableRef(CV, C->getLocation(),
TU)))
return true;
}
>From 0b50f623263bc9e3b9bf0b0d34ef4c0d8599cabc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Bedn=C3=A1r?= <martin at serafean.cz>
Date: Mon, 2 Mar 2026 16:50:59 +0100
Subject: [PATCH 3/3] release notes
---
clang/docs/ReleaseNotes.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8e3ddca5eb637..6561461d12523 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -383,7 +383,7 @@ clang-format
libclang
--------
-- visit identifier initializers in lambda capture as VarDecl
+- visit identifier initializers in lambda capture as VarDecl instead of VariableRef. Warning: this changes behaviour.
Code Completion
---------------
More information about the cfe-commits
mailing list