llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: xiaosa-zhz

<details>
<summary>Changes</summary>

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.


---
Full diff: https://github.com/llvm/llvm-project/pull/235816.diff


5 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+7) 
- (modified) clang/lib/AST/ComputeDependence.cpp (+2-2) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+20-3) 
- (modified) clang/test/CodeGenCXX/cxx2b-deducing-this.cpp (+33-6) 
- (modified) clang/test/SemaCXX/cxx2b-deducing-this.cpp (+59) 


``````````diff
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.
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) {
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}}

``````````

</details>


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

Reply via email to