r362317 - Factor out commonality between variable capture initialization and
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 1 21:00:43 PDT 2019
Author: rsmith
Date: Sat Jun 1 21:00:43 2019
New Revision: 362317
URL: http://llvm.org/viewvc/llvm-project?rev=362317&view=rev
Log:
Factor out commonality between variable capture initialization and
'this' capture initialization.
Modified:
cfe/trunk/include/clang/Sema/Initialization.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaLambda.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/test/AST/ast-dump-expr-json.cpp
cfe/trunk/test/AST/ast-dump-expr.cpp
Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=362317&r1=362316&r2=362317&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Sat Jun 1 21:00:43 2019
@@ -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
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=362317&r1=362316&r2=362317&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Jun 1 21:00:43 2019
@@ -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,
Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=362317&r1=362316&r2=362317&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Sat Jun 1 21:00:43 2019
@@ -1431,32 +1431,22 @@ static void addBlockPointerConversion(Se
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
@@ -1470,17 +1460,39 @@ static ExprResult performLambdaVarCaptur
// 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,
@@ -1647,14 +1659,18 @@ ExprResult Sema::BuildLambdaExpr(SourceL
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(SourceL
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()));
-
- ExprResult Init =
- From.isInitCapture()
- ? Var->getInit()
- : performLambdaVarCaptureInitialization(
- *this, From, Field, CaptureDefaultLoc, IsImplicit);
+ // 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.
+
+ // Add a FieldDecl for the capture and form its initializer.
+ BuildCaptureField(Class, From);
+ Captures.push_back(Capture);
CaptureInits.push_back(Init.get());
}
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=362317&r1=362316&r2=362317&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Sat Jun 1 21:00:43 2019
@@ -4231,39 +4231,35 @@ buildCapturedStmtCaptureList(Sema &S, Ca
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);
+ } else {
+ assert(Cap.isVariableCapture() && "unknown kind of capture");
- VarDecl *Var = Cap.getVariable();
- SourceLocation Loc = Cap.getLocation();
+ if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
+ S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
- // 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));
+ Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
+ Cap.isReferenceCapture()
+ ? CapturedStmt::VCK_ByRef
+ : CapturedStmt::VCK_ByCopy,
+ Cap.getVariable()));
+ }
CaptureInits.push_back(Init.get());
}
return false;
Modified: cfe/trunk/test/AST/ast-dump-expr-json.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-expr-json.cpp?rev=362317&r1=362316&r2=362317&view=diff
==============================================================================
--- cfe/trunk/test/AST/ast-dump-expr-json.cpp (original)
+++ cfe/trunk/test/AST/ast-dump-expr-json.cpp Sat Jun 1 21:00:43 2019
@@ -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: "type": {
+// CHECK-NEXT: "qualType": "NULL TYPE"
// 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: "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{{.*}}",
Modified: cfe/trunk/test/AST/ast-dump-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/AST/ast-dump-expr.cpp?rev=362317&r1=362316&r2=362317&view=diff
==============================================================================
--- cfe/trunk/test/AST/ast-dump-expr.cpp (original)
+++ cfe/trunk/test/AST/ast-dump-expr.cpp Sat Jun 1 21:00:43 2019
@@ -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]{};
More information about the cfe-commits
mailing list