Factor out commonality between variable capture initialization and

'this' capture initialization.

llvm-svn: 362317
This commit is contained in:
Richard Smith 2019-06-02 04:00:43 +00:00
parent 2e2c02c0cd
commit e518235aca
6 changed files with 149 additions and 115 deletions

View File

@ -386,6 +386,8 @@ public:
}
/// Create the initialization entity for a lambda capture.
///
/// \p VarID The name of the entity being captured, or nullptr for 'this'.
static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID,
QualType FieldType,
SourceLocation Loc) {
@ -509,7 +511,7 @@ public:
/// For a lambda capture, return the capture's name.
StringRef getCapturedVarName() const {
assert(getKind() == EK_LambdaCapture && "Not a lambda capture!");
return Capture.VarID->getName();
return Capture.VarID ? Capture.VarID->getName() : "this";
}
/// Determine the location of the capture when initializing

View File

@ -5291,11 +5291,6 @@ public:
const unsigned *const FunctionScopeIndexToStopAt = nullptr,
bool ByCopy = false);
/// Initialize the given 'this' capture with a suitable 'this' or '*this'
/// expression.
ExprResult performThisCaptureInitialization(const sema::Capture &Capture,
bool IsImplicit);
/// Determine whether the given type is the type of *this that is used
/// outside of the body of a member function for a type that is currently
/// being defined.
@ -5808,6 +5803,11 @@ public:
/// Build a FieldDecl suitable to hold the given capture.
FieldDecl *BuildCaptureField(RecordDecl *RD, const sema::Capture &Capture);
/// Initialize the given capture with a suitable expression.
ExprResult BuildCaptureInit(const sema::Capture &Capture,
SourceLocation ImplicitCaptureLoc,
bool IsOpenMPMapping = false);
/// Complete a lambda-expression having processed and attached the
/// lambda body.
ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,

View File

@ -1431,32 +1431,22 @@ static void addBlockPointerConversion(Sema &S,
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;
ExprResult Sema::BuildCaptureInit(const Capture &Cap,
SourceLocation ImplicitCaptureLoc,
bool IsOpenMPMapping) {
// VLA captures don't have a stored initialization expression.
if (Cap.isVLATypeCapture())
return ExprResult();
// 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);
}
// An init-capture is initialized directly from its stored initializer.
if (Cap.isInitCapture())
return Cap.getVariable()->getInit();
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();
// 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
@ -1470,17 +1460,39 @@ static ExprResult performLambdaVarCaptureInitialization(
// 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())
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);
// 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 *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,
@ -1647,14 +1659,18 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
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) {
@ -1682,46 +1698,43 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
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());
}

View File

@ -4231,39 +4231,35 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
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;
} else {
assert(Cap.isVariableCapture() && "unknown kind of capture");
if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
Cap.isReferenceCapture()
? CapturedStmt::VCK_ByRef
: CapturedStmt::VCK_ByCopy,
Cap.getVariable()));
}
if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
VarDecl *Var = Cap.getVariable();
SourceLocation Loc = Cap.getLocation();
// 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);
Captures.push_back(CapturedStmt::Capture(Loc,
Cap.isReferenceCapture()
? CapturedStmt::VCK_ByRef
: CapturedStmt::VCK_ByCopy,
Var));
CaptureInits.push_back(Init.get());
}
return false;

View File

@ -3924,24 +3924,46 @@ void TestNonADLCall3() {
// 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{{.*}}",

View File

@ -255,6 +255,7 @@ void PrimaryExpressions(Ts... a) {
// CHECK-NEXT: CXXMethodDecl
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:8> col:8 implicit 'V *'
// CHECK-NEXT: ParenListExpr
// CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' this
[*this]{};