[clang] [llvm] [clang] Implement lifetime analysis for lifetime_capture_by(X) (PR #115921)

Haojian Wu via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 19 04:50:13 PST 2024


================
@@ -1412,17 +1438,34 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
     return false;
   };
 
+  bool HasReferenceBinding = Init->isGLValue();
   llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
-  if (LK == LK_Assignment &&
-      shouldRunGSLAssignmentAnalysis(SemaRef, *AEntity)) {
-    Path.push_back(
-        {isAssignmentOperatorLifetimeBound(AEntity->AssignmentOperator)
-             ? IndirectLocalPathEntry::LifetimeBoundCall
-             : IndirectLocalPathEntry::GslPointerAssignment,
-         Init});
+  switch (LK) {
+  case LK_Assignment: {
+    if (shouldRunGSLAssignmentAnalysis(SemaRef, *AEntity))
+      Path.push_back(
+          {isAssignmentOperatorLifetimeBound(AEntity->AssignmentOperator)
+               ? IndirectLocalPathEntry::LifetimeBoundCall
+               : IndirectLocalPathEntry::GslPointerAssignment,
+           Init});
+    break;
+  }
+  case LK_LifetimeCapture: {
+    Path.push_back({IndirectLocalPathEntry::LifetimeCapture, Init});
+    if (isRecordWithAttr<PointerAttr>(Init->getType()))
+      HasReferenceBinding = false;
+    // Skip the top MTE if it is a temporary object of the pointer-like type
+    // itself.
+    if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init);
+        MTE && isPointerLikeType(Init->getType()))
+      Init = MTE->getSubExpr();
----------------
hokein wrote:

I know that this code originated from my patch that added assignment support for "container<pointer>." That patch has some issues: although it passed the unit tests, it failed to diagnose cases in real STL headers.

I'm not sure I fully understand the implementation here (my initial idea was to leverage the existing code paths for `lifetimebound` and `gsl::Pointer`, so the need for `IndirectLocalPathEntry::LifetimeCapture` isn’t clear). I experimented this patch, and made some tweaks to simplify the logic, and here’s the diff I came up with:

```cpp
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -1212,9 +1212,9 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
       // and the capturing entity does too, so don't warn.
       if (!MTE)
         return false;
-      assert(shouldLifetimeExtendThroughPath(Path) ==
-                 PathLifetimeKind::NoExtend &&
-             "No lifetime extension in function calls");
+      // assert(shouldLifetimeExtendThroughPath(Path) ==
+      //            PathLifetimeKind::NoExtend &&
+      //        "No lifetime extension in function calls");
       if (CapEntity->Entity)
         SemaRef.Diag(DiagLoc, diag::warn_dangling_reference_captured)
             << CapEntity->Entity << DiagRange;
@@ -1451,14 +1451,8 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
     break;
   }
   case LK_LifetimeCapture: {
-    Path.push_back({IndirectLocalPathEntry::LifetimeCapture, Init});
-    if (isRecordWithAttr<PointerAttr>(Init->getType()))
-      HasReferenceBinding = false;
-    // Skip the top MTE if it is a temporary object of the pointer-like type
-    // itself.
-    if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init);
-        MTE && isPointerLikeType(Init->getType()))
-      Init = MTE->getSubExpr();
+    if (isPointerLikeType(Init->getType()))
+      Path.push_back({IndirectLocalPathEntry::GslPointerInit, Init});
     break;
   }
   default:
```

The tests passed, and it also fixes the known false positives:

```
error: 'expected-warning' diagnostics expected but not seen: 
  File /workspace/llvm-project/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp Line 313: captured
  File /workspace/llvm-project/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp Line 314: captured
  File /workspace/llvm-project/clang/test/Sema/warn-lifetime-analysis-capture-by.cpp Line 318: captured
```

Would you mind taking it further?

https://github.com/llvm/llvm-project/pull/115921


More information about the llvm-commits mailing list