Skip to content

Commit 2860431

Browse files
authored
[LifetimeSafety] Add per-program-point lattice tracking (#149199)
Add per-program-point state tracking to the dataflow analysis framework. - Added a `ProgramPoint` type representing a pair of a CFGBlock and a Fact within that block - Added a `PerPointStates` map to store lattice states at each program point - Modified the `transferBlock` method to store intermediate states after each fact is processed - Added a `getLoans` method to the `LoanPropagationAnalysis` class that uses program points This change enables more precise analysis by tracking program state at each individual program point rather than just at block boundaries. This is necessary for answering queries about the state of loans, origins, and other properties at specific points in the program, which is required for error reporting in the lifetime safety analysis.
1 parent f0bbe73 commit 2860431

File tree

1 file changed

+31
-8
lines changed

1 file changed

+31
-8
lines changed

clang/lib/Analysis/LifetimeSafety.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,13 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
502502

503503
enum class Direction { Forward, Backward };
504504

505+
/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
506+
/// `Fact`. identified by a lifetime-related event (`Fact`).
507+
///
508+
/// A `ProgramPoint` has "after" semantics: it represents the location
509+
/// immediately after its corresponding `Fact`.
510+
using ProgramPoint = const Fact *;
511+
505512
/// A generic, policy-based driver for dataflow analyses. It combines
506513
/// the dataflow runner and the transferer logic into a single class hierarchy.
507514
///
@@ -524,14 +531,20 @@ template <typename Derived, typename LatticeType, Direction Dir>
524531
class DataflowAnalysis {
525532
public:
526533
using Lattice = LatticeType;
527-
using Base = DataflowAnalysis<Derived, LatticeType, Dir>;
534+
using Base = DataflowAnalysis<Derived, Lattice, Dir>;
528535

529536
private:
530537
const CFG &Cfg;
531538
AnalysisDeclContext &AC;
532539

540+
/// The dataflow state before a basic block is processed.
533541
llvm::DenseMap<const CFGBlock *, Lattice> InStates;
542+
/// The dataflow state after a basic block is processed.
534543
llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
544+
/// The dataflow state at a Program Point.
545+
/// In a forward analysis, this is the state after the Fact at that point has
546+
/// been applied, while in a backward analysis, it is the state before.
547+
llvm::DenseMap<ProgramPoint, Lattice> PerPointStates;
535548

536549
static constexpr bool isForward() { return Dir == Direction::Forward; }
537550

@@ -577,6 +590,8 @@ class DataflowAnalysis {
577590
}
578591
}
579592

593+
Lattice getState(ProgramPoint P) const { return PerPointStates.lookup(P); }
594+
580595
Lattice getInState(const CFGBlock *B) const { return InStates.lookup(B); }
581596

582597
Lattice getOutState(const CFGBlock *B) const { return OutStates.lookup(B); }
@@ -590,18 +605,23 @@ class DataflowAnalysis {
590605
getOutState(&B).dump(llvm::dbgs());
591606
}
592607

608+
private:
593609
/// Computes the state at one end of a block by applying all its facts
594610
/// sequentially to a given state from the other end.
595-
/// TODO: We might need to store intermediate states per-fact in the block for
596-
/// later analysis.
597611
Lattice transferBlock(const CFGBlock *Block, Lattice State) {
598612
auto Facts = AllFacts.getFacts(Block);
599-
if constexpr (isForward())
600-
for (const Fact *F : Facts)
613+
if constexpr (isForward()) {
614+
for (const Fact *F : Facts) {
601615
State = transferFact(State, F);
602-
else
603-
for (const Fact *F : llvm::reverse(Facts))
616+
PerPointStates[F] = State;
617+
}
618+
} else {
619+
for (const Fact *F : llvm::reverse(Facts)) {
620+
// In backward analysis, capture the state before applying the fact.
621+
PerPointStates[F] = State;
604622
State = transferFact(State, F);
623+
}
624+
}
605625
return State;
606626
}
607627

@@ -769,6 +789,10 @@ class LoanPropagationAnalysis
769789
Factory.OriginMapFactory.add(In.Origins, DestOID, SrcLoans));
770790
}
771791

792+
LoanSet getLoans(OriginID OID, ProgramPoint P) {
793+
return getLoans(getState(P), OID);
794+
}
795+
772796
private:
773797
LoanSet getLoans(Lattice L, OriginID OID) {
774798
if (auto *Loans = L.Origins.lookup(OID))
@@ -779,7 +803,6 @@ class LoanPropagationAnalysis
779803

780804
// ========================================================================= //
781805
// TODO:
782-
// - Modifying loan propagation to answer `LoanSet getLoans(Origin O, Point P)`
783806
// - Modify loan expiry analysis to answer `bool isExpired(Loan L, Point P)`
784807
// - Modify origin liveness analysis to answer `bool isLive(Origin O, Point P)`
785808
// - Using the above three to perform the final error reporting.

0 commit comments

Comments
 (0)