This is an archive of the discontinued LLVM Phabricator instance.

[Cxx1z] Implement Lambda Capture of *this by Value as [=,*this] (P0018R3)
ClosedPublic

Authored by faisalv on Mar 13 2016, 9:02 PM.

Details

Reviewers
rsmith
Summary

Implement lambda capture of *this.

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);

Diff Detail

Event Timeline

faisalv updated this revision to Diff 50568.Mar 13 2016, 9:02 PM
faisalv retitled this revision from to [Cxx1z] Implement Lambda Capture of *this by Value as [=,*this] (P0018R3).
faisalv updated this object.
faisalv added a reviewer: rsmith.
faisalv added a subscriber: cfe-commits.
faisalv updated this revision to Diff 50621.Mar 14 2016, 11:44 AM

Add warnings and extension diagnostics for C++1z, and refactor the codegen portion, simplifying it further.
Thanks!

rsmith added inline comments.Mar 14 2016, 3:49 PM
include/clang/AST/LambdaCapture.h
53

I'm not a fan of this representation. Please use Capture_ByCopy to indicate a by-copy capture of *this. It's probably time to clean up DeclAndBits a little. Something like this should work:

struct LLVM_ALIGNAS(4) OpaqueCapturedEntity {};
llvm::PointerIntPair<void*, 2> CapturedEntityAndBits;
static OpaqueCapturedEntity StarThis;
static OpaqueCapturedEntity VLAType;

where the void* is either a Decl* or points to StarThis or VLAType.

include/clang/Basic/Lambda.h
35–36

-> Capturing the \c *this object by reference?

include/clang/Sema/ScopeInfo.h
414–417

Please try to integrate this into the existing code rather than adding it as a separate thing on the side. Again, we can model this and *this as capturing the same entity either by reference or by value, and we should do so.

455–468

In particular: don't add isStarThisCapture, just use isThisCapture and isCopyCapture/isReferenceCapture to distinguish between this and *this.

lib/AST/ExprCXX.cpp
894

Add // Fall through comment.

lib/Parse/ParseExprCXX.cpp
850

You don't need lookahead for this; if the current token is *, you can consume that token then look for this. It's an error if something else comes next.

857–860

We shouldn't produce this warning during disambiguation between a lambda and an Obj-C message send or designator. Please move the diagnostic into Sema instead.

lib/Sema/SemaDecl.cpp
10994

Use C.getCaptureKind() rather than querying the type of the field directly here.

lib/Sema/SemaExpr.cpp
13256

Just delete this parameter? (As a separate change, though.)

lib/Sema/SemaExprCXX.cpp
841–849

(Only somewhat related to the current change...) This looks wrong. If we're in a lambda within a lambda within a default member initializer, we need to recurse up more parents to find the right context. Looks like we should be walking up to the parent of the closure type, checking whether that is itself a lambda, and if so, recursing, until we reach a class or a function that isn't a lambda call operator. And we should accumulate the constness of *this on the way.

919

Please don't invent a fake identifier *this here. Instead, directly pass the fact that the capture in question is a capture of *this.

929–932

Please assert(!ByCopy || Explicit) here (we cannot implicitly capture *this by value).

982

This looks wrong: for all scopes other than the innermost one, if *this is not already captured (explicitly) then it should always be captured by reference.

lib/Sema/SemaLambda.cpp
943

Just make this change?

faisalv marked 14 inline comments as done.Mar 14 2016, 10:32 PM

Thanks for the review! An updated patch that should address your concerns will follow in a few mins.

I'm still not entirely sure I follow your comment about the intialized-entity: 'directly pass the fact that the capture in question is a capture of *this'.

lib/Sema/SemaExprCXX.cpp
841–849

Thanks for taking a look at this. Agreed - I'll submit this as a separate fix - added a fixme.

919

OK - I don't invent a fake identifier and instead pass in nullptr - but to be honest, I'm not sure what you mean by 'directly pass the fact that the capture in question is a capture of *this'

982

You're absolutely right. Fixed. [=] { return [*this] { return m; }; }; will now emit the right code.

faisalv updated this revision to Diff 50698.Mar 14 2016, 10:37 PM
faisalv marked 3 inline comments as done.

Updated patch that should incorporate Richard's feedback.

Thanks!

faisalv updated this revision to Diff 50757.Mar 15 2016, 11:19 AM

Added some more comments (hopefully didn't go overboard).

Thanks again for reviewing Richard!

rsmith accepted this revision.Mar 18 2016, 8:30 AM
rsmith edited edge metadata.

LGTM, thanks!

include/clang/AST/LambdaCapture.h
48

"by VLA capture" -> "capture of a VLA type"?

include/clang/Basic/DiagnosticSemaKinds.td
5982

star-this -> *this

5984–5987

by value capture of '*this' -> capture of '*this' by copy

lib/Sema/SemaExprCXX.cpp
994

You don't need this flag; instead, check Explicit && idx == MaxFunctionScopesIndex here.

1033

Likewise here.

This revision is now accepted and ready to land.Mar 18 2016, 8:30 AM

Couple more things:

  1. Please add some testing to tests/CXX/expr/expr.prim/expr.prim.lambda
  2. Please update cxx_status.html