[clang] [LifetimeSafety] Use ImmutableList for buildOriginFlowChain DFS nodes (PR #208890)
Yuan Suo via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 14 05:26:54 PDT 2026
https://github.com/suoyuan666 updated https://github.com/llvm/llvm-project/pull/208890
>From 9d667b1da7631efd70dcfa1723ff689d6b3a2948 Mon Sep 17 00:00:00 2001
From: Yuan Suo <suoyuan666 at s5n.xyz>
Date: Sat, 11 Jul 2026 16:22:16 +0800
Subject: [PATCH 1/5] [LifetimeSafety] Use ImmutableList for
buildOriginFlowChain DFS nodes
This commit mainly address the suggestion in https://github.com/llvm/llvm-project/pull/204592#discussion_r3523582077 to use `ImmutableList` for the DFS nodes in `buildOriginFlowChain`, and also updates the unreachable messages.
Signed-off-by: Yuan Suo <suoyuan666 at s5n.xyz>
---
.../Analyses/LifetimeSafety/LoanPropagation.h | 23 +++++-----
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 2 +-
.../LifetimeSafety/LifetimeSafety.cpp | 5 ++-
.../LifetimeSafety/LoanPropagation.cpp | 42 +++++++++++--------
clang/lib/Sema/SemaLifetimeSafety.h | 4 +-
.../unittests/Analysis/LifetimeSafetyTest.cpp | 22 +++++-----
6 files changed, 56 insertions(+), 42 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
index 838daa024c953..3d489965a5aa6 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
@@ -18,6 +18,7 @@
#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableSet.h"
@@ -31,9 +32,11 @@ using OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
class LoanPropagationAnalysis {
public:
- LoanPropagationAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F,
- OriginLoanMap::Factory &OriginLoanMapFactory,
- LoanSet::Factory &LoanSetFactory);
+ LoanPropagationAnalysis(
+ const CFG &C, AnalysisDeclContext &AC, FactManager &F,
+ OriginLoanMap::Factory &OriginLoanMapFactory,
+ LoanSet::Factory &LoanSetFactory,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory);
~LoanPropagationAnalysis();
LoanSet getLoans(OriginID OID, ProgramPoint P) const;
@@ -47,14 +50,14 @@ class LoanPropagationAnalysis {
/// The traversal follows OriginFlowFacts backwards to reconstruct the
/// sequence of origins through which the loan flowed, ending at the origin
/// where the loan was originally issued.
- llvm::SmallVector<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
- const OriginID StartOID,
- const LoanID TargetLoan,
- const CFG *Cfg) const;
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
+ const OriginID StartOID,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const;
- llvm::SmallVector<OriginID> buildOriginFlowChain(const UseFact *UF,
- const LoanID TargetLoan,
- const CFG *Cfg) const;
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(const UseFact *UF,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const;
private:
class Impl;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index f72f7f80abbc0..3b7248b28b945 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -527,7 +527,7 @@ class LifetimeChecker {
/// extracts the corresponding expressions for each origin. Origins that refer
/// to declarations (rather than expressions) are skipped.
llvm::SmallVector<const Expr *>
- getExprChain(llvm::ArrayRef<OriginID> OriginFlowChain) {
+ getExprChain(llvm::ImmutableList<OriginID> OriginFlowChain) {
llvm::SmallVector<const Expr *> rs;
for (const OriginID CurrOID : OriginFlowChain)
if (const Expr *CurrExpr =
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 798812327d3ab..50fc8e033d81b 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -86,8 +86,11 @@ void LifetimeSafetyAnalysis::run() {
/// the analysis.
/// 3. Collapse ExpireFacts belonging to same source location into a single
/// Fact.
+
+ llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
LoanPropagation = std::make_unique<LoanPropagationAnalysis>(
- Cfg, AC, *FactMgr, Factory.OriginMapFactory, Factory.LoanSetFactory);
+ Cfg, AC, *FactMgr, Factory.OriginMapFactory, Factory.LoanSetFactory,
+ OriginFlowChainFactory);
LiveOrigins = std::make_unique<LiveOriginsAnalysis>(
Cfg, AC, *FactMgr, Factory.LivenessMapFactory);
diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index 078892bd48c10..56e17c080db3d 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -18,6 +18,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/TimeProfiler.h"
@@ -136,9 +137,11 @@ class AnalysisImpl
public:
AnalysisImpl(const CFG &C, AnalysisDeclContext &AC, FactManager &F,
OriginLoanMap::Factory &OriginLoanMapFactory,
- LoanSet::Factory &LoanSetFactory)
+ LoanSet::Factory &LoanSetFactory,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory)
: DataflowAnalysis(C, AC, F), OriginLoanMapFactory(OriginLoanMapFactory),
LoanSetFactory(LoanSetFactory),
+ OriginFlowChainFactory(OriginFlowChainFactory),
PersistentOrigins(computePersistentOrigins(F, C)) {}
using Base::transfer;
@@ -203,10 +206,10 @@ class AnalysisImpl
return getLoans(getState(P), OID);
}
- llvm::SmallVector<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
- const OriginID StartOID,
- const LoanID TargetLoan,
- const CFG *Cfg) const {
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
+ const OriginID StartOID,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const {
assert(getLoans(StartOID, StartPoint).contains(TargetLoan) &&
"TargetLoan must be present in the StartOID at the StartPoint");
@@ -225,12 +228,13 @@ class AnalysisImpl
using SearchState = std::pair<const CFGBlock *, OriginID>;
struct DFSNode {
SearchState CurrState;
- llvm::SmallVector<OriginID> OriginFlowChain;
+ llvm::ImmutableList<OriginID> OriginFlowChain;
};
llvm::SmallVector<DFSNode> PendingStates;
llvm::SmallSet<SearchState, 16> VistedStates;
- PendingStates.push_back({{EndBlock, StartOID}, {}});
+ PendingStates.push_back(
+ {{EndBlock, StartOID}, OriginFlowChainFactory.getEmptyList()});
// DFS loop to trace loan backwards through CFG
while (!PendingStates.empty()) {
@@ -241,7 +245,9 @@ class AnalysisImpl
const auto [BuildResult, Complete] =
buildOriginFlowChain(CurrBlock, CurrOID, TargetLoan);
if (!BuildResult.empty()) {
- CurrNode.OriginFlowChain.append(BuildResult);
+ for (OriginID OID : BuildResult)
+ CurrNode.OriginFlowChain =
+ OriginFlowChainFactory.add(OID, CurrNode.OriginFlowChain);
CurrOID = BuildResult.back();
}
@@ -259,13 +265,13 @@ class AnalysisImpl
}
}
- llvm_unreachable(
- "buildOriginFlowChain did not reach IssueFact for TargetLoan");
+ llvm_unreachable("Could not reconstruct origin flow. Search finished "
+ "without reaching IssueFact");
}
- llvm::SmallVector<OriginID> buildOriginFlowChain(const UseFact *UF,
- const LoanID TargetLoan,
- const CFG *Cfg) const {
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(const UseFact *UF,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const {
for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
Cur = Cur->peelOuterOrigin())
if (getLoans(Cur->getOuterOriginID(), UF).contains(TargetLoan))
@@ -333,6 +339,7 @@ class AnalysisImpl
OriginLoanMap::Factory &OriginLoanMapFactory;
LoanSet::Factory &LoanSetFactory;
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory;
/// Boolean vector indexed by origin ID. If true, the origin appears in
/// multiple basic blocks and must participate in join operations. If false,
/// the origin is block-local and can be discarded at block boundaries.
@@ -347,9 +354,10 @@ class LoanPropagationAnalysis::Impl final : public AnalysisImpl {
LoanPropagationAnalysis::LoanPropagationAnalysis(
const CFG &C, AnalysisDeclContext &AC, FactManager &F,
OriginLoanMap::Factory &OriginLoanMapFactory,
- LoanSet::Factory &LoanSetFactory)
+ LoanSet::Factory &LoanSetFactory,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory)
: PImpl(std::make_unique<Impl>(C, AC, F, OriginLoanMapFactory,
- LoanSetFactory)) {
+ LoanSetFactory, OriginFlowChainFactory)) {
PImpl->run();
}
@@ -359,13 +367,13 @@ LoanSet LoanPropagationAnalysis::getLoans(OriginID OID, ProgramPoint P) const {
return PImpl->getLoans(OID, P);
}
-llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
+llvm::ImmutableList<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
const CFG *Cfg) const {
return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan, Cfg);
}
-llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
+llvm::ImmutableList<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg) const {
return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg);
}
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 48edf5f3f070f..c36402b393729 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -668,10 +668,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
if (OriginExprChain.empty())
return;
- const Expr *LastExpr = OriginExprChain.back();
+ const Expr *LastExpr = OriginExprChain.front();
std::string IssueStr = getDiagSubjectDescription(LastExpr);
- for (const Expr *CurrExpr : reverse(OriginExprChain.drop_back())) {
+ for (const Expr *CurrExpr : OriginExprChain.drop_front()) {
if (!shouldShowInAliasChain(CurrExpr, LastExpr))
continue;
S.Diag(CurrExpr->getBeginLoc(),
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index 57cf7068affae..cb69b440c482c 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -205,18 +205,18 @@ class LifetimeTestHelper {
return Runner.getAnalysis().getFactManager().getBlockContaining(P);
}
- llvm::SmallVector<OriginID>
+ llvm::ImmutableList<OriginID>
buildOriginFlowChain(llvm::StringRef StartOriginVar,
llvm::StringRef EndLoanVar, llvm::StringRef Annotation) {
std::optional<OriginID> StartOriginID = getOriginForDecl(StartOriginVar);
std::vector<LoanID> EndLoanIDs = getLoansForVar(EndLoanVar);
for (LoanID LID : EndLoanIDs) {
- llvm::SmallVector<OriginID> OriginFlowChain =
+ llvm::ImmutableList<OriginID> OriginFlowChain =
Runner.getAnalysis().getLoanPropagation().buildOriginFlowChain(
getProgramPoint(Annotation), *StartOriginID, LID,
Runner.getAnalysisContext().getCFG());
- if (!OriginFlowChain.empty())
+ if (!OriginFlowChain.isEmpty())
return OriginFlowChain;
}
@@ -2001,11 +2001,11 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChain) {
}
)");
- llvm::SmallVector<OriginID> ChainForTgtA =
+ llvm::ImmutableList<OriginID> ChainForTgtA =
Helper->buildOriginFlowChain("s", "tgta", "after_nested_merge");
- llvm::SmallVector<OriginID> ChainForTgtB =
+ llvm::ImmutableList<OriginID> ChainForTgtB =
Helper->buildOriginFlowChain("s", "tgtb", "after_nested_merge");
- llvm::SmallVector<OriginID> ChainForTgtC =
+ llvm::ImmutableList<OriginID> ChainForTgtC =
Helper->buildOriginFlowChain("s", "tgtc", "after_nested_merge");
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("a")));
@@ -2050,7 +2050,7 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithSelfAssignment) {
}
)");
- const llvm::SmallVector<OriginID> OriginFlowChain =
+ const llvm::ImmutableList<OriginID> OriginFlowChain =
Helper->buildOriginFlowChain("s", "tgt", "after_use");
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
@@ -2067,7 +2067,7 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithMultiAssignInSameStmt) {
}
)");
- const llvm::SmallVector<OriginID> OriginFlowChain =
+ const llvm::ImmutableList<OriginID> OriginFlowChain =
Helper->buildOriginFlowChain("s", "tgt", "after_use");
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
@@ -2088,7 +2088,7 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithOverwritingAssignments) {
}
)");
- const llvm::SmallVector<OriginID> OriginFlowChain =
+ const llvm::ImmutableList<OriginID> OriginFlowChain =
Helper->buildOriginFlowChain("s", "tgt1", "after_use");
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
@@ -2110,9 +2110,9 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithLifetimeBound) {
}
)");
- llvm::SmallVector<OriginID> ChainForTgtA =
+ llvm::ImmutableList<OriginID> ChainForTgtA =
Helper->buildOriginFlowChain("s", "tgta", "after_use");
- llvm::SmallVector<OriginID> ChainForTgtB =
+ llvm::ImmutableList<OriginID> ChainForTgtB =
Helper->buildOriginFlowChain("s", "tgtb", "after_use");
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("a")));
>From 82eb90682a5199aabbf185ba17c1da1f6e41faaa Mon Sep 17 00:00:00 2001
From: Yuan Suo <suoyuan666 at s5n.xyz>
Date: Sat, 11 Jul 2026 18:09:34 +0800
Subject: [PATCH 2/5] Move ImmutableListFactory from LoanPropagationAnalysis to
function parameter
Signed-off-by: Yuan Suo <suoyuan666 at s5n.xyz>
---
.../Analyses/LifetimeSafety/LoanPropagation.h | 22 ++++----
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 7 ++-
.../LifetimeSafety/LifetimeSafety.cpp | 4 +-
.../LifetimeSafety/LoanPropagation.cpp | 38 +++++++-------
.../unittests/Analysis/LifetimeSafetyTest.cpp | 50 ++++++++++++-------
5 files changed, 67 insertions(+), 54 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
index 3d489965a5aa6..6b9f748ead026 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
@@ -32,11 +32,9 @@ using OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
class LoanPropagationAnalysis {
public:
- LoanPropagationAnalysis(
- const CFG &C, AnalysisDeclContext &AC, FactManager &F,
- OriginLoanMap::Factory &OriginLoanMapFactory,
- LoanSet::Factory &LoanSetFactory,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory);
+ LoanPropagationAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F,
+ OriginLoanMap::Factory &OriginLoanMapFactory,
+ LoanSet::Factory &LoanSetFactory);
~LoanPropagationAnalysis();
LoanSet getLoans(OriginID OID, ProgramPoint P) const;
@@ -50,14 +48,14 @@ class LoanPropagationAnalysis {
/// The traversal follows OriginFlowFacts backwards to reconstruct the
/// sequence of origins through which the loan flowed, ending at the origin
/// where the loan was originally issued.
- llvm::ImmutableList<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
- const OriginID StartOID,
- const LoanID TargetLoan,
- const CFG *Cfg) const;
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(
+ ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
+ const CFG *Cfg,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const;
- llvm::ImmutableList<OriginID> buildOriginFlowChain(const UseFact *UF,
- const LoanID TargetLoan,
- const CFG *Cfg) const;
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(
+ const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const;
private:
class Impl;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 3b7248b28b945..e32faff310dbc 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -270,11 +270,14 @@ class LifetimeChecker {
SemaHelper->reportUseAfterInvalidation(
InvalidatedPVD, UF->getUseExpr(), Warning.InvalidatedByExpr);
- } else
+ } else {
// Scope-based expiry (use-after-scope).
+ llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
SemaHelper->reportUseAfterScope(
IssueExpr, UF->getUseExpr(), MovedExpr, ExpiryLoc,
- getExprChain(LoanPropagation.buildOriginFlowChain(UF, LID, Cfg)));
+ getExprChain(LoanPropagation.buildOriginFlowChain(
+ UF, LID, Cfg, OriginFlowChainFactory)));
+ }
} else if (const auto *OEF =
CausingFact.dyn_cast<const OriginEscapesFact *>()) {
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 50fc8e033d81b..95e854abc540e 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -87,10 +87,8 @@ void LifetimeSafetyAnalysis::run() {
/// 3. Collapse ExpireFacts belonging to same source location into a single
/// Fact.
- llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
LoanPropagation = std::make_unique<LoanPropagationAnalysis>(
- Cfg, AC, *FactMgr, Factory.OriginMapFactory, Factory.LoanSetFactory,
- OriginFlowChainFactory);
+ Cfg, AC, *FactMgr, Factory.OriginMapFactory, Factory.LoanSetFactory);
LiveOrigins = std::make_unique<LiveOriginsAnalysis>(
Cfg, AC, *FactMgr, Factory.LivenessMapFactory);
diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index 56e17c080db3d..49d65d536507a 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -137,11 +137,9 @@ class AnalysisImpl
public:
AnalysisImpl(const CFG &C, AnalysisDeclContext &AC, FactManager &F,
OriginLoanMap::Factory &OriginLoanMapFactory,
- LoanSet::Factory &LoanSetFactory,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory)
+ LoanSet::Factory &LoanSetFactory)
: DataflowAnalysis(C, AC, F), OriginLoanMapFactory(OriginLoanMapFactory),
LoanSetFactory(LoanSetFactory),
- OriginFlowChainFactory(OriginFlowChainFactory),
PersistentOrigins(computePersistentOrigins(F, C)) {}
using Base::transfer;
@@ -206,10 +204,10 @@ class AnalysisImpl
return getLoans(getState(P), OID);
}
- llvm::ImmutableList<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
- const OriginID StartOID,
- const LoanID TargetLoan,
- const CFG *Cfg) const {
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(
+ ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
+ const CFG *Cfg,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
assert(getLoans(StartOID, StartPoint).contains(TargetLoan) &&
"TargetLoan must be present in the StartOID at the StartPoint");
@@ -269,14 +267,14 @@ class AnalysisImpl
"without reaching IssueFact");
}
- llvm::ImmutableList<OriginID> buildOriginFlowChain(const UseFact *UF,
- const LoanID TargetLoan,
- const CFG *Cfg) const {
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(
+ const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
Cur = Cur->peelOuterOrigin())
if (getLoans(Cur->getOuterOriginID(), UF).contains(TargetLoan))
return buildOriginFlowChain(UF, Cur->getOuterOriginID(), TargetLoan,
- Cfg);
+ Cfg, OriginFlowChainFactory);
return {};
}
@@ -339,7 +337,6 @@ class AnalysisImpl
OriginLoanMap::Factory &OriginLoanMapFactory;
LoanSet::Factory &LoanSetFactory;
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory;
/// Boolean vector indexed by origin ID. If true, the origin appears in
/// multiple basic blocks and must participate in join operations. If false,
/// the origin is block-local and can be discarded at block boundaries.
@@ -354,10 +351,9 @@ class LoanPropagationAnalysis::Impl final : public AnalysisImpl {
LoanPropagationAnalysis::LoanPropagationAnalysis(
const CFG &C, AnalysisDeclContext &AC, FactManager &F,
OriginLoanMap::Factory &OriginLoanMapFactory,
- LoanSet::Factory &LoanSetFactory,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory)
+ LoanSet::Factory &LoanSetFactory)
: PImpl(std::make_unique<Impl>(C, AC, F, OriginLoanMapFactory,
- LoanSetFactory, OriginFlowChainFactory)) {
+ LoanSetFactory)) {
PImpl->run();
}
@@ -369,12 +365,16 @@ LoanSet LoanPropagationAnalysis::getLoans(OriginID OID, ProgramPoint P) const {
llvm::ImmutableList<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
- const CFG *Cfg) const {
- return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan, Cfg);
+ const CFG *Cfg,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
+ return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan, Cfg,
+ OriginFlowChainFactory);
}
llvm::ImmutableList<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
- const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg) const {
- return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg);
+ const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
+ return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg,
+ OriginFlowChainFactory);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index cb69b440c482c..d164acf73a8a9 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -205,9 +205,10 @@ class LifetimeTestHelper {
return Runner.getAnalysis().getFactManager().getBlockContaining(P);
}
- llvm::ImmutableList<OriginID>
- buildOriginFlowChain(llvm::StringRef StartOriginVar,
- llvm::StringRef EndLoanVar, llvm::StringRef Annotation) {
+ llvm::ImmutableList<OriginID> buildOriginFlowChain(
+ llvm::StringRef StartOriginVar, llvm::StringRef EndLoanVar,
+ llvm::StringRef Annotation,
+ llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) {
std::optional<OriginID> StartOriginID = getOriginForDecl(StartOriginVar);
std::vector<LoanID> EndLoanIDs = getLoansForVar(EndLoanVar);
@@ -215,7 +216,7 @@ class LifetimeTestHelper {
llvm::ImmutableList<OriginID> OriginFlowChain =
Runner.getAnalysis().getLoanPropagation().buildOriginFlowChain(
getProgramPoint(Annotation), *StartOriginID, LID,
- Runner.getAnalysisContext().getCFG());
+ Runner.getAnalysisContext().getCFG(), OriginFlowChainFactory);
if (!OriginFlowChain.isEmpty())
return OriginFlowChain;
}
@@ -2001,12 +2002,15 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChain) {
}
)");
- llvm::ImmutableList<OriginID> ChainForTgtA =
- Helper->buildOriginFlowChain("s", "tgta", "after_nested_merge");
- llvm::ImmutableList<OriginID> ChainForTgtB =
- Helper->buildOriginFlowChain("s", "tgtb", "after_nested_merge");
- llvm::ImmutableList<OriginID> ChainForTgtC =
- Helper->buildOriginFlowChain("s", "tgtc", "after_nested_merge");
+ llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtA;
+ llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtB;
+ llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtC;
+ llvm::ImmutableList<OriginID> ChainForTgtA = Helper->buildOriginFlowChain(
+ "s", "tgta", "after_nested_merge", ChainFactoryForTgtA);
+ llvm::ImmutableList<OriginID> ChainForTgtB = Helper->buildOriginFlowChain(
+ "s", "tgtb", "after_nested_merge", ChainFactoryForTgtB);
+ llvm::ImmutableList<OriginID> ChainForTgtC = Helper->buildOriginFlowChain(
+ "s", "tgtc", "after_nested_merge", ChainFactoryForTgtC);
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(ChainForTgtA, Not(Contains(*Helper->getOriginForDecl("b"))));
@@ -2032,7 +2036,9 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithErrorTargetLoan) {
)");
#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
- EXPECT_DEATH(Helper->buildOriginFlowChain("s", "a", "after_use"),
+ llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
+ EXPECT_DEATH(Helper->buildOriginFlowChain("s", "a", "after_use",
+ OriginFlowChainFactory),
"TargetLoan must be present in the StartOID at the StartPoint");
#endif
}
@@ -2050,8 +2056,10 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithSelfAssignment) {
}
)");
+ llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
const llvm::ImmutableList<OriginID> OriginFlowChain =
- Helper->buildOriginFlowChain("s", "tgt", "after_use");
+ Helper->buildOriginFlowChain("s", "tgt", "after_use",
+ OriginFlowChainFactory);
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
}
@@ -2067,8 +2075,10 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithMultiAssignInSameStmt) {
}
)");
+ llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
const llvm::ImmutableList<OriginID> OriginFlowChain =
- Helper->buildOriginFlowChain("s", "tgt", "after_use");
+ Helper->buildOriginFlowChain("s", "tgt", "after_use",
+ OriginFlowChainFactory);
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("b")));
@@ -2088,8 +2098,10 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithOverwritingAssignments) {
}
)");
+ llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
const llvm::ImmutableList<OriginID> OriginFlowChain =
- Helper->buildOriginFlowChain("s", "tgt1", "after_use");
+ Helper->buildOriginFlowChain("s", "tgt1", "after_use",
+ OriginFlowChainFactory);
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("b")));
@@ -2110,10 +2122,12 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithLifetimeBound) {
}
)");
- llvm::ImmutableList<OriginID> ChainForTgtA =
- Helper->buildOriginFlowChain("s", "tgta", "after_use");
- llvm::ImmutableList<OriginID> ChainForTgtB =
- Helper->buildOriginFlowChain("s", "tgtb", "after_use");
+ llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtA;
+ llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtB;
+ llvm::ImmutableList<OriginID> ChainForTgtA = Helper->buildOriginFlowChain(
+ "s", "tgta", "after_use", ChainFactoryForTgtB);
+ llvm::ImmutableList<OriginID> ChainForTgtB = Helper->buildOriginFlowChain(
+ "s", "tgtb", "after_use", ChainFactoryForTgtB);
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("result")));
>From 0a5aba669ee80e822b32218a463870cc02e2654c Mon Sep 17 00:00:00 2001
From: Yuan Suo <suoyuan666 at s5n.xyz>
Date: Sun, 12 Jul 2026 09:54:03 +0800
Subject: [PATCH 3/5] Move OriginFlowChainFactory inside the function
Signed-off-by: Yuan Suo <suoyuan666 at s5n.xyz>
---
.../Analyses/LifetimeSafety/LoanPropagation.h | 14 ++---
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 9 +--
.../LifetimeSafety/LifetimeSafety.cpp | 1 -
.../LifetimeSafety/LoanPropagation.cpp | 41 ++++++-------
.../unittests/Analysis/LifetimeSafetyTest.cpp | 60 +++++++------------
5 files changed, 54 insertions(+), 71 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
index 6b9f748ead026..2dc6f745de38d 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
@@ -48,14 +48,14 @@ class LoanPropagationAnalysis {
/// The traversal follows OriginFlowFacts backwards to reconstruct the
/// sequence of origins through which the loan flowed, ending at the origin
/// where the loan was originally issued.
- llvm::ImmutableList<OriginID> buildOriginFlowChain(
- ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
- const CFG *Cfg,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const;
+ llvm::SmallVector<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
+ const OriginID StartOID,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const;
- llvm::ImmutableList<OriginID> buildOriginFlowChain(
- const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const;
+ llvm::SmallVector<OriginID> buildOriginFlowChain(const UseFact *UF,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const;
private:
class Impl;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index e32faff310dbc..c56726864f20c 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -270,14 +270,11 @@ class LifetimeChecker {
SemaHelper->reportUseAfterInvalidation(
InvalidatedPVD, UF->getUseExpr(), Warning.InvalidatedByExpr);
- } else {
+ } else
// Scope-based expiry (use-after-scope).
- llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
SemaHelper->reportUseAfterScope(
IssueExpr, UF->getUseExpr(), MovedExpr, ExpiryLoc,
- getExprChain(LoanPropagation.buildOriginFlowChain(
- UF, LID, Cfg, OriginFlowChainFactory)));
- }
+ getExprChain(LoanPropagation.buildOriginFlowChain(UF, LID, Cfg)));
} else if (const auto *OEF =
CausingFact.dyn_cast<const OriginEscapesFact *>()) {
@@ -530,7 +527,7 @@ class LifetimeChecker {
/// extracts the corresponding expressions for each origin. Origins that refer
/// to declarations (rather than expressions) are skipped.
llvm::SmallVector<const Expr *>
- getExprChain(llvm::ImmutableList<OriginID> OriginFlowChain) {
+ getExprChain(llvm::SmallVector<OriginID> OriginFlowChain) {
llvm::SmallVector<const Expr *> rs;
for (const OriginID CurrOID : OriginFlowChain)
if (const Expr *CurrExpr =
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 95e854abc540e..798812327d3ab 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -86,7 +86,6 @@ void LifetimeSafetyAnalysis::run() {
/// the analysis.
/// 3. Collapse ExpireFacts belonging to same source location into a single
/// Fact.
-
LoanPropagation = std::make_unique<LoanPropagationAnalysis>(
Cfg, AC, *FactMgr, Factory.OriginMapFactory, Factory.LoanSetFactory);
diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index 49d65d536507a..1a5deb5bfca10 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -204,10 +204,10 @@ class AnalysisImpl
return getLoans(getState(P), OID);
}
- llvm::ImmutableList<OriginID> buildOriginFlowChain(
- ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
- const CFG *Cfg,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
+ llvm::SmallVector<OriginID> buildOriginFlowChain(ProgramPoint StartPoint,
+ const OriginID StartOID,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const {
assert(getLoans(StartOID, StartPoint).contains(TargetLoan) &&
"TargetLoan must be present in the StartOID at the StartPoint");
@@ -231,6 +231,7 @@ class AnalysisImpl
llvm::SmallVector<DFSNode> PendingStates;
llvm::SmallSet<SearchState, 16> VistedStates;
+ llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
PendingStates.push_back(
{{EndBlock, StartOID}, OriginFlowChainFactory.getEmptyList()});
@@ -250,8 +251,12 @@ class AnalysisImpl
}
// If we found the IssueFact, we're done
- if (Complete)
- return CurrNode.OriginFlowChain;
+ if (Complete) {
+ llvm::SmallVector<OriginID> Chain;
+ for (OriginID OID : CurrNode.OriginFlowChain)
+ Chain.push_back(OID);
+ return Chain;
+ }
// Only explore predecessor blocks where the target loan is present in the
// current origin.
@@ -267,14 +272,14 @@ class AnalysisImpl
"without reaching IssueFact");
}
- llvm::ImmutableList<OriginID> buildOriginFlowChain(
- const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
+ llvm::SmallVector<OriginID> buildOriginFlowChain(const UseFact *UF,
+ const LoanID TargetLoan,
+ const CFG *Cfg) const {
for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
Cur = Cur->peelOuterOrigin())
if (getLoans(Cur->getOuterOriginID(), UF).contains(TargetLoan))
return buildOriginFlowChain(UF, Cur->getOuterOriginID(), TargetLoan,
- Cfg, OriginFlowChainFactory);
+ Cfg);
return {};
}
@@ -363,18 +368,14 @@ LoanSet LoanPropagationAnalysis::getLoans(OriginID OID, ProgramPoint P) const {
return PImpl->getLoans(OID, P);
}
-llvm::ImmutableList<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
+llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
- const CFG *Cfg,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
- return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan, Cfg,
- OriginFlowChainFactory);
+ const CFG *Cfg) const {
+ return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan, Cfg);
}
-llvm::ImmutableList<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
- const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) const {
- return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg,
- OriginFlowChainFactory);
+llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
+ const UseFact *UF, const LoanID TargetLoan, const CFG *Cfg) const {
+ return PImpl->buildOriginFlowChain(UF, TargetLoan, Cfg);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index d164acf73a8a9..57cf7068affae 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -205,19 +205,18 @@ class LifetimeTestHelper {
return Runner.getAnalysis().getFactManager().getBlockContaining(P);
}
- llvm::ImmutableList<OriginID> buildOriginFlowChain(
- llvm::StringRef StartOriginVar, llvm::StringRef EndLoanVar,
- llvm::StringRef Annotation,
- llvm::ImmutableList<OriginID>::Factory &OriginFlowChainFactory) {
+ llvm::SmallVector<OriginID>
+ buildOriginFlowChain(llvm::StringRef StartOriginVar,
+ llvm::StringRef EndLoanVar, llvm::StringRef Annotation) {
std::optional<OriginID> StartOriginID = getOriginForDecl(StartOriginVar);
std::vector<LoanID> EndLoanIDs = getLoansForVar(EndLoanVar);
for (LoanID LID : EndLoanIDs) {
- llvm::ImmutableList<OriginID> OriginFlowChain =
+ llvm::SmallVector<OriginID> OriginFlowChain =
Runner.getAnalysis().getLoanPropagation().buildOriginFlowChain(
getProgramPoint(Annotation), *StartOriginID, LID,
- Runner.getAnalysisContext().getCFG(), OriginFlowChainFactory);
- if (!OriginFlowChain.isEmpty())
+ Runner.getAnalysisContext().getCFG());
+ if (!OriginFlowChain.empty())
return OriginFlowChain;
}
@@ -2002,15 +2001,12 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChain) {
}
)");
- llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtA;
- llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtB;
- llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtC;
- llvm::ImmutableList<OriginID> ChainForTgtA = Helper->buildOriginFlowChain(
- "s", "tgta", "after_nested_merge", ChainFactoryForTgtA);
- llvm::ImmutableList<OriginID> ChainForTgtB = Helper->buildOriginFlowChain(
- "s", "tgtb", "after_nested_merge", ChainFactoryForTgtB);
- llvm::ImmutableList<OriginID> ChainForTgtC = Helper->buildOriginFlowChain(
- "s", "tgtc", "after_nested_merge", ChainFactoryForTgtC);
+ llvm::SmallVector<OriginID> ChainForTgtA =
+ Helper->buildOriginFlowChain("s", "tgta", "after_nested_merge");
+ llvm::SmallVector<OriginID> ChainForTgtB =
+ Helper->buildOriginFlowChain("s", "tgtb", "after_nested_merge");
+ llvm::SmallVector<OriginID> ChainForTgtC =
+ Helper->buildOriginFlowChain("s", "tgtc", "after_nested_merge");
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(ChainForTgtA, Not(Contains(*Helper->getOriginForDecl("b"))));
@@ -2036,9 +2032,7 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithErrorTargetLoan) {
)");
#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
- llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
- EXPECT_DEATH(Helper->buildOriginFlowChain("s", "a", "after_use",
- OriginFlowChainFactory),
+ EXPECT_DEATH(Helper->buildOriginFlowChain("s", "a", "after_use"),
"TargetLoan must be present in the StartOID at the StartPoint");
#endif
}
@@ -2056,10 +2050,8 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithSelfAssignment) {
}
)");
- llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
- const llvm::ImmutableList<OriginID> OriginFlowChain =
- Helper->buildOriginFlowChain("s", "tgt", "after_use",
- OriginFlowChainFactory);
+ const llvm::SmallVector<OriginID> OriginFlowChain =
+ Helper->buildOriginFlowChain("s", "tgt", "after_use");
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
}
@@ -2075,10 +2067,8 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithMultiAssignInSameStmt) {
}
)");
- llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
- const llvm::ImmutableList<OriginID> OriginFlowChain =
- Helper->buildOriginFlowChain("s", "tgt", "after_use",
- OriginFlowChainFactory);
+ const llvm::SmallVector<OriginID> OriginFlowChain =
+ Helper->buildOriginFlowChain("s", "tgt", "after_use");
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("b")));
@@ -2098,10 +2088,8 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithOverwritingAssignments) {
}
)");
- llvm::ImmutableList<OriginID>::Factory OriginFlowChainFactory;
- const llvm::ImmutableList<OriginID> OriginFlowChain =
- Helper->buildOriginFlowChain("s", "tgt1", "after_use",
- OriginFlowChainFactory);
+ const llvm::SmallVector<OriginID> OriginFlowChain =
+ Helper->buildOriginFlowChain("s", "tgt1", "after_use");
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(OriginFlowChain, Contains(*Helper->getOriginForDecl("b")));
@@ -2122,12 +2110,10 @@ TEST_F(LifetimeAnalysisTest, BuildOriginFlowChainWithLifetimeBound) {
}
)");
- llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtA;
- llvm::ImmutableList<OriginID>::Factory ChainFactoryForTgtB;
- llvm::ImmutableList<OriginID> ChainForTgtA = Helper->buildOriginFlowChain(
- "s", "tgta", "after_use", ChainFactoryForTgtB);
- llvm::ImmutableList<OriginID> ChainForTgtB = Helper->buildOriginFlowChain(
- "s", "tgtb", "after_use", ChainFactoryForTgtB);
+ llvm::SmallVector<OriginID> ChainForTgtA =
+ Helper->buildOriginFlowChain("s", "tgta", "after_use");
+ llvm::SmallVector<OriginID> ChainForTgtB =
+ Helper->buildOriginFlowChain("s", "tgtb", "after_use");
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("a")));
EXPECT_THAT(ChainForTgtA, Contains(*Helper->getOriginForDecl("result")));
>From 8ec261b353bab115d7366d64d6bd001bb49b5532 Mon Sep 17 00:00:00 2001
From: Yuan Suo <suoyuan666 at s5n.xyz>
Date: Sun, 12 Jul 2026 09:59:27 +0800
Subject: [PATCH 4/5] Delete the unnecessary parts
Signed-off-by: Yuan Suo <suoyuan666 at s5n.xyz>
---
.../clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h | 1 -
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
index 2dc6f745de38d..838daa024c953 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
@@ -18,7 +18,6 @@
#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
-#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableSet.h"
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index c56726864f20c..f72f7f80abbc0 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -527,7 +527,7 @@ class LifetimeChecker {
/// extracts the corresponding expressions for each origin. Origins that refer
/// to declarations (rather than expressions) are skipped.
llvm::SmallVector<const Expr *>
- getExprChain(llvm::SmallVector<OriginID> OriginFlowChain) {
+ getExprChain(llvm::ArrayRef<OriginID> OriginFlowChain) {
llvm::SmallVector<const Expr *> rs;
for (const OriginID CurrOID : OriginFlowChain)
if (const Expr *CurrExpr =
>From 38d33e744ab0eee26cecb41e1384324d190537dd Mon Sep 17 00:00:00 2001
From: Yuan Suo <suoyuan666 at s5n.xyz>
Date: Tue, 14 Jul 2026 20:25:46 +0800
Subject: [PATCH 5/5] Simplify return
Signed-off-by: Yuan Suo <suoyuan666 at s5n.xyz>
---
clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index 1a5deb5bfca10..52f566669be7f 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -251,12 +251,9 @@ class AnalysisImpl
}
// If we found the IssueFact, we're done
- if (Complete) {
- llvm::SmallVector<OriginID> Chain;
- for (OriginID OID : CurrNode.OriginFlowChain)
- Chain.push_back(OID);
- return Chain;
- }
+ if (Complete)
+ return llvm::SmallVector<OriginID>(CurrNode.OriginFlowChain.begin(),
+ CurrNode.OriginFlowChain.end());
// Only explore predecessor blocks where the target loan is present in the
// current origin.
More information about the cfe-commits
mailing list