[clang] [LifetimeSafety] Add multi-block support to buildOriginFlowChain (PR #204592)
Yuan Suo via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 19 00:28:43 PDT 2026
https://github.com/suoyuan666 updated https://github.com/llvm/llvm-project/pull/204592
>From 7ef65e032565e5e5589b6fdb5f7d6982ccaedffc Mon Sep 17 00:00:00 2001
From: Yuan Suo <suoyuan666 at s5n.xyz>
Date: Wed, 17 Jun 2026 18:04:06 +0800
Subject: [PATCH 1/2] [LifetimeSafety] Add multi-block support to
buildOriginFlowChain
After introducing `buildOriginFlowChain` to use-after-scope diagnostics,
it should support multi-block analysis. This also allows it to be reused
by other diagnostics.
In some loops, UseFact may appear before OriginFlowFact:
```cpp
void for_loop_use_before_loop_body(MyObj safe) {
MyObj* p = &safe;
for (int i = 0; i < 1; ++i) {
(void)*p;
MyObj s;
p = &s;
}
(void)*p;
}
```
So, I remove the `StartPoint` parameter to correctly find the `OriginID`.
Signed-off-by: Yuan Suo <suoyuan666 at s5n.xyz>
---
.../Analysis/Analyses/LifetimeSafety/Facts.h | 1 +
.../Analyses/LifetimeSafety/LoanPropagation.h | 7 +-
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 6 +-
clang/lib/Analysis/LifetimeSafety/Facts.cpp | 15 ++-
.../LifetimeSafety/LoanPropagation.cpp | 99 ++++++++++++++-----
clang/lib/Sema/SemaLifetimeSafety.h | 4 +-
clang/test/Sema/LifetimeSafety/safety-c.c | 4 +-
clang/test/Sema/LifetimeSafety/safety.cpp | 33 +++++--
.../unittests/Analysis/LifetimeSafetyTest.cpp | 3 +-
9 files changed, 125 insertions(+), 47 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 88b509e1b94df..e0ddfe95b00b2 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -374,6 +374,7 @@ class FactManager {
/// Retrieves all the facts in the block containing Program Point P.
/// \note This is intended for testing only.
llvm::ArrayRef<const Fact *> getBlockContaining(ProgramPoint P) const;
+ std::optional<size_t> getBlockID(ProgramPoint P) const;
unsigned getNumFacts() const { return NextFactID.Value; }
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
index 724c6eee7d3c2..42d7df0838f35 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LOAN_PROPAGATION_H
#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -46,10 +47,12 @@ class LoanPropagationAnalysis {
/// where the loan was originally issued.
llvm::SmallVector<OriginID>
buildOriginFlowChain(ProgramPoint StartPoint, const OriginID StartOID,
- const LoanID TargetLoan) const;
+ const LoanID TargetLoan,
+ const PostOrderCFGView *POV) const;
llvm::SmallVector<OriginID>
- buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan) const;
+ buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan,
+ const PostOrderCFGView *POV) const;
private:
class Impl;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index d41d6f43f837b..2fe52585087e4 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -68,6 +68,7 @@ class LifetimeChecker {
LifetimeSafetySemaHelper *SemaHelper;
ASTContext &AST;
const Decl *FD;
+ const PostOrderCFGView *POV;
static SourceLocation
GetFactLoc(llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> F) {
@@ -90,7 +91,8 @@ class LifetimeChecker {
LifetimeSafetySemaHelper *SemaHelper)
: LoanPropagation(LoanPropagation), MovedLoans(MovedLoans),
LiveOrigins(LiveOrigins), FactMgr(FM), SemaHelper(SemaHelper),
- AST(ADC.getASTContext()), FD(ADC.getDecl()) {
+ AST(ADC.getASTContext()), FD(ADC.getDecl()),
+ POV(ADC.getAnalysis<PostOrderCFGView>()) {
for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
for (const Fact *F : FactMgr.getFacts(B))
if (const auto *EF = F->getAs<ExpireFact>())
@@ -268,7 +270,7 @@ class LifetimeChecker {
// Scope-based expiry (use-after-scope).
SemaHelper->reportUseAfterScope(
IssueExpr, UF->getUseExpr(), MovedExpr, ExpiryLoc,
- getExprChain(LoanPropagation.buildOriginFlowChain(UF, LID)));
+ getExprChain(LoanPropagation.buildOriginFlowChain(UF, LID, POV)));
} else if (const auto *OEF =
CausingFact.dyn_cast<const OriginEscapesFact *>()) {
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 3d7fbcdacc830..823f1f686f904 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -145,12 +145,17 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const {
llvm::ArrayRef<const Fact *>
FactManager::getBlockContaining(ProgramPoint P) const {
- for (const auto &BlockToFactsVec : BlockToFacts) {
- for (const Fact *F : BlockToFactsVec)
- if (F == P)
- return BlockToFactsVec;
- }
+ std::optional<size_t> BlockIndex = getBlockID(P);
+ if (BlockIndex)
+ return BlockToFacts[BlockIndex.value()];
return {};
}
+std::optional<size_t> FactManager::getBlockID(ProgramPoint P) const {
+ for (size_t i = 0; i < BlockToFacts.size(); ++i)
+ for (const Fact *F : BlockToFacts[i])
+ if (F == P)
+ return i;
+ return std::nullopt;
+}
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index a67b1b3c0f826..8e2d9a6577427 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -130,6 +130,11 @@ struct Lattice {
}
};
+struct BuildOriginFlowChainResult {
+ const llvm::SmallVector<OriginID> OriginFlowChain;
+ const bool Complete;
+};
+
class AnalysisImpl
: public DataflowAnalysis<AnalysisImpl, Lattice, Direction::Forward> {
public:
@@ -204,22 +209,72 @@ class AnalysisImpl
llvm::SmallVector<OriginID>
buildOriginFlowChain(ProgramPoint StartPoint, const OriginID StartOID,
- const LoanID TargetLoan) const {
+ const LoanID TargetLoan,
+ const PostOrderCFGView *POV) const {
assert(getLoans(StartOID, StartPoint).contains(TargetLoan) &&
"TargetLoan must be present in the StartOID at the StartPoint");
+ std::optional<OriginID> FinalOID;
+ llvm::DenseMap<OriginID, OriginID> VistedOriginIDs;
+
+ const auto OriginFlowChainFilter = [&VistedOriginIDs](OriginID FinalOID) {
+ llvm::SmallVector<OriginID> OriginFlowChain;
+ while (true) {
+ OriginFlowChain.push_back(FinalOID);
+ const auto NextOriginID = VistedOriginIDs.find(FinalOID);
+ if (NextOriginID == VistedOriginIDs.end())
+ break;
+ FinalOID = NextOriginID->second;
+ }
+ return OriginFlowChain;
+ };
+
+ const auto InsertVistedOriginIDs =
+ [&VistedOriginIDs, &FinalOID](llvm::ArrayRef<OriginID> OriginFlowChain,
+ OriginID &StartOID) {
+ if (!VistedOriginIDs.empty())
+ VistedOriginIDs.insert({OriginFlowChain[0], StartOID});
+
+ for (size_t i = 0; i < OriginFlowChain.size() - 1; ++i)
+ VistedOriginIDs.insert(
+ {OriginFlowChain[i + 1], OriginFlowChain[i]});
+
+ StartOID = OriginFlowChain.back();
+ FinalOID = StartOID;
+ };
+
+ std::optional<size_t> BlockID = FactMgr.getBlockID(StartPoint);
+ assert(BlockID.has_value());
+ const auto StartIt = llvm::find_if(*POV, [&BlockID](const CFGBlock *Block) {
+ return Block->getBlockID() == BlockID;
+ });
+
+ OriginID CurrOID = StartOID;
+ for (const CFGBlock *B :
+ llvm::reverse(llvm::make_range(POV->begin(), StartIt + 1))) {
+ BuildOriginFlowChainResult BuildResult =
+ buildOriginFlowChain(B, CurrOID, TargetLoan);
+ if (!BuildResult.OriginFlowChain.empty())
+ InsertVistedOriginIDs(BuildResult.OriginFlowChain, CurrOID);
+ if (BuildResult.Complete)
+ return OriginFlowChainFilter(*FinalOID);
+ }
+
+ llvm_unreachable(
+ "buildOriginFlowChain should return at BuildResult.Complete");
+ }
+
+ BuildOriginFlowChainResult
+ buildOriginFlowChain(const CFGBlock *Block, const OriginID StartOID,
+ const LoanID TargetLoan) const {
OriginID CurrOID = StartOID;
llvm::SmallVector<OriginID> OriginFlowChain;
- llvm::ArrayRef<const Fact *> Facts = FactMgr.getBlockContaining(StartPoint);
- const auto *StartIt = llvm::find(Facts, StartPoint);
- assert(StartIt != Facts.end());
- for (const Fact *F :
- llvm::reverse(llvm::make_range(Facts.begin(), StartIt))) {
+ for (const Fact *F : llvm::reverse(FactMgr.getFacts(Block))) {
if (const auto *IF = F->getAs<IssueFact>())
if (IF->getLoanID() == TargetLoan) {
assert(IF->getOriginID() == CurrOID);
- return OriginFlowChain;
+ return {OriginFlowChain, true};
}
const auto *OFF = F->getAs<OriginFlowFact>();
@@ -235,20 +290,17 @@ class AnalysisImpl
CurrOID = SrcOriginID;
}
- // FIXME: Ideally, this return is unreachable and should be an assert
- // because we expect to always finish at an IssueFact. But since current
- // traversal is limited to a single CFG block, multi-block OriginFlowChain
- // construction might miss the IssueFact. We should add llvm_unreachable
- // here once multi-block support is implemented.
- return {};
+ return {OriginFlowChain, false};
}
llvm::SmallVector<OriginID>
- buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan) const {
+ buildOriginFlowChain(const UseFact *UF, const LoanID TargetLoan,
+ const PostOrderCFGView *POV) const {
for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
Cur = Cur->peelOuterOrigin())
if (getLoans(Cur->getOuterOriginID(), UF).contains(TargetLoan))
- return buildOriginFlowChain(UF, Cur->getOuterOriginID(), TargetLoan);
+ return buildOriginFlowChain(UF, Cur->getOuterOriginID(), TargetLoan,
+ POV);
return {};
}
@@ -303,16 +355,15 @@ LoanSet LoanPropagationAnalysis::getLoans(OriginID OID, ProgramPoint P) const {
return PImpl->getLoans(OID, P);
}
-llvm::SmallVector<OriginID>
-LoanPropagationAnalysis::buildOriginFlowChain(ProgramPoint StartPoint,
- const OriginID StartOID,
- const LoanID TargetLoan) const {
- return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan);
+llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
+ ProgramPoint StartPoint, const OriginID StartOID, const LoanID TargetLoan,
+ const PostOrderCFGView *POV) const {
+ return PImpl->buildOriginFlowChain(StartPoint, StartOID, TargetLoan, POV);
}
-llvm::SmallVector<OriginID>
-LoanPropagationAnalysis::buildOriginFlowChain(const UseFact *UF,
- const LoanID TargetLoan) const {
- return PImpl->buildOriginFlowChain(UF, TargetLoan);
+llvm::SmallVector<OriginID> LoanPropagationAnalysis::buildOriginFlowChain(
+ const UseFact *UF, const LoanID TargetLoan,
+ const PostOrderCFGView *POV) const {
+ return PImpl->buildOriginFlowChain(UF, TargetLoan, POV);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index a8bde363e3397..f4649019ceb1d 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -550,10 +550,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/test/Sema/LifetimeSafety/safety-c.c b/clang/test/Sema/LifetimeSafety/safety-c.c
index 95c8cf7bb00c7..c87a9b4768f2c 100644
--- a/clang/test/Sema/LifetimeSafety/safety-c.c
+++ b/clang/test/Sema/LifetimeSafety/safety-c.c
@@ -93,7 +93,9 @@ void conditional_operator_lifetimebound(int cond) {
int *p;
{
int a, b;
- p = identity(cond ? &a // expected-warning {{local variable 'a' does not live long enough}}
+ p = identity(cond ? &a // expected-warning {{local variable 'a' does not live long enough}} \
+ // expected-note {{result of call to 'identity' aliases the storage of local variable 'a'}} \
+ // expected-note {{result of call to 'identity' aliases the storage of local variable 'b'}}
: &b); // expected-warning {{local variable 'b' does not live long enough}}
} // expected-note 2 {{destroyed here}}
(void)*p; // expected-note 2 {{later used here}}
diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp
index 6fc275b51a9d0..51b042afa8760 100644
--- a/clang/test/Sema/LifetimeSafety/safety.cpp
+++ b/clang/test/Sema/LifetimeSafety/safety.cpp
@@ -236,7 +236,7 @@ void overrides_potential(bool cond) {
{
MyObj s;
q = &s; // expected-warning {{does not live long enough}}
- p = q;
+ p = q; // expected-note {{local variable 'q' aliases the storage of local variable 's'}}
} // expected-note {{destroyed here}}
if (cond) {
@@ -448,7 +448,7 @@ void loan_from_previous_iteration(MyObj safe, bool condition) {
p = &x; // expected-warning {{does not live long enough}}
if (condition)
- q = p;
+ q = p; // expected-note {{local variable 'p' aliases the storage of local variable 'x'}}
(void)*p;
(void)*q; // expected-note {{later used here}}
} // expected-note {{destroyed here}}
@@ -845,7 +845,8 @@ void lifetimebound_multiple_args_potential(bool cond) {
MyObj obj1;
if (cond) {
MyObj obj2;
- v = Choose(true,
+ v = Choose(true, // expected-note {{result of call to 'Choose' aliases the storage of local variable 'obj1'}} \
+ // expected-note {{result of call to 'Choose' aliases the storage of local variable 'obj2'}}
obj1, // expected-warning {{local variable 'obj1' does not live long enough}}
obj2); // expected-warning {{local variable 'obj2' does not live long enough}}
} // expected-note {{destroyed here}}
@@ -939,7 +940,7 @@ void lifetimebound_partial_safety(bool cond) {
if (cond) {
MyObj temp_obj;
- v = Choose(true,
+ v = Choose(true, // expected-note {{result of call to 'Choose' aliases the storage of local variable 'temp_obj'}}
safe_obj,
temp_obj); // expected-warning {{local variable 'temp_obj' does not live long enough}}
} // expected-note {{destroyed here}}
@@ -1222,7 +1223,9 @@ void conditional_operator_lifetimebound(bool cond) {
MyObj* p;
{
MyObj a, b;
- p = Identity(cond ? &a // expected-warning {{local variable 'a' does not live long enough}}
+ p = Identity(cond ? &a // expected-warning {{local variable 'a' does not live long enough}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'a'}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'b'}}
: &b); // expected-warning {{local variable 'b' does not live long enough}}
} // expected-note 2 {{destroyed here}}
(void)*p; // expected-note 2 {{later used here}}
@@ -1232,8 +1235,11 @@ void conditional_operator_lifetimebound_nested(bool cond) {
MyObj* p;
{
MyObj a, b;
- p = Identity(cond ? Identity(&a) // expected-warning {{local variable 'a' does not live long enough}}
- : Identity(&b)); // expected-warning {{local variable 'b' does not live long enough}}
+ p = Identity(cond ? Identity(&a) // expected-warning {{local variable 'a' does not live long enough}} \
+ // expected-note 2 {{result of call to 'Identity' aliases the storage of local variable 'a'}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'b'}}
+ : Identity(&b)); // expected-warning {{local variable 'b' does not live long enough}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'b'}}
} // expected-note 2 {{destroyed here}}
(void)*p; // expected-note 2 {{later used here}}
}
@@ -1242,9 +1248,15 @@ void conditional_operator_lifetimebound_nested_deep(bool cond) {
MyObj* p;
{
MyObj a, b, c, d;
- p = Identity(cond ? Identity(cond ? &a // expected-warning {{local variable 'a' does not live long enough}}
+ p = Identity(cond ? Identity(cond ? &a // expected-warning {{local variable 'a' does not live long enough}} \
+ // expected-note 2 {{result of call to 'Identity' aliases the storage of local variable 'a'}} \
+ // expected-note 2 {{result of call to 'Identity' aliases the storage of local variable 'b'}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'c'}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'd'}}
: &b) // expected-warning {{local variable 'b' does not live long enough}}
- : Identity(cond ? &c // expected-warning {{local variable 'c' does not live long enough}}
+ : Identity(cond ? &c // expected-warning {{local variable 'c' does not live long enough}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'c'}} \
+ // expected-note {{result of call to 'Identity' aliases the storage of local variable 'd'}}
: &d)); // expected-warning {{local variable 'd' does not live long enough}}
} // expected-note 4 {{destroyed here}}
(void)*p; // expected-note 4 {{later used here}}
@@ -1428,7 +1440,8 @@ void range_based_for_use_after_scope() {
View v;
{
MyObjStorage s;
- for (const MyObj &o : s) { // expected-warning {{local variable 's' does not live long enough}}
+ for (const MyObj &o : s) { // expected-warning {{local variable 's' does not live long enough}} \
+ // expected-note {{local variable '__range2' aliases the storage of local variable 's'}}
v = o;
}
} // expected-note {{destroyed here}}
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index 78b7449958140..8d5ed9c88dcff 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -215,7 +215,8 @@ class LifetimeTestHelper {
for (LoanID LID : EndLoanIDs) {
llvm::SmallVector<OriginID> OriginFlowChain =
Runner.getAnalysis().getLoanPropagation().buildOriginFlowChain(
- getProgramPoint(Annotation), *StartOriginID, LID);
+ getProgramPoint(Annotation), *StartOriginID, LID,
+ Runner.getAnalysisContext().getAnalysis<PostOrderCFGView>());
if (!OriginFlowChain.empty())
return OriginFlowChain;
}
>From 3a7b00c0333abc25f1f7a7e140fae90cafeafbf3 Mon Sep 17 00:00:00 2001
From: Yuan Suo <suoyuan666 at s5n.xyz>
Date: Fri, 19 Jun 2026 15:25:42 +0800
Subject: [PATCH 2/2] Add return after llvm_unreachable and clean up code
Signed-off-by: Yuan Suo <suoyuan666 at s5n.xyz>
---
.../LifetimeSafety/LoanPropagation.cpp | 104 +++++++-----------
clang/lib/Sema/SemaLifetimeSafety.h | 4 +-
2 files changed, 42 insertions(+), 66 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
index 8e2d9a6577427..59081522b40f7 100644
--- a/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LoanPropagation.cpp
@@ -214,35 +214,7 @@ class AnalysisImpl
assert(getLoans(StartOID, StartPoint).contains(TargetLoan) &&
"TargetLoan must be present in the StartOID at the StartPoint");
- std::optional<OriginID> FinalOID;
- llvm::DenseMap<OriginID, OriginID> VistedOriginIDs;
-
- const auto OriginFlowChainFilter = [&VistedOriginIDs](OriginID FinalOID) {
- llvm::SmallVector<OriginID> OriginFlowChain;
- while (true) {
- OriginFlowChain.push_back(FinalOID);
- const auto NextOriginID = VistedOriginIDs.find(FinalOID);
- if (NextOriginID == VistedOriginIDs.end())
- break;
- FinalOID = NextOriginID->second;
- }
- return OriginFlowChain;
- };
-
- const auto InsertVistedOriginIDs =
- [&VistedOriginIDs, &FinalOID](llvm::ArrayRef<OriginID> OriginFlowChain,
- OriginID &StartOID) {
- if (!VistedOriginIDs.empty())
- VistedOriginIDs.insert({OriginFlowChain[0], StartOID});
-
- for (size_t i = 0; i < OriginFlowChain.size() - 1; ++i)
- VistedOriginIDs.insert(
- {OriginFlowChain[i + 1], OriginFlowChain[i]});
-
- StartOID = OriginFlowChain.back();
- FinalOID = StartOID;
- };
-
+ llvm::SmallVector<OriginID> OriginFlowChain;
std::optional<size_t> BlockID = FactMgr.getBlockID(StartPoint);
assert(BlockID.has_value());
const auto StartIt = llvm::find_if(*POV, [&BlockID](const CFGBlock *Block) {
@@ -252,45 +224,20 @@ class AnalysisImpl
OriginID CurrOID = StartOID;
for (const CFGBlock *B :
llvm::reverse(llvm::make_range(POV->begin(), StartIt + 1))) {
- BuildOriginFlowChainResult BuildResult =
- buildOriginFlowChain(B, CurrOID, TargetLoan);
- if (!BuildResult.OriginFlowChain.empty())
- InsertVistedOriginIDs(BuildResult.OriginFlowChain, CurrOID);
- if (BuildResult.Complete)
- return OriginFlowChainFilter(*FinalOID);
- }
-
- llvm_unreachable(
- "buildOriginFlowChain should return at BuildResult.Complete");
- }
-
- BuildOriginFlowChainResult
- buildOriginFlowChain(const CFGBlock *Block, const OriginID StartOID,
- const LoanID TargetLoan) const {
- OriginID CurrOID = StartOID;
- llvm::SmallVector<OriginID> OriginFlowChain;
+ auto [OFChain, Complete] = buildOriginFlowChain(B, CurrOID, TargetLoan);
- for (const Fact *F : llvm::reverse(FactMgr.getFacts(Block))) {
- if (const auto *IF = F->getAs<IssueFact>())
- if (IF->getLoanID() == TargetLoan) {
- assert(IF->getOriginID() == CurrOID);
- return {OriginFlowChain, true};
- }
-
- const auto *OFF = F->getAs<OriginFlowFact>();
- if (!OFF)
- continue;
- if (OFF->getDestOriginID() != CurrOID)
- continue;
+ if (!OFChain.empty()) {
+ OriginFlowChain.append(OFChain.begin(), OFChain.end());
+ CurrOID = OFChain.back();
+ }
- const OriginID SrcOriginID = OFF->getSrcOriginID();
- if (!getLoans(SrcOriginID, OFF).contains(TargetLoan))
- continue;
- OriginFlowChain.push_back(SrcOriginID);
- CurrOID = SrcOriginID;
+ if (Complete)
+ return OriginFlowChain;
}
- return {OriginFlowChain, false};
+ llvm_unreachable(
+ "buildOriginFlowChain should return at BuildResult.Complete");
+ return OriginFlowChain;
}
llvm::SmallVector<OriginID>
@@ -327,6 +274,35 @@ class AnalysisImpl
return LoanSetFactory.getEmptySet();
}
+ BuildOriginFlowChainResult
+ buildOriginFlowChain(const CFGBlock *Block, const OriginID StartOID,
+ const LoanID TargetLoan) const {
+ OriginID CurrOID = StartOID;
+ llvm::SmallVector<OriginID> OriginFlowChain;
+
+ for (const Fact *F : llvm::reverse(FactMgr.getFacts(Block))) {
+ if (const auto *IF = F->getAs<IssueFact>())
+ if (IF->getLoanID() == TargetLoan) {
+ assert(IF->getOriginID() == CurrOID);
+ return {OriginFlowChain, true};
+ }
+
+ const auto *OFF = F->getAs<OriginFlowFact>();
+ if (!OFF)
+ continue;
+ if (OFF->getDestOriginID() != CurrOID)
+ continue;
+
+ const OriginID SrcOriginID = OFF->getSrcOriginID();
+ if (!getLoans(SrcOriginID, OFF).contains(TargetLoan))
+ continue;
+ OriginFlowChain.push_back(SrcOriginID);
+ CurrOID = SrcOriginID;
+ }
+
+ return {OriginFlowChain, false};
+ }
+
OriginLoanMap::Factory &OriginLoanMapFactory;
LoanSet::Factory &LoanSetFactory;
/// Boolean vector indexed by origin ID. If true, the origin appears in
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index f4649019ceb1d..bbc7c77de4d31 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -550,10 +550,10 @@ class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
if (OriginExprChain.empty())
return;
- const Expr *LastExpr = OriginExprChain.front();
+ const Expr *LastExpr = OriginExprChain.back();
std::string IssueStr = getDiagSubjectDescription(LastExpr);
- for (const Expr *CurrExpr : OriginExprChain.drop_front()) {
+ for (const Expr *CurrExpr : llvm::reverse(OriginExprChain.drop_back())) {
if (!shouldShowInAliasChain(CurrExpr, LastExpr))
continue;
S.Diag(CurrExpr->getBeginLoc(),
More information about the cfe-commits
mailing list