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
