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
