================
@@ -878,6 +878,65 @@ void FactsGenerator::handleImplicitObjectFieldUses(const 
Expr *Call,
   });
 }
 
+void FactsGenerator::handleLifetimeCaptureBy(const FunctionDecl *FD,
+                                             ArrayRef<const Expr *> Args) {
+  if (Args.empty())
+    return;
+  // FIXME: Add support for capture_by on constructors.
+  if (isa<CXXConstructorDecl>(FD))
+    return;
+  const auto *Method = dyn_cast<CXXMethodDecl>(FD);
+  bool IsInstance =
+      Method && Method->isInstance() && !isa<CXXConstructorDecl>(FD);
+  auto getArgCaptureBy = [FD,
+                          IsInstance](unsigned I) -> LifetimeCaptureByAttr * {
+    const ParmVarDecl *PVD = nullptr;
+    if (IsInstance) {
+      // FIXME: Add support for I == 0 i.e. capture_by on function declarations
+      if (I > 0 && I - 1 < FD->getNumParams())
+        PVD = FD->getParamDecl(I - 1);
+    } else {
+      if (I < FD->getNumParams())
+        PVD = FD->getParamDecl(I);
+    }
+    return PVD ? PVD->getAttr<LifetimeCaptureByAttr>() : nullptr;
+  };
+  for (unsigned I = 0; I < Args.size(); ++I) {
+    const LifetimeCaptureByAttr *Attr = getArgCaptureBy(I);
+    if (!Attr)
+      continue;
+    OriginList *CapturedOriginList = getOriginsList(*Args[I]);
+    if (!CapturedOriginList)
+      continue;
+    if (isGslPointerType(Args[I]->getType())) {
+      assert(!Args[I]->isGLValue() || CapturedOriginList->getLength() >= 2);
+      CapturedOriginList = getRValueOrigins(Args[I], CapturedOriginList);
+    }
+    if (!CapturedOriginList)
+      continue;
+    for (int CapturedByIdx : Attr->params()) {
+      // FIXME: Add support for capturing to Global/unknown.
+      if (CapturedByIdx == LifetimeCaptureByAttr::Global ||
+          CapturedByIdx == LifetimeCaptureByAttr::Unknown ||
+          CapturedByIdx == LifetimeCaptureByAttr::Invalid)
+        continue;
+      ArrayRef<const Expr *> CallArgs = IsInstance ? Args.drop_front() : Args;
+      const Expr *CapturedByArg = (CapturedByIdx == 
LifetimeCaptureByAttr::This)
+                                      ? Args[0]
+                                      : CallArgs[CapturedByIdx];
+      assert(CapturedByArg && "Capturer expression must be valid");
+
+      OriginList *CapturedByOriginList = getOriginsList(*CapturedByArg);
+      OriginList *Dest = getRValueOrigins(CapturedByArg, CapturedByOriginList);
+      if (!Dest)
+        continue;
+      CurrentBlockFacts.push_back(FactMgr.createFact<OriginFlowFact>(
+          Dest->getOuterOriginID(), CapturedOriginList->getOuterOriginID(),
+          /*KillDest=*/false));
----------------
usx95 wrote:

This seems like an important design decision! Please document this.
We can never be certain that the original loans in the capturing arg is killed.
So captured args are always accumulated.

```
// KillDest=false because we cannot know if previous captures are being
// replaced or accumulated. Multiple successive captures into the same
// destination must all be tracked, so captured lifetimes are always merged.
```

Example:
```cpp
void foo() {
    View v;
    {
        MyObj local1;
        setCaptureBy(v, local1);
        MyObj local2;
        setCaptureBy(v, local2);
    }
    (void)v;
}
```
Warn on both `local1` and `local2`.


https://github.com/llvm/llvm-project/pull/196884
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to