https://github.com/xiaosa-zhz created 
https://github.com/llvm/llvm-project/pull/235816

This patch contains two parts. Part one is to add missing flag in 
`computeDependence`. It used to accidentally set only `ExprDependence::Type` 
without `ExprDependence::Value` and most importantly 
`ExprDependence::Instantiation`. The absense of flags leaked to all following 
pipelines, made substitution not happen when it should, and resulted in #125439 
and #163582.

Part two is to fix 
`FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter`. This 
function used to always check the object parameter of function prototype, even 
during halfway of instantiation. As a result, capture of lambda with explicit 
object parameter was always considered dependent even if the object parameter 
had been substituted into concrete type during current instantiation. This 
along with previous described defect caused #153493.

Self tested on x86_64 Ubuntu 26.04 LTS

Fixes #125439
Fixes #153493
Fixes #163582

Prepared with AI assistance. Used DeepSeek v4.1 Flash to browse other maybe 
related llvm issues, to jump into ten other rabbit holes of clang/Sema when I 
jump into one, and to write CHECKs in CodeGen tests.


>From 6c878e79dc97a2936348e4008fbb7d58a4ee69b6 Mon Sep 17 00:00:00 2001
From: xiaosaOvO <[email protected]>
Date: Mon, 26 Oct 2026 19:58:20 +0800
Subject: [PATCH 1/3] The Fix

---
 clang/lib/AST/ComputeDependence.cpp |  4 ++--
 clang/lib/Sema/SemaExpr.cpp         | 23 ++++++++++++++++++++---
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/clang/lib/AST/ComputeDependence.cpp 
b/clang/lib/AST/ComputeDependence.cpp
index 7ea1c67ff77389..c9ea0986500307 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -327,7 +327,7 @@ ExprDependence clang::computeDependence(CXXThisExpr *E) {
   // Note: The standard does not mention this case explicitly, but we need
   // to do this so we can mark NSDM accesses as dependent.
   if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter())
-    D |= ExprDependence::Type;
+    D |= ExprDependence::TypeValueInstantiation;
 
   assert(!(D & ExprDependence::UnexpandedPack));
   return D;
@@ -544,7 +544,7 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, 
const ASTContext &Ctx) {
   //    - an identifier associated by name lookup with an entity captured by
   //    copy ([expr.prim.lambda.capture])
   if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter())
-    Deps |= ExprDependence::Type;
+    Deps |= ExprDependence::TypeValueInstantiation;
 
   //    - a conversion-function-id that specifies a dependent type
   if (Decl->getDeclName().getNameKind() ==
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 43b0c86132172b..d43d19187cde1a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -21250,9 +21250,26 @@ static void 
FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter(
       if (MD->getType().isNull())
         continue;
 
-      const auto *Ty = MD->getType()->getAs<FunctionProtoType>();
-      if (!Ty || !MD->isExplicitObjectMemberFunction() ||
-          !Ty->getParamType(0)->isDependentType())
+      if (!MD->isExplicitObjectMemberFunction())
+        continue;
+
+      bool IsDependentObjectParam = [&]() {
+        const ParmVarDecl *ObjectParamDecl = MD->getParamDecl(0);
+        assert(ObjectParamDecl && "Shall explicit object parameter exist 
here.");
+        QualType ObjectParamType = ObjectParamDecl->getType();
+        // If we are in the middle of instantiation, try to use
+        // the real type of the deduced explicit object parameter.
+        if (auto *CIS = SemaRef.CurrentInstantiationScope) {
+          if (auto *Inst = CIS->getInstantiationOfIfExists(ObjectParamDecl)) {
+            auto *Deduced = dyn_cast<ParmVarDecl>(Inst->dyn_cast<Decl *>());
+            assert(Deduced);
+            ObjectParamType = Deduced->getType();
+          }
+        }
+        return ObjectParamType->isDependentType();
+      }();
+
+      if (!IsDependentObjectParam)
         continue;
 
       if (auto *C = LSI->CaptureMap.count(D) ? &LSI->getCapture(D) : nullptr) {

>From f20c834a5b4ba82a2ef32a3db38a9c60f2e1a65e Mon Sep 17 00:00:00 2001
From: xiaosaOvO <[email protected]>
Date: Mon, 26 Oct 2026 20:13:31 +0800
Subject: [PATCH 2/3] The Docs

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

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 44f30666457f94..def8d0da51dce0 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -891,6 +891,13 @@ documentation](CIR/index.md) for more information 
regarding ClangIR's status and
 #### Bug Fixes to C++ Support
 - Instantiate constexpr functions as needed before they are evaluated. 
(#GH73232) (#GH35052) (#GH100897)
 
+- Fixed missing dependence flag when try to decide whether by-value capture
+  of lambda with explicit object parameter is dependent. (#GH125439) 
(#GH163582)
+
+- Fixed incorrectly reference to object parameter of function prototype
+  rather than the one of current instantiation when try to decide whether
+  by-value capture of lambda with explicit object parameter is dependent. 
(#GH153493)
+
 - Fixed lambdas with specifiers or attributes after the capture list being
   misparsed as function declarations in direct-initialization contexts under
   `-fms-extensions` or in HLSL mode.

>From 00117586e266eebc059c24603425bcd11d046601 Mon Sep 17 00:00:00 2001
From: xiaosaOvO <[email protected]>
Date: Mon, 26 Oct 2026 22:52:41 +0800
Subject: [PATCH 3/3] The tests

---
 clang/test/CodeGenCXX/cxx2b-deducing-this.cpp | 39 ++++++++++--
 clang/test/SemaCXX/cxx2b-deducing-this.cpp    | 59 +++++++++++++++++++
 2 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp 
b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp
index 9664a866376ae8..9865cc159967f7 100644
--- a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp
@@ -265,6 +265,33 @@ void test() {
 // CHECK: call void @_ZN5P27971C1cEi
 }
 
+// This used to crash because capture is not set as instantiation dependent 
correctly,
+// and then the <dependent-type> leaks to the codegen step.
+namespace GH125439 {
+void main() {
+  int x = 0;
+  auto f = [x](this auto) { decltype(x) n; (void)x; };
+  f();
+}
+}
+// CHECK-LABEL: define {{.*}} void @_ZN8GH1254394mainEv()
+// CHECK: call void @"_ZZN8GH1254394mainEvE{{.*}}"
+// CHECK-LABEL: define {{.*}} void @"_ZZN8GH1254394mainEvE{{.*}}"
+
+// This used to crash because capture in return type did not see
+// the real type of deduced explicit object parameter during instantiation.
+namespace GH153493 {
+void main() {
+  auto f = [b = 0](this auto&&) -> decltype(b + 0) {
+    return b;
+  };
+  f();
+}
+}
+// CHECK-LABEL: define {{.*}} void @_ZN8GH1534934mainEv()
+// CHECK:       call {{.*}} i32 @"_ZZN8GH1534934mainEv{{.*}}"
+// CHECK-LABEL: define {{.*}} i32 @"_ZZN8GH1534934mainEv{{.*}}"
+
 // This used to crash because we weren’t instantiating a dependent 'this'.
 namespace GH154054 {
 struct S {
@@ -285,11 +312,11 @@ void main() {
 
 // CHECK-LABEL: define {{.*}} i32 
@_ZZN8GH1540541S5byvalEvENHUlT_E_clIS2_EEDaS1_(i32 %.coerce)
 // CHECK: entry:
-// CHECK:   %0 = alloca %class.anon.11, align 4
-// CHECK:   %coerce.dive = getelementptr inbounds nuw %class.anon.11, ptr %0, 
i32 0, i32 0
+// CHECK:   %0 = alloca %class.anon.13, align 4
+// CHECK:   %coerce.dive = getelementptr inbounds nuw %class.anon.13, ptr %0, 
i32 0, i32 0
 // CHECK:   %coerce.dive1 = getelementptr inbounds nuw %"struct.GH154054::S", 
ptr %coerce.dive, i32 0, i32 0
 // CHECK:   store i32 %.coerce, ptr %coerce.dive1, align 4
-// CHECK:   %1 = getelementptr inbounds nuw %class.anon.11, ptr %0, i32 0, i32 0
+// CHECK:   %1 = getelementptr inbounds nuw %class.anon.13, ptr %0, i32 0, i32 0
 // CHECK:   %x = getelementptr inbounds nuw %"struct.GH154054::S", ptr %1, i32 
0, i32 0
 // CHECK:   %2 = load i32, ptr %x, align 4
 // CHECK:   ret i32 %2
@@ -309,10 +336,10 @@ void f() {
 
 // CHECK-LABEL: define {{.*}} ptr 
@_ZZN8GH1540541s1fEvENHUlT_E_clIS2_EEDaS1_(i32 %.coerce)
 // CHECK: entry:
-// CHECK:   %0 = alloca %class.anon.12, align 4
-// CHECK:   %coerce.dive = getelementptr inbounds nuw %class.anon.12, ptr %0, 
i32 0, i32 0
+// CHECK:   %0 = alloca %class.anon.14, align 4
+// CHECK:   %coerce.dive = getelementptr inbounds nuw %class.anon.14, ptr %0, 
i32 0, i32 0
 // CHECK:   %coerce.dive1 = getelementptr inbounds nuw %"struct.GH154054::s", 
ptr %coerce.dive, i32 0, i32 0
 // CHECK:   store i32 %.coerce, ptr %coerce.dive1, align 4
-// CHECK:   %1 = getelementptr inbounds nuw %class.anon.12, ptr %0, i32 0, i32 0
+// CHECK:   %1 = getelementptr inbounds nuw %class.anon.14, ptr %0, i32 0, i32 0
 // CHECK:   ret ptr %1
 }
diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp 
b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
index 5dfc5bbf50abd3..097179457bddbb 100644
--- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp
+++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp
@@ -1404,6 +1404,65 @@ void f() {
 
 }
 
+// Capture is not set as instantiation dependent correctly
+namespace GH163582 {
+
+// Builtin __is_same(T, U) does not triger the bug
+template <class T, class U> constexpr bool is_same_v = false;
+template <class T> constexpr bool is_same_v<T, T> = true;
+
+struct S {
+  int x = 1;
+
+  void f() {
+    [n = 42](this auto&&) {
+      static_assert(is_same_v<decltype(n), int>);
+      static_assert(is_same_v<decltype((n)), int&>);
+      static_assert(is_same_v<decltype(n), short>); // expected-error {{static 
assertion failed}}
+    }(); // expected-note {{in instantiation of function template 
specialization}}
+
+    [n = 42](this const auto&) {
+      static_assert(is_same_v<decltype(n), int>);
+      static_assert(is_same_v<decltype((n)), const int&>);
+      static_assert(is_same_v<decltype(n), long>); // expected-error {{static 
assertion failed}}
+    }(); // expected-note {{in instantiation of function template 
specialization}}
+
+    [*this](this auto&&) {
+      static_assert(is_same_v<decltype(this), S*>);
+      static_assert(is_same_v<decltype(this), int>); // expected-error 
{{static assertion failed}}
+    }(); // expected-note {{in instantiation of function template 
specialization}}
+
+    [*this](this const auto&) {
+      static_assert(is_same_v<decltype(this), const S*>);
+      static_assert(is_same_v<decltype(this), void>); // expected-error 
{{static assertion failed}}
+    }(); // expected-note {{in instantiation of function template 
specialization}}
+
+    [&r = x](this const auto&) {
+      static_assert(is_same_v<decltype(r), int&>);
+    }();
+
+    const int y = 0;
+    [=, this](this auto&&) {
+      static_assert(is_same_v<decltype(this), S*>);
+      static_assert(is_same_v<decltype(x), int>);
+      static_assert(is_same_v<decltype((x)), int&>);
+      static_assert(is_same_v<decltype(y), const int>);
+      static_assert(is_same_v<decltype((y)), const int&>);
+      [&, *this](this const auto&) {
+        [=, this](this auto&&) {
+          static_assert(is_same_v<decltype(this), const S*>);
+          static_assert(is_same_v<decltype(x), int>);
+          static_assert(is_same_v<decltype((x)), const int&>);
+          static_assert(is_same_v<decltype(y), const int>);
+          static_assert(is_same_v<decltype((y)), const int&>);
+        }();
+      }();
+    }();
+  }
+};
+
+} // namespace GH163582
+
 namespace GH173943 {
 
 a void Bar(this int) { // expected-note {{candidate function}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to