diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7f76f87ce6be..eed26c00641a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -232,6 +232,8 @@ Bug Fixes to C++ Support "intializing multiple members of union" coincide (#GH149985). - Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. (#GH152729) - Fix the parsing of variadic member functions when the ellipis immediately follows a default argument.(#GH153445) +- Fixed a bug that caused ``this`` captured by value in a lambda with a dependent explicit object parameter to not be + instantiated properly. (#GH154054) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index bd3702591148..e55daece3c3e 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14326,7 +14326,9 @@ TreeTransform::TransformCXXThisExpr(CXXThisExpr *E) { // for type deduction, so we need to recompute it. // // Always recompute the type if we're in the body of a lambda, and - // 'this' is dependent on a lambda's explicit object parameter. + // 'this' is dependent on a lambda's explicit object parameter; we + // also need to always rebuild the expression in this case to clear + // the flag. QualType T = [&]() { auto &S = getSema(); if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter()) @@ -14336,7 +14338,8 @@ TreeTransform::TransformCXXThisExpr(CXXThisExpr *E) { return S.getCurrentThisType(); }(); - if (!getDerived().AlwaysRebuild() && T == E->getType()) { + if (!getDerived().AlwaysRebuild() && T == E->getType() && + !E->isCapturedByCopyInLambdaWithExplicitObjectParameter()) { // Mark it referenced in the new context regardless. // FIXME: this is a bit instantiation-specific. getSema().MarkThisReferenced(E); diff --git a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp index 8a78463d3a49..9664a866376a 100644 --- a/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp +++ b/clang/test/CodeGenCXX/cxx2b-deducing-this.cpp @@ -264,3 +264,55 @@ void test() { // CHECK: call void @_ZNH5P27971C1cERKS0_ // CHECK: call void @_ZN5P27971C1cEi } + +// This used to crash because we weren’t instantiating a dependent 'this'. +namespace GH154054 { +struct S { + int x; + auto byval() { + return [*this](this auto) { return this->x; }; + } +}; + +// CHECK-LABEL: define {{.*}} void @_ZN8GH1540544mainEv +void main() { + S s{ 42 }; + + // CHECK: call {{.*}} i32 @_ZZN8GH1540541S5byvalEvENHUlT_E_clIS2_EEDaS1_ + if ( s.byval()() != 42) + __builtin_abort(); +} + +// 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: %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: %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 + +struct s { + int q; + auto f() { + return [*this](this auto) { return this; }; + } +}; + +// CHECK-LABEL: define {{.*}} void @_ZN8GH1540541fEv +void f() { + // CHECK: call {{.*}} ptr @_ZZN8GH1540541s1fEvENHUlT_E_clIS2_EEDaS1_ + s{}.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: %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: ret ptr %1 +}