https://github.com/usx95 created https://github.com/llvm/llvm-project/pull/207526
This patch updates Fact::dump to accept an optional LoanPropagationAnalysis parameter. If provided, OriginFlowFact::dump will query it to print the loans held by the destination origin. This enables richer debug output for LifetimeFacts. TAG=agy CONV=2cfd8d00-18d7-4a03-8d78-2aba2f9a8f23 >From 2d600bae741843473263efc82edec2e85f4a82da Mon Sep 17 00:00:00 2001 From: Utkarsh Saxena <[email protected]> Date: Sat, 4 Jul 2026 16:44:49 +0000 Subject: [PATCH] [LifetimeSafety][NFC] Support printing propagated loans in Fact::dump This patch updates Fact::dump to accept an optional LoanPropagationAnalysis parameter. If provided, OriginFlowFact::dump will query it to print the loans held by the destination origin. This enables richer debug output for LifetimeFacts. TAG=agy CONV=2cfd8d00-18d7-4a03-8d78-2aba2f9a8f23 --- .../Analysis/Analyses/LifetimeSafety/Facts.h | 51 ++++++++++-------- clang/lib/Analysis/LifetimeSafety/Facts.cpp | 54 +++++++++++++------ .../LifetimeSafety/LifetimeSafety.cpp | 10 ++-- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h index 5c671a93b149c..8dccccc0f2257 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h @@ -23,11 +23,14 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include <cstdint> #include <optional> namespace clang::lifetimes::internal { +class LoanPropagationAnalysis; + using FactID = utils::ID<struct FactTag>; /// An abstract base class for a single, atomic lifetime-relevant event. @@ -80,7 +83,8 @@ class Fact { } virtual void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &) const; + const OriginManager &, + const LoanPropagationAnalysis *LPA = nullptr) const; }; /// A `ProgramPoint` identifies a location in the CFG by pointing to a specific @@ -101,7 +105,8 @@ class IssueFact : public Fact { LoanID getLoanID() const { return LID; } OriginID getOriginID() const { return OID; } void dump(llvm::raw_ostream &OS, const LoanManager &LM, - const OriginManager &OM) const override; + const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// When an AccessPath expires (e.g., a variable goes out of scope), all loans @@ -127,7 +132,8 @@ class ExpireFact : public Fact { SourceLocation getExpiryLoc() const { return ExpiryLoc; } void dump(llvm::raw_ostream &OS, const LoanManager &LM, - const OriginManager &OM) const override; + const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; class OriginFlowFact : public Fact { @@ -150,8 +156,8 @@ class OriginFlowFact : public Fact { OriginID getSrcOriginID() const { return OIDSrc; } bool getKillDest() const { return KillDest; } - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// Represents that an origin escapes the current scope through various means. @@ -191,8 +197,8 @@ class ReturnEscapeFact : public OriginEscapesFact { EscapeKind::Return; } const Expr *getReturnExpr() const { return ReturnExpr; }; - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// Represents that an origin escapes via assignment to a field. @@ -211,8 +217,8 @@ class FieldEscapeFact : public OriginEscapesFact { EscapeKind::Field; } const FieldDecl *getFieldDecl() const { return FDecl; }; - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// Represents that an origin escapes via assignment to global or static @@ -230,8 +236,8 @@ class GlobalEscapeFact : public OriginEscapesFact { EscapeKind::Global; } const VarDecl *getGlobal() const { return Global; }; - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; class UseFact : public Fact { @@ -253,8 +259,8 @@ class UseFact : public Fact { void markAsWritten() { IsWritten = true; } bool isWritten() const { return IsWritten; } - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// Represents that an origin's storage has been invalidated by a container @@ -276,8 +282,8 @@ class InvalidateOriginFact : public Fact { OriginID getInvalidatedOrigin() const { return OID; } const Expr *getInvalidationExpr() const { return InvalidationExpr; } - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// Top-level origin of the expression which was found to be moved, e.g, when @@ -297,8 +303,8 @@ class MovedOriginFact : public Fact { OriginID getMovedOrigin() const { return MovedOrigin; } const Expr *getMoveExpr() const { return MoveExpr; } - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// A dummy-fact used to mark a specific point in the code for testing. @@ -314,8 +320,8 @@ class TestPointFact : public Fact { StringRef getAnnotation() const { return Annotation; } - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; /// All loans are cleared from an origin (e.g., assigning a callable without @@ -332,8 +338,8 @@ class KillOriginFact : public Fact { OriginID getKilledOrigin() const { return OID; } - void dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const override; + void dump(llvm::raw_ostream &OS, const LoanManager &, const OriginManager &OM, + const LoanPropagationAnalysis *LPA = nullptr) const override; }; class FactManager { @@ -363,7 +369,8 @@ class FactManager { return Res; } - void dump(const CFG &Cfg, AnalysisDeclContext &AC) const; + void dump(const CFG &Cfg, AnalysisDeclContext &AC, + const LoanPropagationAnalysis *LPA = nullptr) const; /// Retrieves program points that were specially marked in the source code /// for testing. diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp index 3d7fbcdacc830..333a69d600061 100644 --- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp @@ -7,18 +7,20 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/LifetimeSafety/Facts.h" +#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h" #include "clang/AST/Decl.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" namespace clang::lifetimes::internal { void Fact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &) const { + const OriginManager &, const LoanPropagationAnalysis *) const { OS << "Fact (Kind: " << static_cast<int>(K) << ")\n"; } void IssueFact::dump(llvm::raw_ostream &OS, const LoanManager &LM, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "Issue ("; LM.getLoan(getLoanID())->dump(OS); OS << ", ToOrigin: "; @@ -27,7 +29,8 @@ void IssueFact::dump(llvm::raw_ostream &OS, const LoanManager &LM, } void ExpireFact::dump(llvm::raw_ostream &OS, const LoanManager &LM, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *LPA) const { OS << "Expire ("; getAccessPath().dump(OS); if (auto OID = getOriginID()) { @@ -37,11 +40,23 @@ void ExpireFact::dump(llvm::raw_ostream &OS, const LoanManager &LM, OS << ")\n"; } -void OriginFlowFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { +void OriginFlowFact::dump(llvm::raw_ostream &OS, const LoanManager &LM, + const OriginManager &OM, + const LoanPropagationAnalysis *LPA) const { OS << "OriginFlow: \n"; OS << "\tDest: "; OM.dump(getDestOriginID(), OS); + if (LPA) { + LoanSet DestinationLoans = LPA->getLoans(getDestOriginID(), this); + if (!DestinationLoans.isEmpty()) { + OS << " has loans to { "; + for (LoanID LID : DestinationLoans) { + LM.getLoan(LID)->getAccessPath().dump(OS); + OS << " "; + } + OS << "}"; + } + } OS << "\n"; OS << "\tSrc: "; OM.dump(getSrcOriginID(), OS); @@ -50,35 +65,40 @@ void OriginFlowFact::dump(llvm::raw_ostream &OS, const LoanManager &, } void MovedOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "MovedOrigins ("; OM.dump(getMovedOrigin(), OS); OS << ")\n"; } void ReturnEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "OriginEscapes ("; OM.dump(getEscapedOriginID(), OS); OS << ", via Return)\n"; } void FieldEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "OriginEscapes ("; OM.dump(getEscapedOriginID(), OS); OS << ", via Field)\n"; } void GlobalEscapeFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "OriginEscapes ("; OM.dump(getEscapedOriginID(), OS); OS << ", via Global)\n"; } void UseFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "Use ("; size_t NumUsedOrigins = getUsedOrigins()->getLength(); size_t I = 0; @@ -92,19 +112,22 @@ void UseFact::dump(llvm::raw_ostream &OS, const LoanManager &, } void InvalidateOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "InvalidateOrigin ("; OM.dump(getInvalidatedOrigin(), OS); OS << ")\n"; } void TestPointFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &) const { + const OriginManager &, + const LoanPropagationAnalysis *) const { OS << "TestPoint (Annotation: \"" << getAnnotation() << "\")\n"; } void KillOriginFact::dump(llvm::raw_ostream &OS, const LoanManager &, - const OriginManager &OM) const { + const OriginManager &OM, + const LoanPropagationAnalysis *) const { OS << "KillOrigin ("; OM.dump(getKilledOrigin(), OS); OS << ")\n"; @@ -125,7 +148,8 @@ llvm::StringMap<ProgramPoint> FactManager::getTestPoints() const { return AnnotationToPointMap; } -void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const { +void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC, + const LoanPropagationAnalysis *LPA) const { llvm::dbgs() << "==========================================\n"; llvm::dbgs() << " Lifetime Analysis Facts:\n"; llvm::dbgs() << "==========================================\n"; @@ -137,7 +161,7 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const { llvm::dbgs() << " Block B" << B->getBlockID() << ":\n"; for (const Fact *F : getFacts(B)) { llvm::dbgs() << " "; - F->dump(llvm::dbgs(), LoanMgr, OriginMgr); + F->dump(llvm::dbgs(), LoanMgr, OriginMgr, LPA); } llvm::dbgs() << " End of Block\n"; } diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index 680095a54177c..798812327d3ab 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -35,7 +35,8 @@ namespace internal { #ifndef NDEBUG static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg, - FactManager &FactMgr) { + FactManager &FactMgr, + const LoanPropagationAnalysis *LPA) { std::string Name; if (const Decl *D = AC.getDecl()) { if (const auto *ND = dyn_cast<NamedDecl>(D)) @@ -44,7 +45,7 @@ static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg, DEBUG_WITH_TYPE(Name.c_str(), AC.getDecl()->dumpColor()); DEBUG_WITH_TYPE(Name.c_str(), Cfg.dump(AC.getASTContext().getLangOpts(), /*ShowColors=*/true)); - DEBUG_WITH_TYPE(Name.c_str(), FactMgr.dump(Cfg, AC)); + DEBUG_WITH_TYPE(Name.c_str(), FactMgr.dump(Cfg, AC, LPA)); } #endif @@ -101,12 +102,13 @@ void LifetimeSafetyAnalysis::run() { DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(), /*ShowColors=*/true)); - DEBUG_WITH_TYPE("LifetimeFacts", FactMgr->dump(Cfg, AC)); + DEBUG_WITH_TYPE("LifetimeFacts", + FactMgr->dump(Cfg, AC, LoanPropagation.get())); // Debug print facts for a specific function using // -debug-only=EnableFilterByFunctionName,YourFunctionNameFoo DEBUG_WITH_TYPE("EnableFilterByFunctionName", - DebugOnlyFunction(AC, Cfg, *FactMgr)); + DebugOnlyFunction(AC, Cfg, *FactMgr, LoanPropagation.get())); DEBUG_WITH_TYPE("LiveOrigins", LiveOrigins->dump(llvm::dbgs(), FactMgr->getTestPoints())); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
