Class->addDecl(Conversion);
}
-ExprResult Sema::performThisCaptureInitialization(const Capture &Cap,
- bool IsImplicit) {
- QualType ThisTy = getCurrentThisType();
- SourceLocation Loc = Cap.getLocation();
- Expr *This = BuildCXXThisExpr(Loc, ThisTy, IsImplicit);
- if (Cap.isReferenceCapture())
- return This;
-
- // Capture (by copy) of '*this'.
- Expr *StarThis = CreateBuiltinUnaryOp(Loc, UO_Deref, This).get();
- InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture(
- nullptr, Cap.getCaptureType(), Loc);
- InitializationKind InitKind =
- InitializationKind::CreateDirect(Loc, Loc, Loc);
- InitializationSequence Init(*this, Entity, InitKind, StarThis);
- return Init.Perform(*this, Entity, InitKind, StarThis);
-}
-
-static ExprResult performLambdaVarCaptureInitialization(
- Sema &S, const Capture &Capture, FieldDecl *Field,
- SourceLocation ImplicitCaptureLoc, bool IsImplicitCapture) {
- assert(Capture.isVariableCapture() && "not a variable capture");
-
- auto *Var = Capture.getVariable();
+ExprResult Sema::BuildCaptureInit(const Capture &Cap,
+ SourceLocation ImplicitCaptureLoc,
+ bool IsOpenMPMapping) {
+ // VLA captures don't have a stored initialization expression.
+ if (Cap.isVLATypeCapture())
+ return ExprResult();
+
+ // An init-capture is initialized directly from its stored initializer.
+ if (Cap.isInitCapture())
+ return Cap.getVariable()->getInit();
+
+ // For anything else, build an initialization expression. For an implicit
+ // capture, the capture notionally happens at the capture-default, so use
+ // that location here.
SourceLocation Loc =
- IsImplicitCapture ? ImplicitCaptureLoc : Capture.getLocation();
+ ImplicitCaptureLoc.isValid() ? ImplicitCaptureLoc : Cap.getLocation();
// C++11 [expr.prim.lambda]p21:
// When the lambda-expression is evaluated, the entities that
// C++ [expr.prim.lambda]p12:
// An entity captured by a lambda-expression is odr-used (3.2) in
// the scope containing the lambda-expression.
- ExprResult RefResult = S.BuildDeclarationNameExpr(
+ ExprResult Init;
+ IdentifierInfo *Name = nullptr;
+ if (Cap.isThisCapture()) {
+ QualType ThisTy = getCurrentThisType();
+ Expr *This = BuildCXXThisExpr(Loc, ThisTy, ImplicitCaptureLoc.isValid());
+ if (Cap.isCopyCapture())
+ Init = CreateBuiltinUnaryOp(Loc, UO_Deref, This);
+ else
+ Init = This;
+ } else {
+ assert(Cap.isVariableCapture() && "unknown kind of capture");
+ VarDecl *Var = Cap.getVariable();
+ Name = Var->getIdentifier();
+ Init = BuildDeclarationNameExpr(
CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
- if (RefResult.isInvalid())
+ }
+
+ // In OpenMP, the capture kind doesn't actually describe how to capture:
+ // variables are "mapped" onto the device in a process that does not formally
+ // make a copy, even for a "copy capture".
+ if (IsOpenMPMapping)
+ return Init;
+
+ if (Init.isInvalid())
return ExprError();
- Expr *Ref = RefResult.get();
- auto Entity = InitializedEntity::InitializeLambdaCapture(
- Var->getIdentifier(), Field->getType(), Loc);
- InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc);
- InitializationSequence Init(S, Entity, InitKind, Ref);
- return Init.Perform(S, Entity, InitKind, Ref);
+ Expr *InitExpr = Init.get();
+ InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture(
+ Name, Cap.getCaptureType(), Loc);
+ InitializationKind InitKind =
+ InitializationKind::CreateDirect(Loc, Loc, Loc);
+ InitializationSequence InitSeq(*this, Entity, InitKind, InitExpr);
+ return InitSeq.Perform(*this, Entity, InitKind, InitExpr);
}
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
assert(!From.isBlockCapture() && "Cannot capture __block variables");
bool IsImplicit = I >= LSI->NumExplicitCaptures;
+ SourceLocation ImplicitCaptureLoc =
+ IsImplicit ? CaptureDefaultLoc : SourceLocation();
// Use source ranges of explicit captures for fixits where available.
SourceRange CaptureRange = LSI->ExplicitCaptureRanges[I];
// Warn about unused explicit captures.
bool IsCaptureUsed = true;
- if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
+ if (!CurContext->isDependentContext() && !IsImplicit &&
+ !From.isODRUsed()) {
// Initialized captures that are non-ODR used may not be eliminated.
+ // FIXME: Where did the IsGenericLambda here come from?
bool NonODRUsedInitCapture =
IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
if (!NonODRUsedInitCapture) {
PrevCaptureLoc = CaptureRange.getEnd();
}
- // Add a FieldDecl for the capture.
- FieldDecl *Field = BuildCaptureField(Class, From);
-
- // Handle 'this' capture.
- if (From.isThisCapture()) {
- // Capturing 'this' implicitly with a default of '[=]' is deprecated,
- // because it results in a reference capture. Don't warn prior to
- // C++2a; there's nothing that can be done about it before then.
- if (getLangOpts().CPlusPlus2a && IsImplicit &&
- CaptureDefault == LCD_ByCopy) {
- Diag(From.getLocation(), diag::warn_deprecated_this_capture);
- Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture)
- << FixItHint::CreateInsertion(
- getLocForEndOfToken(CaptureDefaultLoc), ", this");
+ // Map the capture to our AST representation.
+ LambdaCapture Capture = [&] {
+ if (From.isThisCapture()) {
+ // Capturing 'this' implicitly with a default of '[=]' is deprecated,
+ // because it results in a reference capture. Don't warn prior to
+ // C++2a; there's nothing that can be done about it before then.
+ if (getLangOpts().CPlusPlus2a && IsImplicit &&
+ CaptureDefault == LCD_ByCopy) {
+ Diag(From.getLocation(), diag::warn_deprecated_this_capture);
+ Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture)
+ << FixItHint::CreateInsertion(
+ getLocForEndOfToken(CaptureDefaultLoc), ", this");
+ }
+ return LambdaCapture(From.getLocation(), IsImplicit,
+ From.isCopyCapture() ? LCK_StarThis : LCK_This);
+ } else if (From.isVLATypeCapture()) {
+ return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
+ } else {
+ assert(From.isVariableCapture() && "unknown kind of capture");
+ VarDecl *Var = From.getVariable();
+ LambdaCaptureKind Kind =
+ From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
+ return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
+ From.getEllipsisLoc());
}
+ }();
- ExprResult Init = performThisCaptureInitialization(From, IsImplicit);
- Captures.push_back(
- LambdaCapture(From.getLocation(), IsImplicit,
- From.isCopyCapture() ? LCK_StarThis : LCK_This));
- CaptureInits.push_back(Init.get());
- continue;
- }
- if (From.isVLATypeCapture()) {
- Captures.push_back(
- LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType));
- CaptureInits.push_back(nullptr);
- continue;
- }
+ // Form the initializer for the capture field.
+ ExprResult Init = BuildCaptureInit(From, ImplicitCaptureLoc);
- VarDecl *Var = From.getVariable();
- LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
- Captures.push_back(LambdaCapture(From.getLocation(), IsImplicit, Kind,
- Var, From.getEllipsisLoc()));
+ // FIXME: Skip this capture if the capture is not used, the initializer
+ // has no side-effects, the type of the capture is trivial, and the
+ // lambda is not externally visible.
- ExprResult Init =
- From.isInitCapture()
- ? Var->getInit()
- : performLambdaVarCaptureInitialization(
- *this, From, Field, CaptureDefaultLoc, IsImplicit);
+ // Add a FieldDecl for the capture and form its initializer.
+ BuildCaptureField(Class, From);
+ Captures.push_back(Capture);
CaptureInits.push_back(Init.get());
}
if (Cap.isInvalid())
continue;
+ // Form the initializer for the capture.
+ ExprResult Init = S.BuildCaptureInit(Cap, Cap.getLocation(),
+ RSI->CapRegionKind == CR_OpenMP);
+
+ // FIXME: Bail out now if the capture is not used and the initializer has
+ // no side-effects.
+
// Create a field for this capture.
FieldDecl *Field = S.BuildCaptureField(RSI->TheRecordDecl, Cap);
+ // Add the capture to our list of captures.
if (Cap.isThisCapture()) {
- ExprResult Init =
- S.performThisCaptureInitialization(Cap, /*Implicit*/ true);
Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
CapturedStmt::VCK_This));
- CaptureInits.push_back(Init.get());
- continue;
} else if (Cap.isVLATypeCapture()) {
Captures.push_back(
CapturedStmt::Capture(Cap.getLocation(), CapturedStmt::VCK_VLAType));
- CaptureInits.push_back(nullptr);
- continue;
- }
-
- if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
- S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
-
- VarDecl *Var = Cap.getVariable();
- SourceLocation Loc = Cap.getLocation();
+ } else {
+ assert(Cap.isVariableCapture() && "unknown kind of capture");
- // FIXME: For a non-reference capture, we need to build an expression to
- // perform a copy here!
- ExprResult Init = S.BuildDeclarationNameExpr(
- CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
+ if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
+ S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
- Captures.push_back(CapturedStmt::Capture(Loc,
- Cap.isReferenceCapture()
- ? CapturedStmt::VCK_ByRef
- : CapturedStmt::VCK_ByCopy,
- Var));
+ Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
+ Cap.isReferenceCapture()
+ ? CapturedStmt::VCK_ByRef
+ : CapturedStmt::VCK_ByCopy,
+ Cap.getVariable()));
+ }
CaptureInits.push_back(Init.get());
}
return false;
// CHECK-NEXT: ]
// CHECK-NEXT: },
// CHECK-NEXT: {
-// CHECK-NEXT: "id": "0x{{.*}}",
-// CHECK-NEXT: "kind": "CXXThisExpr",
-// CHECK-NEXT: "range": {
-// CHECK-NEXT: "begin": {
-// CHECK-NEXT: "col": 8,
-// CHECK-NEXT: "file": "{{.*}}",
-// CHECK-NEXT: "line": 98
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "ParenListExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 8,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 98
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 8,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 98
+// CHECK-NEXT: }
// CHECK-NEXT: },
-// CHECK-NEXT: "end": {
-// CHECK-NEXT: "col": 8,
-// CHECK-NEXT: "file": "{{.*}}",
-// CHECK-NEXT: "line": 98
-// CHECK-NEXT: }
-// CHECK-NEXT: },
-// CHECK-NEXT: "type": {
-// CHECK-NEXT: "qualType": "V *"
-// CHECK-NEXT: },
-// CHECK-NEXT: "valueCategory": "rvalue"
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "NULL TYPE"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue",
+// CHECK-NEXT: "inner": [
+// CHECK-NEXT: {
+// CHECK-NEXT: "id": "0x{{.*}}",
+// CHECK-NEXT: "kind": "CXXThisExpr",
+// CHECK-NEXT: "range": {
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "col": 8,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 98
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "col": 8,
+// CHECK-NEXT: "file": "{{.*}}",
+// CHECK-NEXT: "line": 98
+// CHECK-NEXT: }
+// CHECK-NEXT: },
+// CHECK-NEXT: "type": {
+// CHECK-NEXT: "qualType": "V *"
+// CHECK-NEXT: },
+// CHECK-NEXT: "valueCategory": "rvalue"
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",