From dc6b596ebbd3c594c75fc6c6bc6cb7c14fdcec24 Mon Sep 17 00:00:00 2001 From: Faisal Vali Date: Mon, 21 Mar 2016 09:25:37 +0000 Subject: [Cxx1z] Implement Lambda Capture of *this by Value as [=,*this] (P0018R3) Implement lambda capture of *this by copy. For e.g.: struct A { int d = 10; auto foo() { return [*this] (auto a) mutable { d+=a; return d; }; } }; auto L = A{}.foo(); // A{}'s lifetime is gone. // Below is still ok, because *this was captured by value. assert(L(10) == 20); assert(L(100) == 120); If the capture was implicit, or [this] (i.e. *this was captured by reference), this code would be otherwise undefined. Implementation Strategy: - amend the parser to accept *this in the lambda introducer - add a new king of capture LCK_StarThis - teach Sema::CheckCXXThisCapture to handle by copy captures of the enclosing object (i.e. *this) - when CheckCXXThisCapture does capture by copy, the corresponding initializer expression for the closure's data member direct-initializes it thus making a copy of '*this'. - in codegen, when assigning to CXXThisValue, if *this was captured by copy, make sure it points to the corresponding field member, and not, unlike when captured by reference, what the field member points to. - mark feature as implemented in svn Much gratitude to Richard Smith for his carefully illuminating reviews! llvm-svn: 263921 --- clang/lib/CodeGen/CodeGenFunction.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'clang/lib/CodeGen/CodeGenFunction.cpp') diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ac03223..71c364c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -823,10 +823,22 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, MD->getParent()->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); if (LambdaThisCaptureField) { - // If this lambda captures this, load it. - LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField); - CXXThisValue = EmitLoadOfLValue(ThisLValue, - SourceLocation()).getScalarVal(); + // If the lambda captures the object referred to by '*this' - either by + // value or by reference, make sure CXXThisValue points to the correct + // object. + + // Get the lvalue for the field (which is a copy of the enclosing object + // or contains the address of the enclosing object). + LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); + if (!LambdaThisCaptureField->getType()->isPointerType()) { + // If the enclosing object was captured by value, just use its address. + CXXThisValue = ThisFieldLValue.getAddress().getPointer(); + } else { + // Load the lvalue pointed to by the field, since '*this' was captured + // by reference. + CXXThisValue = + EmitLoadOfLValue(ThisFieldLValue, SourceLocation()).getScalarVal(); + } } for (auto *FD : MD->getParent()->fields()) { if (FD->hasCapturedVLAType()) { -- cgit v1.1