]> granicus.if.org Git - clang/commitdiff
Defer building 'this' captures until we have left the capturing region
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 31 May 2019 01:17:04 +0000 (01:17 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 31 May 2019 01:17:04 +0000 (01:17 +0000)
and returned to the context in which 'this' should be captured.

This means we now always mark 'this' referenced from the context in
which it's actually referenced, rather than potentially from some
context nested within that.

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

include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaStmt.cpp
test/AST/ast-dump-expr-json.cpp
test/AST/ast-dump-expr.cpp
test/SemaCXX/lambda-expressions.cpp

index 215025c62d29fb2fa7def9d69e8064def53e22b1..177c88d7e8475128b84188221038055d37656dff 100644 (file)
@@ -517,11 +517,6 @@ class Capture {
     VarDecl *CapturedVar;
   };
 
-  /// Expression to initialize a field of the given type. This is only required
-  /// if we are capturing ByVal and the variable's type has a non-trivial copy
-  /// constructor.
-  Expr *InitExpr = nullptr;
-
   /// The source location at which the first capture occurred.
   SourceLocation Loc;
 
@@ -566,8 +561,8 @@ public:
 
   enum IsThisCapture { ThisCapture };
   Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
-          QualType CaptureType, Expr *Cpy, const bool ByCopy, bool Invalid)
-      : InitExpr(Cpy), Loc(Loc), CaptureType(CaptureType),
+          QualType CaptureType, const bool ByCopy, bool Invalid)
+      : Loc(Loc), CaptureType(CaptureType),
         Kind(ByCopy ? Cap_ByCopy : Cap_ByRef), Nested(IsNested),
         CapturesThis(true), ODRUsed(false), NonODRUsed(false),
         Invalid(Invalid) {}
@@ -626,11 +621,6 @@ public:
   /// the type of the non-static data member in the lambda/block structure
   /// that would store this capture.
   QualType getCaptureType() const { return CaptureType; }
-
-  Expr *getThisInitExpr() const {
-    assert(isThisCapture() && "no 'this' init expression for non-this capture");
-    return InitExpr;
-  }
 };
 
 class CapturingScopeInfo : public FunctionScopeInfo {
@@ -681,7 +671,7 @@ public:
   }
 
   void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType,
-                      Expr *Cpy, bool ByCopy);
+                      bool ByCopy);
 
   /// Determine whether the C++ 'this' is captured.
   bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; }
@@ -1025,12 +1015,12 @@ void FunctionScopeInfo::recordUseOfWeak(const ExprT *E, bool IsRead) {
   Uses.push_back(WeakUseTy(E, IsRead));
 }
 
-inline void
-CapturingScopeInfo::addThisCapture(bool isNested, SourceLocation Loc,
-                                   QualType CaptureType, Expr *Cpy,
-                                   const bool ByCopy) {
+inline void CapturingScopeInfo::addThisCapture(bool isNested,
+                                               SourceLocation Loc,
+                                               QualType CaptureType,
+                                               bool ByCopy) {
   Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType,
-                             Cpy, ByCopy, /*Invalid*/ false));
+                             ByCopy, /*Invalid*/ false));
   CXXThisCaptureIndex = Captures.size();
 }
 
index 7ec9f4737b212e1b293fa38a3cfc75e36ca93369..3e128df7fba2a876a24734ab1c8b6cf0eab559ed 100644 (file)
@@ -5291,6 +5291,11 @@ 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.
index 759eb531c50fe7603cd70c126b2c8e3d803dd536..6bd7b4e0711016de04b6680aa6a63822944cd072 100644 (file)
@@ -12943,7 +12943,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
 
     } else if (C.capturesThis()) {
       LSI->addThisCapture(/*Nested*/ false, C.getLocation(), I->getType(),
-                          /*Expr*/ nullptr, C.getCaptureKind() == LCK_StarThis);
+                          C.getCaptureKind() == LCK_StarThis);
     } else {
       LSI->addVLATypeCapture(C.getLocation(), I->getCapturedVLAType(),
                              I->getType());
index 6e67968929ad079f949741ebb3193b91be70754b..ac050fa1ef55cdd80cc5830799fa023e29fc6f02 100644 (file)
@@ -1134,24 +1134,6 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() {
   }
 }
 
-static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD,
-                         QualType ThisTy, QualType CaptureType,
-                         SourceLocation Loc, const bool ByCopy) {
-  Expr *This = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/ true);
-  if (ByCopy) {
-    Expr *StarThis = S.CreateBuiltinUnaryOp(Loc, UO_Deref, This).get();
-    InitializedEntity Entity =
-        InitializedEntity::InitializeLambdaCapture(nullptr, CaptureType, Loc);
-    InitializationKind InitKind =
-        InitializationKind::CreateDirect(Loc, Loc, Loc);
-    InitializationSequence Init(S, Entity, InitKind, StarThis);
-    ExprResult ER = Init.Perform(S, Entity, InitKind, StarThis);
-    if (ER.isInvalid()) return nullptr;
-    return ER.get();
-  }
-  return This;
-}
-
 bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
     bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt,
     const bool ByCopy) {
@@ -1241,13 +1223,10 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
           dyn_cast<LambdaScopeInfo>(FunctionScopes[MaxFunctionScopesIndex])) &&
          "Only a lambda can capture the enclosing object (referred to by "
          "*this) by copy");
-  // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated
-  // contexts.
   QualType ThisTy = getCurrentThisType();
   for (int idx = MaxFunctionScopesIndex; NumCapturingClosures;
        --idx, --NumCapturingClosures) {
     CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
-    Expr *ThisExpr = nullptr;
 
     // The type of the corresponding data member (not a 'this' pointer if 'by
     // copy').
@@ -1261,20 +1240,8 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
       CaptureType.removeLocalCVRQualifiers(Qualifiers::CVRMask);
     }
 
-    if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
-      // For lambda expressions, build a field and an initializing expression,
-      // and capture the *enclosing object* by copy only if this is the first
-      // iteration.
-      ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, CaptureType,
-                             Loc, ByCopy && idx == MaxFunctionScopesIndex);
-
-    } else if (CapturedRegionScopeInfo *RSI
-        = dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx]))
-      ThisExpr = captureThis(*this, Context, RSI->TheRecordDecl, ThisTy,
-                             CaptureType, Loc, false /*ByCopy*/);
-
     bool isNested = NumCapturingClosures > 1;
-    CSI->addThisCapture(isNested, Loc, CaptureType, ThisExpr, ByCopy);
+    CSI->addThisCapture(isNested, Loc, CaptureType, ByCopy);
   }
   return false;
 }
index a17a3da67fdec13539b7a83bccd9631d7485306f..d3f3b60926fa3a107a7b630ab4a28c6ae88fad4a 100644 (file)
@@ -1431,6 +1431,24 @@ 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) {
@@ -1680,10 +1698,11 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
                      getLocForEndOfToken(CaptureDefaultLoc), ", this");
         }
 
+        ExprResult Init = performThisCaptureInitialization(From, IsImplicit);
         Captures.push_back(
             LambdaCapture(From.getLocation(), IsImplicit,
                           From.isCopyCapture() ? LCK_StarThis : LCK_This));
-        CaptureInits.push_back(From.getThisInitExpr());
+        CaptureInits.push_back(Init.get());
         continue;
       }
       if (From.isVLATypeCapture()) {
@@ -1703,8 +1722,6 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
               ? Var->getInit()
               : performLambdaVarCaptureInitialization(
                     *this, From, Field, CaptureDefaultLoc, IsImplicit);
-      if (Init.isInvalid())
-        return ExprError();
       CaptureInits.push_back(Init.get());
     }
 
index 7a9a801b188aa7761f48c74a233d153ba9c471bd..3a7acd20274ecf2ee409492c9f08b2882501ad33 100644 (file)
@@ -4235,9 +4235,11 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
     FieldDecl *Field = S.BuildCaptureField(RSI->TheRecordDecl, Cap);
 
     if (Cap.isThisCapture()) {
+      ExprResult Init =
+          S.performThisCaptureInitialization(Cap, /*Implicit*/ true);
       Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
                                                CapturedStmt::VCK_This));
-      CaptureInits.push_back(Cap.getThisInitExpr());
+      CaptureInits.push_back(Init.get());
       continue;
     } else if (Cap.isVLATypeCapture()) {
       Captures.push_back(
@@ -4256,8 +4258,6 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
     // perform a copy here!
     ExprResult Init = S.BuildDeclarationNameExpr(
         CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
-    if (Init.isInvalid())
-      return true;
 
     Captures.push_back(CapturedStmt::Capture(Loc,
                                              Cap.isReferenceCapture()
index 90a3bb073422119c4b6d5ba92eec5857a140f757..3a8e745e50f3e9645f399048779dfbb06e2c3409 100644 (file)
@@ -3941,8 +3941,7 @@ void TestNonADLCall3() {
 // CHECK-NEXT:                  "type": {
 // CHECK-NEXT:                   "qualType": "V *"
 // CHECK-NEXT:                  },
-// CHECK-NEXT:                  "valueCategory": "rvalue",
-// CHECK-NEXT:                  "implicit": true
+// CHECK-NEXT:                  "valueCategory": "rvalue"
 // CHECK-NEXT:                 },
 // CHECK-NEXT:                 {
 // CHECK-NEXT:                  "id": "0x{{.*}}",
@@ -4173,8 +4172,7 @@ void TestNonADLCall3() {
 // CHECK-NEXT:                      "type": {
 // CHECK-NEXT:                       "qualType": "V *"
 // CHECK-NEXT:                      },
-// CHECK-NEXT:                      "valueCategory": "rvalue",
-// CHECK-NEXT:                      "implicit": true
+// CHECK-NEXT:                      "valueCategory": "rvalue"
 // CHECK-NEXT:                     }
 // CHECK-NEXT:                    ]
 // CHECK-NEXT:                   }
index 693dd573079f305d4b03cbb4209982c5f4473124..47f69a882ecbae80acb2c66059ee1bbc13ce51e0 100644 (file)
@@ -255,7 +255,7 @@ void PrimaryExpressions(Ts... a) {
       // CHECK-NEXT: CXXMethodDecl
       // CHECK-NEXT: CompoundStmt
       // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:8> col:8 implicit 'V *'
-      // CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' implicit this
+      // CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' this
 
       [*this]{};
       // CHECK: LambdaExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:7, col:15>
@@ -272,7 +272,7 @@ void PrimaryExpressions(Ts... a) {
       // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:8> col:8 implicit 'V'
       // CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} <col:8> 'NULL TYPE'
       // CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> '<dependent type>' prefix '*' cannot overflow
-      // CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' implicit this
+      // CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' this
     }
   };
 
index 8b0b83078b0a11813159cf50f17786813c97b4d0..311def9147f36f3c58231b073b68df025af65ab9 100644 (file)
@@ -105,7 +105,7 @@ namespace SpecialMembers {
     a = static_cast<decltype(a)&&>(a); // expected-error {{copy assignment operator is implicitly deleted}}
   }
   struct P {
-    P(const P&) = delete; // expected-note {{deleted here}}
+    P(const P&) = delete; // expected-note 2{{deleted here}}
   };
   struct Q {
     ~Q() = delete; // expected-note {{deleted here}}
@@ -117,7 +117,9 @@ namespace SpecialMembers {
     R &operator=(R&&) = delete;
   };
   void g(P &p, Q &q, R &r) {
-    auto pp = [p]{}; // expected-error {{deleted constructor}}
+    // FIXME: The note attached to the second error here is just amazingly bad.
+    auto pp = [p]{}; // expected-error {{deleted constructor}} expected-error {{deleted copy constructor of '(lambda}}
+    // expected-note@-1 {{copy constructor of '' is implicitly deleted because field '' has a deleted copy constructor}}
     auto qq = [q]{}; // expected-error {{deleted function}} expected-note {{because}}
 
     auto a = [r]{}; // expected-note 2{{here}}