]> granicus.if.org Git - clang/commitdiff
Factor out commonality between variable capture initialization and
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 2 Jun 2019 04:00:43 +0000 (04:00 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 2 Jun 2019 04:00:43 +0000 (04:00 +0000)
'this' capture initialization.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362317 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Initialization.h
include/clang/Sema/Sema.h
lib/Sema/SemaLambda.cpp
lib/Sema/SemaStmt.cpp
test/AST/ast-dump-expr-json.cpp
test/AST/ast-dump-expr.cpp

index 8efa2e7597cb0694d979765eb140b30f3cfc3f78..14d8aa8dabf3098a402e8bb58124349e39af049a 100644 (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
index 3e128df7fba2a876a24734ab1c8b6cf0eab559ed..a6db2f046bbd9dcaff576e3f2696305df660aeb0 100644 (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,
index d3f3b60926fa3a107a7b630ab4a28c6ae88fad4a..4b832f5653025bfde36d23f106c798d9be5e90ae 100644 (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;
-
-  // 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 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())
+  }
+
+  // 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(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());
     }
 
index 3a7acd20274ecf2ee409492c9f08b2882501ad33..bc1e8f27090afd45760a0bdb48060fe6b4e3c3c8 100644 (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;
-    }
-
-    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;
index 3a8e745e50f3e9645f399048779dfbb06e2c3409..d56d79d8c16710f7996ec4655424d4ea39fd5ad1 100644 (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{{.*}}",
index 47f69a882ecbae80acb2c66059ee1bbc13ce51e0..f04c311c63470e1a448396ad94cb57ddca1739df 100644 (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]{};