Skip to content

Commit 7f20c6c

Browse files
authored
[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.
1 parent 58c41b7 commit 7f20c6c

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ Bug Fixes to C++ Support
232232
"intializing multiple members of union" coincide (#GH149985).
233233
- Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. (#GH152729)
234234
- Fix the parsing of variadic member functions when the ellipis immediately follows a default argument.(#GH153445)
235+
- Fixed a bug that caused ``this`` captured by value in a lambda with a dependent explicit object parameter to not be
236+
instantiated properly. (#GH154054)
235237

236238
Bug Fixes to AST Handling
237239
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/TreeTransform.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14326,7 +14326,9 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
1432614326
// for type deduction, so we need to recompute it.
1432714327
//
1432814328
// Always recompute the type if we're in the body of a lambda, and
14329-
// 'this' is dependent on a lambda's explicit object parameter.
14329+
// 'this' is dependent on a lambda's explicit object parameter; we
14330+
// also need to always rebuild the expression in this case to clear
14331+
// the flag.
1433014332
QualType T = [&]() {
1433114333
auto &S = getSema();
1433214334
if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter())
@@ -14336,7 +14338,8 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
1433614338
return S.getCurrentThisType();
1433714339
}();
1433814340

14339-
if (!getDerived().AlwaysRebuild() && T == E->getType()) {
14341+
if (!getDerived().AlwaysRebuild() && T == E->getType() &&
14342+
!E->isCapturedByCopyInLambdaWithExplicitObjectParameter()) {
1434014343
// Mark it referenced in the new context regardless.
1434114344
// FIXME: this is a bit instantiation-specific.
1434214345
getSema().MarkThisReferenced(E);

clang/test/CodeGenCXX/cxx2b-deducing-this.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,55 @@ void test() {
264264
// CHECK: call void @_ZNH5P27971C1cERKS0_
265265
// CHECK: call void @_ZN5P27971C1cEi
266266
}
267+
268+
// This used to crash because we weren’t instantiating a dependent 'this'.
269+
namespace GH154054 {
270+
struct S {
271+
int x;
272+
auto byval() {
273+
return [*this](this auto) { return this->x; };
274+
}
275+
};
276+
277+
// CHECK-LABEL: define {{.*}} void @_ZN8GH1540544mainEv
278+
void main() {
279+
S s{ 42 };
280+
281+
// CHECK: call {{.*}} i32 @_ZZN8GH1540541S5byvalEvENHUlT_E_clIS2_EEDaS1_
282+
if ( s.byval()() != 42)
283+
__builtin_abort();
284+
}
285+
286+
// CHECK-LABEL: define {{.*}} i32 @_ZZN8GH1540541S5byvalEvENHUlT_E_clIS2_EEDaS1_(i32 %.coerce)
287+
// CHECK: entry:
288+
// CHECK: %0 = alloca %class.anon.11, align 4
289+
// CHECK: %coerce.dive = getelementptr inbounds nuw %class.anon.11, ptr %0, i32 0, i32 0
290+
// CHECK: %coerce.dive1 = getelementptr inbounds nuw %"struct.GH154054::S", ptr %coerce.dive, i32 0, i32 0
291+
// CHECK: store i32 %.coerce, ptr %coerce.dive1, align 4
292+
// CHECK: %1 = getelementptr inbounds nuw %class.anon.11, ptr %0, i32 0, i32 0
293+
// CHECK: %x = getelementptr inbounds nuw %"struct.GH154054::S", ptr %1, i32 0, i32 0
294+
// CHECK: %2 = load i32, ptr %x, align 4
295+
// CHECK: ret i32 %2
296+
297+
struct s {
298+
int q;
299+
auto f() {
300+
return [*this](this auto) { return this; };
301+
}
302+
};
303+
304+
// CHECK-LABEL: define {{.*}} void @_ZN8GH1540541fEv
305+
void f() {
306+
// CHECK: call {{.*}} ptr @_ZZN8GH1540541s1fEvENHUlT_E_clIS2_EEDaS1_
307+
s{}.f()();
308+
}
309+
310+
// CHECK-LABEL: define {{.*}} ptr @_ZZN8GH1540541s1fEvENHUlT_E_clIS2_EEDaS1_(i32 %.coerce)
311+
// CHECK: entry:
312+
// CHECK: %0 = alloca %class.anon.12, align 4
313+
// CHECK: %coerce.dive = getelementptr inbounds nuw %class.anon.12, ptr %0, i32 0, i32 0
314+
// CHECK: %coerce.dive1 = getelementptr inbounds nuw %"struct.GH154054::s", ptr %coerce.dive, i32 0, i32 0
315+
// CHECK: store i32 %.coerce, ptr %coerce.dive1, align 4
316+
// CHECK: %1 = getelementptr inbounds nuw %class.anon.12, ptr %0, i32 0, i32 0
317+
// CHECK: ret ptr %1
318+
}

0 commit comments

Comments
 (0)