[clang] [LifetimeSafety] Trace assignment history for use-after-scope errors (PR #188467)

via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 26 04:28:00 PDT 2026


================
@@ -219,6 +227,194 @@ class LifetimeChecker {
     }
   }
 
+  std::optional<llvm::SmallVector<AssignmentPair>>
+  getAliasListInMultiBlock(const CFGBlock *StartBlock, const LoanID EndLoanID,
+                           OriginID *StartOID) {
+    const ValueDecl *LastDestDecl = nullptr;
+    llvm::SmallVector<const CFGBlock *> PendingBlocks;
+    std::optional<AssignmentPair> StartStmt = std::nullopt;
+    std::optional<AssignmentPair> EndStmt = std::nullopt;
+    std::optional<OriginID> LastOriginID = std::nullopt;
+    llvm::SmallPtrSet<const CFGBlock *, 32> VistedBlocks;
+    llvm::DenseMap<AssignmentPair, AssignmentPair> VistedExprs;
+
+    const auto AliasStmtFilter = [&VistedExprs](const AssignmentPair StartStmt,
+                                                const AssignmentPair EndStmt) {
+      llvm::SmallVector<AssignmentPair> AliasStmts;
+      for (auto Stmt = StartStmt; Stmt != EndStmt;
+           Stmt = VistedExprs.at(Stmt)) {
+        AliasStmts.push_back(Stmt);
+      }
+      AliasStmts.push_back(EndStmt);
+      return AliasStmts;
+    };
+
+    PendingBlocks.push_back(StartBlock);
+
+    for (size_t i = 0; i < PendingBlocks.size(); ++i) {
+      const CFGBlock *CurrBlock = PendingBlocks[i];
+
+      const auto [BlockAliasList, Success, CurrLastDestDecl, CurrLastOriginID] =
+          getAliasListCore(CurrBlock, EndLoanID, StartOID, LastDestDecl,
+                           LastOriginID);
+      if (CurrLastDestDecl)
+        LastDestDecl = CurrLastDestDecl;
+      if (CurrLastOriginID.has_value())
+        LastOriginID = CurrLastOriginID;
+
+      if (!BlockAliasList.empty()) {
+        if (VistedExprs.empty()) {
+          StartStmt = BlockAliasList[0];
+        }
+
+        for (size_t i = 0; i < BlockAliasList.size() - 1; ++i) {
+          VistedExprs.insert({BlockAliasList[i], BlockAliasList[i + 1]});
+        }
+
+        if (EndStmt.has_value())
+          VistedExprs.insert({EndStmt.value(), BlockAliasList[0]});
+
+        EndStmt = BlockAliasList[BlockAliasList.size() - 1];
+      }
+
+      if (Success && StartStmt.has_value() && EndStmt.has_value()) {
+        return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+      }
+
+      for (const auto Block : CurrBlock->preds()) {
+        if (Block && VistedBlocks.insert(Block).second)
+          PendingBlocks.push_back(Block);
+      }
+
+      if (VistedBlocks.size() >= 32 && StartStmt.has_value() &&
+          EndStmt.has_value()) {
+        return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+      }
+    }
+
+    if (StartStmt.has_value() && EndStmt.has_value()) {
+      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+    }
+
+    return std::nullopt;
+  }
+
+  std::optional<OriginSrcExpr> GetPureSrcExpr(const Expr *TargetExpr) {
+    if (!TargetExpr)
+      return std::nullopt;
+    const Expr *SExpr = TargetExpr->IgnoreParenCasts();
+    if (!SExpr)
+      return std::nullopt;
+
+    if (const auto *SDRExpr = llvm::dyn_cast<DeclRefExpr>(SExpr)) {
+      return SDRExpr;
+    }
+    if (const auto *STMExpr = llvm::dyn_cast<CXXTemporaryObjectExpr>(SExpr)) {
+      return STMExpr;
+    }
+    if (const auto *SCExpr = llvm::dyn_cast<CallExpr>(SExpr)) {
+      return SCExpr;
+    }
+
+    if (const auto *SCCExpr = llvm::dyn_cast<CXXConstructExpr>(SExpr)) {
+      if (SCCExpr->getNumArgs() > 0)
+        return GetPureSrcExpr(SCCExpr->getArg(0));
----------------
suoyuan666 wrote:

The implementation here is a bit unrefined, and I haven't found a better workaround yet.
My intention was to bypass this part because I don't believe the assignment statements we're searching for should involve explicit constructors; I only intend to match implicit ones here.

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


More information about the cfe-commits mailing list