[Clang] [Sema] Always rebuild this if captured by value in a lambda with a dependent explicit object parameter (#154276)

We have a flag that tracks whether a `CXXThisExpr` refers to a `*this`
capture in a lambda with a dependent explicit object parameter; this is
to mark it and member accesses involving it as dependent because there
is no other way to track that (DREs have a similar flag); when
instantiating the lambda, we need to always rebuild the `CXXThisExpr` to
potentially clear that flag if the explicit object parameter is no
longer dependent.

Fixes #154054.
This commit is contained in:
Sirraide 2025-08-20 00:37:48 +02:00 committed by GitHub
parent 58c41b7491
commit 7f20c6c29e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 2 deletions

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -14326,7 +14326,9 @@ TreeTransform<Derived>::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<Derived>::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);

View File

@ -264,3 +264,55 @@ void test() {
// CHECK: call void @_ZNH5P27971C1cERKS0_
// CHECK: call void @_ZN5P27971C1cEi
}
// This used to crash because we werent 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
}