[clang] [LifetimeSafety] Add bailout for large CFGs (PR #170444)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 02:21:21 PST 2026
https://github.com/DEBADRIBASAK updated https://github.com/llvm/llvm-project/pull/170444
>From a7f5c0cc51ee72bfdd150eb6e4b7aa2b20e24373 Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Wed, 3 Dec 2025 09:11:15 +0000
Subject: [PATCH 01/13] Adding an integer flag for setting a threhsold for
skipping large CFGs and a debug-only flag for printing CFG size stats.
In this context, CFG size refers to the number of facts generated by the fact generator. This is a change to effectively control bail-out strategies.
---
.../Analyses/LifetimeSafety/Checker.h | 3 ++-
.../Analysis/Analyses/LifetimeSafety/Facts.h | 7 +++++++
.../Analyses/LifetimeSafety/LifetimeSafety.h | 7 +++++--
clang/include/clang/Basic/LangOptions.def | 3 +++
clang/include/clang/Options/Options.td | 4 ++++
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 16 ++++++++++----
clang/lib/Analysis/LifetimeSafety/Facts.cpp | 21 +++++++++++++++++++
.../LifetimeSafety/LifetimeSafety.cpp | 15 ++++++++-----
clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +-
9 files changed, 65 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
index 03636be7d00c3..c609543575e0f 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
@@ -28,7 +28,8 @@ namespace clang::lifetimes::internal {
void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetyReporter *Reporter);
+ LifetimeSafetyReporter *Reporter,
+ uint32_t BlockFactNumThreshold);
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index b5f7f8746186a..5e7e93118bf10 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -218,6 +218,9 @@ class FactManager {
void dump(const CFG &Cfg, AnalysisDeclContext &AC) const;
+ // A utility function to print the size of the CFG blocks in the analysis context.
+ void dumpBlockSizes(const CFG &Cfg, AnalysisDeclContext &AC) const;
+
/// Retrieves program points that were specially marked in the source code
/// for testing.
///
@@ -238,6 +241,9 @@ class FactManager {
const LoanManager &getLoanMgr() const { return LoanMgr; }
OriginManager &getOriginMgr() { return OriginMgr; }
const OriginManager &getOriginMgr() const { return OriginMgr; }
+ void setBlockFactNumThreshold(uint32_t Threshold) {
+ BlockFactNumThreshold = Threshold;
+ }
private:
FactID NextFactID{0};
@@ -246,6 +252,7 @@ class FactManager {
/// Facts for each CFG block, indexed by block ID.
llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts;
llvm::BumpPtrAllocator FactAllocator;
+ uint32_t BlockFactNumThreshold = 0;
};
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index b34a7f18b5809..29078756b3e15 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -51,7 +51,8 @@ class LifetimeSafetyReporter {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter);
+ LifetimeSafetyReporter *Reporter,
+ uint32_t BlockFactNumThreshold);
namespace internal {
/// An object to hold the factories for immutable collections, ensuring
@@ -67,7 +68,8 @@ struct LifetimeFactory {
class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter);
+ LifetimeSafetyReporter *Reporter,
+ uint32_t BlockFactNumThreshold);
void run();
@@ -79,6 +81,7 @@ class LifetimeSafetyAnalysis {
FactManager &getFactManager() { return FactMgr; }
private:
+ uint32_t BlockFactNumThreshold;
AnalysisDeclContext &AC;
LifetimeSafetyReporter *Reporter;
LifetimeFactory Factory;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..9b6e36f0ace3a 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -501,6 +501,9 @@ LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety
LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
+LANGOPT(BlockFactNumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++")
+
+
#undef LANGOPT
#undef ENUM_LANGOPT
#undef VALUE_LANGOPT
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 756d6deed7130..7d227b3d5e194 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5166,6 +5166,10 @@ def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">,
Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Set Fuchsia API level">,
MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
+def fblock_size_threshold : Joined<["-"], "fblock-size-threshold=">,
+ Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set Threshold for block size above which lifetime analysis will be skipped">,
+ MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>;
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
Visibility<[ClangOption, CC1Option, FlangOption]>,
Group<m_Group>, HelpText<"Set macOS deployment target">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 1f7c282dadac2..ec5377bf8168e 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -58,13 +58,20 @@ class LifetimeChecker {
public:
LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
- AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
+ AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, uint32_t BlockFactNumThreshold)
: LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
Reporter(Reporter) {
- for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
+ if (BlockFactNumThreshold <= 0) {
+ llvm::errs() << "Warning: BlockFactNumThreshold should be positive.\n";
+ }
+ for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) {
+ const auto& BlockFacts = FactMgr.getFacts(B);
+ if (BlockFactNumThreshold > 0 && BlockFacts.size() > BlockFactNumThreshold)
+ continue;
for (const Fact *F : FactMgr.getFacts(B))
if (const auto *EF = F->getAs<ExpireFact>())
checkExpiry(EF);
+ }
issuePendingWarnings();
}
@@ -138,9 +145,10 @@ class LifetimeChecker {
void runLifetimeChecker(const LoanPropagationAnalysis &LP,
const LiveOriginsAnalysis &LO,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetyReporter *Reporter) {
+ LifetimeSafetyReporter *Reporter,
+ uint32_t BlockFactNumThreshold) {
llvm::TimeTraceScope TimeProfile("LifetimeChecker");
- LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter);
+ LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter, BlockFactNumThreshold);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 0ae7111c489e8..845c7f18df608 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -95,6 +95,27 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const {
}
}
+void FactManager::dumpBlockSizes(const CFG &Cfg,
+ AnalysisDeclContext &AC) const {
+ llvm::dbgs() << "==========================================\n";
+ llvm::dbgs() << " Lifetime Analysis CFG Block Sizes:\n";
+ llvm::dbgs() << "==========================================\n";
+ if (const Decl *D = AC.getDecl())
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n";
+ // Print blocks in the order as they appear in code for a stable ordering.
+ for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) {
+ if (getFacts(B).size() > BlockFactNumThreshold)
+ continue;
+ if (B->getLabel()) {
+ llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName();
+ } else {
+ llvm::dbgs() << " Block B" << B->getBlockID();
+ }
+ llvm::dbgs() << ": Number of facts = " << getFacts(B).size() << "\n";
+ }
+}
+
llvm::ArrayRef<const Fact *>
FactManager::getBlockContaining(ProgramPoint P) const {
for (const auto &BlockToFactsVec : BlockToFacts) {
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index a51ba4280f284..d057e9fa08c73 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -32,8 +32,11 @@ namespace clang::lifetimes {
namespace internal {
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter)
- : AC(AC), Reporter(Reporter) {}
+ LifetimeSafetyReporter *Reporter,
+ uint32_t BlockFactNumThreshold)
+ : BlockFactNumThreshold(BlockFactNumThreshold), AC(AC), Reporter(Reporter) {
+ FactMgr.setBlockFactNumThreshold(BlockFactNumThreshold);
+ }
void LifetimeSafetyAnalysis::run() {
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
@@ -46,6 +49,7 @@ void LifetimeSafetyAnalysis::run() {
FactsGenerator FactGen(FactMgr, AC);
FactGen.run();
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC));
+ DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC));
/// TODO(opt): Consider optimizing individual blocks before running the
/// dataflow analysis.
@@ -66,13 +70,14 @@ void LifetimeSafetyAnalysis::run() {
DEBUG_WITH_TYPE("LiveOrigins",
LiveOrigins->dump(llvm::dbgs(), FactMgr.getTestPoints()));
- runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter);
+ runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter, BlockFactNumThreshold);
}
} // namespace internal
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter) {
- internal::LifetimeSafetyAnalysis Analysis(AC, Reporter);
+ LifetimeSafetyReporter *Reporter,
+ uint32_t BlockFactNumThreshold) {
+ internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, BlockFactNumThreshold);
Analysis.run();
}
} // namespace clang::lifetimes
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 43d2b9a829545..b379279115784 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -3107,7 +3107,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
if (AC.getCFG()) {
lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
- lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter);
+ lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold);
}
}
// Check for violations of "called once" parameter properties.
>From 1f989f9103e73c439d3c63e1e74d7797a7339a0b Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Wed, 3 Dec 2025 09:13:39 +0000
Subject: [PATCH 02/13] Formatting changes
---
.../Analysis/Analyses/LifetimeSafety/Checker.h | 2 +-
.../clang/Analysis/Analyses/LifetimeSafety/Facts.h | 3 ++-
.../Analyses/LifetimeSafety/LifetimeSafety.h | 4 ++--
clang/include/clang/Options/Options.td | 11 +++++++----
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 13 ++++++++-----
.../lib/Analysis/LifetimeSafety/LifetimeSafety.cpp | 12 +++++++-----
clang/lib/Sema/AnalysisBasedWarnings.cpp | 3 ++-
7 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
index c609543575e0f..be10f298ab2ff 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
@@ -29,7 +29,7 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold);
+ uint32_t BlockFactNumThreshold);
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 5e7e93118bf10..c6680d234ddba 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -218,7 +218,8 @@ class FactManager {
void dump(const CFG &Cfg, AnalysisDeclContext &AC) const;
- // A utility function to print the size of the CFG blocks in the analysis context.
+ // A utility function to print the size of the CFG blocks in the analysis
+ // context.
void dumpBlockSizes(const CFG &Cfg, AnalysisDeclContext &AC) const;
/// Retrieves program points that were specially marked in the source code
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 29078756b3e15..95b0ed71af3e0 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -52,7 +52,7 @@ class LifetimeSafetyReporter {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold);
+ uint32_t BlockFactNumThreshold);
namespace internal {
/// An object to hold the factories for immutable collections, ensuring
@@ -69,7 +69,7 @@ class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold);
+ uint32_t BlockFactNumThreshold);
void run();
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 7d227b3d5e194..dd367e4555228 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5166,10 +5166,13 @@ def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">,
Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Set Fuchsia API level">,
MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
-def fblock_size_threshold : Joined<["-"], "fblock-size-threshold=">,
- Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
- HelpText<"Set Threshold for block size above which lifetime analysis will be skipped">,
- MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>;
+def fblock_size_threshold
+ : Joined<["-"], "fblock-size-threshold=">,
+ Group<m_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set Threshold for block size above which lifetime analysis "
+ "will be skipped">,
+ MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>;
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
Visibility<[ClangOption, CC1Option, FlangOption]>,
Group<m_Group>, HelpText<"Set macOS deployment target">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index ec5377bf8168e..89415d1f0bf02 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -58,15 +58,17 @@ class LifetimeChecker {
public:
LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
- AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter, uint32_t BlockFactNumThreshold)
+ AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter,
+ uint32_t BlockFactNumThreshold)
: LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
Reporter(Reporter) {
if (BlockFactNumThreshold <= 0) {
llvm::errs() << "Warning: BlockFactNumThreshold should be positive.\n";
}
for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) {
- const auto& BlockFacts = FactMgr.getFacts(B);
- if (BlockFactNumThreshold > 0 && BlockFacts.size() > BlockFactNumThreshold)
+ const auto &BlockFacts = FactMgr.getFacts(B);
+ if (BlockFactNumThreshold > 0 &&
+ BlockFacts.size() > BlockFactNumThreshold)
continue;
for (const Fact *F : FactMgr.getFacts(B))
if (const auto *EF = F->getAs<ExpireFact>())
@@ -146,9 +148,10 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LP,
const LiveOriginsAnalysis &LO,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold) {
+ uint32_t BlockFactNumThreshold) {
llvm::TimeTraceScope TimeProfile("LifetimeChecker");
- LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter, BlockFactNumThreshold);
+ LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter,
+ BlockFactNumThreshold);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index d057e9fa08c73..36f48ae83dfc8 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -33,10 +33,10 @@ namespace internal {
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold)
+ uint32_t BlockFactNumThreshold)
: BlockFactNumThreshold(BlockFactNumThreshold), AC(AC), Reporter(Reporter) {
FactMgr.setBlockFactNumThreshold(BlockFactNumThreshold);
- }
+}
void LifetimeSafetyAnalysis::run() {
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
@@ -70,14 +70,16 @@ void LifetimeSafetyAnalysis::run() {
DEBUG_WITH_TYPE("LiveOrigins",
LiveOrigins->dump(llvm::dbgs(), FactMgr.getTestPoints()));
- runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter, BlockFactNumThreshold);
+ runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter,
+ BlockFactNumThreshold);
}
} // namespace internal
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold) {
- internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, BlockFactNumThreshold);
+ uint32_t BlockFactNumThreshold) {
+ internal::LifetimeSafetyAnalysis Analysis(AC, Reporter,
+ BlockFactNumThreshold);
Analysis.run();
}
} // namespace clang::lifetimes
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index b379279115784..c32e3c007e13c 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -3107,7 +3107,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
if (AC.getCFG()) {
lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
- lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold);
+ lifetimes::runLifetimeSafetyAnalysis(
+ AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold);
}
}
// Check for violations of "called once" parameter properties.
>From 8294f3f7b95a01f230aa754af7c6703c4cb36177 Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Wed, 3 Dec 2025 09:28:23 +0000
Subject: [PATCH 03/13] Correcting the implementation of block size printing
function
---
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 3 ---
clang/lib/Analysis/LifetimeSafety/Facts.cpp | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 89415d1f0bf02..6622600b1ec30 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -62,9 +62,6 @@ class LifetimeChecker {
uint32_t BlockFactNumThreshold)
: LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
Reporter(Reporter) {
- if (BlockFactNumThreshold <= 0) {
- llvm::errs() << "Warning: BlockFactNumThreshold should be positive.\n";
- }
for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) {
const auto &BlockFacts = FactMgr.getFacts(B);
if (BlockFactNumThreshold > 0 &&
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 845c7f18df608..98f6de28154d2 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -105,7 +105,7 @@ void FactManager::dumpBlockSizes(const CFG &Cfg,
llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n";
// Print blocks in the order as they appear in code for a stable ordering.
for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) {
- if (getFacts(B).size() > BlockFactNumThreshold)
+ if (BlockFactNumThreshold > 0 && getFacts(B).size() > BlockFactNumThreshold)
continue;
if (B->getLabel()) {
llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName();
>From 5f0dff2dbf1d4345dab8121406f99e58d250b20c Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Mon, 8 Dec 2025 04:06:29 +0000
Subject: [PATCH 04/13] Adding two flags for origin count based and block count
based bail-out
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 12 ++++--
clang/include/clang/Basic/LangOptions.def | 2 +-
clang/include/clang/Options/Options.td | 17 +++++---
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 13 ++----
.../LifetimeSafety/LifetimeSafety.cpp | 42 +++++++++++++++----
clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +-
.../unittests/Analysis/LifetimeSafetyTest.cpp | 2 +-
7 files changed, 62 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 95b0ed71af3e0..6b5b71686a758 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -24,6 +24,7 @@
#include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
#include "clang/Analysis/AnalysisDeclContext.h"
+#include <cstdint>
namespace clang::lifetimes {
@@ -52,7 +53,8 @@ class LifetimeSafetyReporter {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold);
+ uint32_t CfgBlocknumThreshold,
+ uint32_t CfgOriginCountThreshold);
namespace internal {
/// An object to hold the factories for immutable collections, ensuring
@@ -69,7 +71,8 @@ class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold);
+ uint32_t CfgBlocknumThreshold,
+ uint32_t CfgOriginCountThreshold);
void run();
@@ -81,7 +84,10 @@ class LifetimeSafetyAnalysis {
FactManager &getFactManager() { return FactMgr; }
private:
- uint32_t BlockFactNumThreshold;
+ bool shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const;
+ bool shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const;
+ uint32_t CfgBlocknumThreshold;
+ uint32_t CfgOriginCountThreshold;
AnalysisDeclContext &AC;
LifetimeSafetyReporter *Reporter;
LifetimeFactory Factory;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 9b6e36f0ace3a..05830caea2830 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -501,7 +501,7 @@ LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety
LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
-LANGOPT(BlockFactNumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++")
+LANGOPT(CfgBlocknumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++")
#undef LANGOPT
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index dd367e4555228..abe984b440e77 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5166,13 +5166,20 @@ def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">,
Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Set Fuchsia API level">,
MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
-def fblock_size_threshold
- : Joined<["-"], "fblock-size-threshold=">,
+def fcfg_block_num_threshold
+ : Joined<["-"], "fcfg-block-num-threshold=">,
Group<m_Group>,
Visibility<[ClangOption, CC1Option]>,
- HelpText<"Set Threshold for block size above which lifetime analysis "
- "will be skipped">,
- MarshallingInfoInt<LangOpts<"BlockFactNumThreshold">>;
+ HelpText<"Set Threshold for number of blocks above which lifetime analysis "
+ "will be skipped for a CFG">,
+ MarshallingInfoInt<LangOpts<"CfgBlocknumThreshold">>;
+def fcfg_origin_count_threshold
+ : Joined<["-"], "fcfg-origin-count-threshold=">,
+ Group<m_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set Threshold for number of origins after fact generation after which lifetime analysis "
+ "will be skipped for a CFG">,
+ MarshallingInfoInt<LangOpts<"CfgOriginCountThreshold">>;
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
Visibility<[ClangOption, CC1Option, FlangOption]>,
Group<m_Group>, HelpText<"Set macOS deployment target">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 6622600b1ec30..0ced00f5fadda 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -58,15 +58,10 @@ class LifetimeChecker {
public:
LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
- AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold)
+ AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
: LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
Reporter(Reporter) {
for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) {
- const auto &BlockFacts = FactMgr.getFacts(B);
- if (BlockFactNumThreshold > 0 &&
- BlockFacts.size() > BlockFactNumThreshold)
- continue;
for (const Fact *F : FactMgr.getFacts(B))
if (const auto *EF = F->getAs<ExpireFact>())
checkExpiry(EF);
@@ -144,11 +139,9 @@ class LifetimeChecker {
void runLifetimeChecker(const LoanPropagationAnalysis &LP,
const LiveOriginsAnalysis &LO,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold) {
+ LifetimeSafetyReporter *Reporter) {
llvm::TimeTraceScope TimeProfile("LifetimeChecker");
- LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter,
- BlockFactNumThreshold);
+ LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 36f48ae83dfc8..0865d54261ce7 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -33,21 +33,48 @@ namespace internal {
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold)
- : BlockFactNumThreshold(BlockFactNumThreshold), AC(AC), Reporter(Reporter) {
- FactMgr.setBlockFactNumThreshold(BlockFactNumThreshold);
+ uint32_t CfgBlocknumThreshold,
+ uint32_t CfgOriginCountThreshold)
+ : CfgBlocknumThreshold(CfgBlocknumThreshold), CfgOriginCountThreshold(CfgOriginCountThreshold), AC(AC), Reporter(Reporter) {
+ FactMgr.setBlockFactNumThreshold(CfgBlocknumThreshold);
+}
+
+bool LifetimeSafetyAnalysis::shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const {
+ if (Cfg.getNumBlockIDs() > CfgBlocknumThreshold) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Lifetime Safety Analysis aborted: CFG too large before fact generation ("
+ << Cfg.getNumBlockIDs() << " blocks).\n");
+ return true;
+ }
+ return false;
+}
+
+bool LifetimeSafetyAnalysis::shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const {
+ if (FactMgr.getOriginMgr().getNumOrigins() > CfgOriginCountThreshold) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Lifetime Safety Analysis aborted: Too many origins after fact generation ("
+ << FactMgr.getOriginMgr().getNumOrigins() << " origins).\n");
+ return true;
+ }
+ return false;
}
void LifetimeSafetyAnalysis::run() {
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
const CFG &Cfg = *AC.getCFG();
+ if (shouldBailOutCFGPreFactGeneration(Cfg)) {
+ return;
+ }
DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
/*ShowColors=*/true));
FactMgr.init(Cfg);
FactsGenerator FactGen(FactMgr, AC);
FactGen.run();
+ if (shouldBailOutCFGPostFactGeneration(Cfg)) {
+ return;
+ }
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC));
DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC));
@@ -70,16 +97,17 @@ void LifetimeSafetyAnalysis::run() {
DEBUG_WITH_TYPE("LiveOrigins",
LiveOrigins->dump(llvm::dbgs(), FactMgr.getTestPoints()));
- runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter,
- BlockFactNumThreshold);
+ runLifetimeChecker(*LoanPropagation, *LiveOrigins, FactMgr, AC, Reporter);
}
} // namespace internal
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold) {
+ uint32_t CfgBlocknumThreshold,
+ uint32_t CfgOriginCountThreshold) {
internal::LifetimeSafetyAnalysis Analysis(AC, Reporter,
- BlockFactNumThreshold);
+ CfgBlocknumThreshold,
+ CfgOriginCountThreshold);
Analysis.run();
}
} // namespace clang::lifetimes
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index c32e3c007e13c..ba396191bfa5f 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -3108,7 +3108,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (AC.getCFG()) {
lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
lifetimes::runLifetimeSafetyAnalysis(
- AC, &LifetimeSafetyReporter, S.getLangOpts().BlockFactNumThreshold);
+ AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold, S.getLangOpts().CfgOriginCountThreshold);
}
}
// Check for violations of "called once" parameter properties.
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index a895475013c98..157b77841f533 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -62,7 +62,7 @@ class LifetimeTestRunner {
BuildOptions.AddLifetime = true;
// Run the main analysis.
- Analysis = std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr);
+ Analysis = std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, 0, 0);
Analysis->run();
AnnotationToPointMap = Analysis->getFactManager().getTestPoints();
>From 58db8bfca9fe6c8371b143d90f397be247e129a4 Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Thu, 11 Dec 2025 07:14:43 +0000
Subject: [PATCH 05/13] Adding block number based bailout logic
---
.../Analyses/LifetimeSafety/Checker.h | 3 +-
.../Analysis/Analyses/LifetimeSafety/Facts.h | 6 +--
.../Analyses/LifetimeSafety/LifetimeSafety.h | 10 ++---
clang/include/clang/Options/Options.td | 12 ++----
clang/lib/Analysis/LifetimeSafety/Facts.cpp | 15 +++++---
.../LifetimeSafety/LifetimeSafety.cpp | 38 +++++++------------
clang/lib/Sema/AnalysisBasedWarnings.cpp | 2 +-
.../unittests/Analysis/LifetimeSafetyTest.cpp | 3 +-
8 files changed, 35 insertions(+), 54 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
index be10f298ab2ff..03636be7d00c3 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
@@ -28,8 +28,7 @@ namespace clang::lifetimes::internal {
void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const LiveOriginsAnalysis &LiveOrigins,
const FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetyReporter *Reporter,
- uint32_t BlockFactNumThreshold);
+ LifetimeSafetyReporter *Reporter);
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index c6680d234ddba..b10b0a95a82fa 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -242,8 +242,8 @@ class FactManager {
const LoanManager &getLoanMgr() const { return LoanMgr; }
OriginManager &getOriginMgr() { return OriginMgr; }
const OriginManager &getOriginMgr() const { return OriginMgr; }
- void setBlockFactNumThreshold(uint32_t Threshold) {
- BlockFactNumThreshold = Threshold;
+ void setBlockNumThreshold(uint32_t Threshold) {
+ BlockNumThreshold = Threshold;
}
private:
@@ -253,7 +253,7 @@ class FactManager {
/// Facts for each CFG block, indexed by block ID.
llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts;
llvm::BumpPtrAllocator FactAllocator;
- uint32_t BlockFactNumThreshold = 0;
+ uint32_t BlockNumThreshold = 0;
};
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 6b5b71686a758..e32e91befca8f 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -53,8 +53,7 @@ class LifetimeSafetyReporter {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold,
- uint32_t CfgOriginCountThreshold);
+ uint32_t CfgBlocknumThreshold);
namespace internal {
/// An object to hold the factories for immutable collections, ensuring
@@ -71,8 +70,7 @@ class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold,
- uint32_t CfgOriginCountThreshold);
+ uint32_t CfgBlocknumThreshold);
void run();
@@ -84,10 +82,8 @@ class LifetimeSafetyAnalysis {
FactManager &getFactManager() { return FactMgr; }
private:
- bool shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const;
- bool shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const;
+ bool shouldBailOutCFGPreFactGeneration(const CFG &Cfg) const;
uint32_t CfgBlocknumThreshold;
- uint32_t CfgOriginCountThreshold;
AnalysisDeclContext &AC;
LifetimeSafetyReporter *Reporter;
LifetimeFactory Factory;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index abe984b440e77..975d7bf0341a9 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5170,16 +5170,10 @@ def fcfg_block_num_threshold
: Joined<["-"], "fcfg-block-num-threshold=">,
Group<m_Group>,
Visibility<[ClangOption, CC1Option]>,
- HelpText<"Set Threshold for number of blocks above which lifetime analysis "
- "will be skipped for a CFG">,
+ HelpText<
+ "Set Threshold for number of blocks above which lifetime analysis "
+ "will be skipped for a CFG">,
MarshallingInfoInt<LangOpts<"CfgBlocknumThreshold">>;
-def fcfg_origin_count_threshold
- : Joined<["-"], "fcfg-origin-count-threshold=">,
- Group<m_Group>,
- Visibility<[ClangOption, CC1Option]>,
- HelpText<"Set Threshold for number of origins after fact generation after which lifetime analysis "
- "will be skipped for a CFG">,
- MarshallingInfoInt<LangOpts<"CfgOriginCountThreshold">>;
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
Visibility<[ClangOption, CC1Option, FlangOption]>,
Group<m_Group>, HelpText<"Set macOS deployment target">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 98f6de28154d2..9cdde1b4d77d9 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -103,16 +103,19 @@ void FactManager::dumpBlockSizes(const CFG &Cfg,
if (const Decl *D = AC.getDecl())
if (const auto *ND = dyn_cast<NamedDecl>(D))
llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n";
+ llvm::dbgs() << "Number of CFG Blocks: " << Cfg.getNumBlockIDs() << "\n";
+ if (BlockNumThreshold > 0 && Cfg.getNumBlockIDs() > BlockNumThreshold) {
+ llvm::dbgs() << "CFG Block Number Threshold: " << BlockNumThreshold << "\n";
+ llvm::dbgs() << "Bailed out before generating facts.\n";
+ return;
+ }
// Print blocks in the order as they appear in code for a stable ordering.
for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) {
- if (BlockFactNumThreshold > 0 && getFacts(B).size() > BlockFactNumThreshold)
- continue;
- if (B->getLabel()) {
+ if (B->getLabel())
llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName();
- } else {
+ else
llvm::dbgs() << " Block B" << B->getBlockID();
- }
- llvm::dbgs() << ": Number of facts = " << getFacts(B).size() << "\n";
+ llvm::dbgs() << ": Number of elements = " << B->size() << "\n";
}
}
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 0865d54261ce7..af3b3cc87f872 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -28,32 +28,26 @@
#include "llvm/Support/TimeProfiler.h"
#include <memory>
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "lifetime-safety"
+
namespace clang::lifetimes {
namespace internal {
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold,
- uint32_t CfgOriginCountThreshold)
- : CfgBlocknumThreshold(CfgBlocknumThreshold), CfgOriginCountThreshold(CfgOriginCountThreshold), AC(AC), Reporter(Reporter) {
- FactMgr.setBlockFactNumThreshold(CfgBlocknumThreshold);
+ uint32_t CfgBlocknumThreshold)
+ : CfgBlocknumThreshold(CfgBlocknumThreshold), AC(AC), Reporter(Reporter) {
+ FactMgr.setBlockNumThreshold(CfgBlocknumThreshold);
}
bool LifetimeSafetyAnalysis::shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const {
- if (Cfg.getNumBlockIDs() > CfgBlocknumThreshold) {
+ if ((CfgBlocknumThreshold > 0) &&
+ (Cfg.getNumBlockIDs() > CfgBlocknumThreshold)) {
LLVM_DEBUG(llvm::dbgs()
- << "Lifetime Safety Analysis aborted: CFG too large before fact generation ("
- << Cfg.getNumBlockIDs() << " blocks).\n");
- return true;
- }
- return false;
-}
-
-bool LifetimeSafetyAnalysis::shouldBailOutCFGPostFactGeneration(const CFG& Cfg) const {
- if (FactMgr.getOriginMgr().getNumOrigins() > CfgOriginCountThreshold) {
- LLVM_DEBUG(llvm::dbgs()
- << "Lifetime Safety Analysis aborted: Too many origins after fact generation ("
- << FactMgr.getOriginMgr().getNumOrigins() << " origins).\n");
+ << "Aborting Lifetime Safety analysis for current CFG as it has "
+ "blocks exceeding the thresold. Number of blocks: "
+ << Cfg.getNumBlockIDs() << "\n");
return true;
}
return false;
@@ -72,9 +66,6 @@ void LifetimeSafetyAnalysis::run() {
FactsGenerator FactGen(FactMgr, AC);
FactGen.run();
- if (shouldBailOutCFGPostFactGeneration(Cfg)) {
- return;
- }
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC));
DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC));
@@ -103,11 +94,8 @@ void LifetimeSafetyAnalysis::run() {
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold,
- uint32_t CfgOriginCountThreshold) {
- internal::LifetimeSafetyAnalysis Analysis(AC, Reporter,
- CfgBlocknumThreshold,
- CfgOriginCountThreshold);
+ uint32_t CfgBlocknumThreshold) {
+ internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, CfgBlocknumThreshold);
Analysis.run();
}
} // namespace clang::lifetimes
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index ba396191bfa5f..00d8e52bcbbea 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -3108,7 +3108,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (AC.getCFG()) {
lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
lifetimes::runLifetimeSafetyAnalysis(
- AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold, S.getLangOpts().CfgOriginCountThreshold);
+ AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold);
}
}
// Check for violations of "called once" parameter properties.
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index 157b77841f533..1f27df26d30f6 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -62,7 +62,8 @@ class LifetimeTestRunner {
BuildOptions.AddLifetime = true;
// Run the main analysis.
- Analysis = std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, 0, 0);
+ Analysis =
+ std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, 0);
Analysis->run();
AnnotationToPointMap = Analysis->getFactManager().getTestPoints();
>From 3cb5ad3c341f2fa65bb74e50becb5d7e04b074c8 Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Fri, 12 Dec 2025 09:11:33 +0000
Subject: [PATCH 06/13] Changing the flag name and removing unused dumpCFGStats
function
---
.../Analysis/Analyses/LifetimeSafety/Facts.h | 10 +----
.../Analyses/LifetimeSafety/LifetimeSafety.h | 9 ++---
clang/include/clang/Basic/LangOptions.def | 5 +--
clang/include/clang/Options/Options.td | 23 ++++++-----
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 3 +-
clang/lib/Analysis/LifetimeSafety/Facts.cpp | 24 -----------
.../LifetimeSafety/LifetimeSafety.cpp | 40 ++++++++-----------
clang/lib/Sema/AnalysisBasedWarnings.cpp | 3 +-
8 files changed, 38 insertions(+), 79 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index b10b0a95a82fa..82e14832208b3 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -218,10 +218,6 @@ class FactManager {
void dump(const CFG &Cfg, AnalysisDeclContext &AC) const;
- // A utility function to print the size of the CFG blocks in the analysis
- // context.
- void dumpBlockSizes(const CFG &Cfg, AnalysisDeclContext &AC) const;
-
/// Retrieves program points that were specially marked in the source code
/// for testing.
///
@@ -242,9 +238,7 @@ class FactManager {
const LoanManager &getLoanMgr() const { return LoanMgr; }
OriginManager &getOriginMgr() { return OriginMgr; }
const OriginManager &getOriginMgr() const { return OriginMgr; }
- void setBlockNumThreshold(uint32_t Threshold) {
- BlockNumThreshold = Threshold;
- }
+ void setMaxCFGBlocksThreshold(size_t Threshold) { MaxCFGBlocks = Threshold; }
private:
FactID NextFactID{0};
@@ -253,7 +247,7 @@ class FactManager {
/// Facts for each CFG block, indexed by block ID.
llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts;
llvm::BumpPtrAllocator FactAllocator;
- uint32_t BlockNumThreshold = 0;
+ size_t MaxCFGBlocks = 0;
};
} // namespace clang::lifetimes::internal
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index e32e91befca8f..0173c872cbee6 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -52,8 +52,7 @@ class LifetimeSafetyReporter {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold);
+ LifetimeSafetyReporter *Reporter);
namespace internal {
/// An object to hold the factories for immutable collections, ensuring
@@ -69,8 +68,7 @@ struct LifetimeFactory {
class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold);
+ LifetimeSafetyReporter *Reporter, size_t MaxCFGBlocks);
void run();
@@ -82,8 +80,7 @@ class LifetimeSafetyAnalysis {
FactManager &getFactManager() { return FactMgr; }
private:
- bool shouldBailOutCFGPreFactGeneration(const CFG &Cfg) const;
- uint32_t CfgBlocknumThreshold;
+ size_t MaxCFGBlocks;
AnalysisDeclContext &AC;
LifetimeSafetyReporter *Reporter;
LifetimeFactory Factory;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 05830caea2830..d8de6e3e8826c 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -499,10 +499,9 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C")
LANGOPT(EnableLifetimeSafety, 1, 0, NotCompatible, "Experimental lifetime safety analysis for C++")
-LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
-
-LANGOPT(CfgBlocknumThreshold, 32, 0, NotCompatible, "Experimental CFG bailout size threshold for C++")
+LANGOPT(LifetimeSafetyMaxCFGBlocks, 32, 0, NotCompatible, "Skip LifetimeSafety analysis for functions with CFG block count exceeding this threshold. Specify 0 for no limit")
+LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
#undef LANGOPT
#undef ENUM_LANGOPT
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 975d7bf0341a9..c208179925b87 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -1955,6 +1955,14 @@ defm lifetime_safety : BoolFOption<
BothFlags<[], [CC1Option],
" experimental lifetime safety for C++">>;
+def fexperimental_lifetime_safety_max_cfg_blocks
+ : Joined<["-"], "fexperimental-lifetime-safety-max-cfg-blocks=">,
+ Group<m_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Skip LifetimeSafety analysis for functions with CFG block "
+ "count exceeding this threshold. Specify 0 for no limit.">,
+ MarshallingInfoInt<LangOpts<"LifetimeSafetyMaxCFGBlocks">>;
+
defm addrsig : BoolFOption<"addrsig",
CodeGenOpts<"Addrsig">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption, CC1Option], "Emit">,
@@ -5163,17 +5171,10 @@ def mmlir : Separate<["-"], "mmlir">,
HelpText<"Additional arguments to forward to MLIR's option processing">,
MarshallingInfoStringVector<FrontendOpts<"MLIRArgs">>;
def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">,
- Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
- HelpText<"Set Fuchsia API level">,
- MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
-def fcfg_block_num_threshold
- : Joined<["-"], "fcfg-block-num-threshold=">,
- Group<m_Group>,
- Visibility<[ClangOption, CC1Option]>,
- HelpText<
- "Set Threshold for number of blocks above which lifetime analysis "
- "will be skipped for a CFG">,
- MarshallingInfoInt<LangOpts<"CfgBlocknumThreshold">>;
+ Group<m_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set Fuchsia API level">,
+ MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
Visibility<[ClangOption, CC1Option, FlangOption]>,
Group<m_Group>, HelpText<"Set macOS deployment target">;
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index 0ced00f5fadda..1f7c282dadac2 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -61,11 +61,10 @@ class LifetimeChecker {
AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
: LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
Reporter(Reporter) {
- for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>()) {
+ for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
for (const Fact *F : FactMgr.getFacts(B))
if (const auto *EF = F->getAs<ExpireFact>())
checkExpiry(EF);
- }
issuePendingWarnings();
}
diff --git a/clang/lib/Analysis/LifetimeSafety/Facts.cpp b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
index 9cdde1b4d77d9..0ae7111c489e8 100644
--- a/clang/lib/Analysis/LifetimeSafety/Facts.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Facts.cpp
@@ -95,30 +95,6 @@ void FactManager::dump(const CFG &Cfg, AnalysisDeclContext &AC) const {
}
}
-void FactManager::dumpBlockSizes(const CFG &Cfg,
- AnalysisDeclContext &AC) const {
- llvm::dbgs() << "==========================================\n";
- llvm::dbgs() << " Lifetime Analysis CFG Block Sizes:\n";
- llvm::dbgs() << "==========================================\n";
- if (const Decl *D = AC.getDecl())
- if (const auto *ND = dyn_cast<NamedDecl>(D))
- llvm::dbgs() << "Function: " << ND->getQualifiedNameAsString() << "\n";
- llvm::dbgs() << "Number of CFG Blocks: " << Cfg.getNumBlockIDs() << "\n";
- if (BlockNumThreshold > 0 && Cfg.getNumBlockIDs() > BlockNumThreshold) {
- llvm::dbgs() << "CFG Block Number Threshold: " << BlockNumThreshold << "\n";
- llvm::dbgs() << "Bailed out before generating facts.\n";
- return;
- }
- // Print blocks in the order as they appear in code for a stable ordering.
- for (const CFGBlock *B : *AC.getAnalysis<PostOrderCFGView>()) {
- if (B->getLabel())
- llvm::dbgs() << " Block: " << B->getLabel()->getStmtClassName();
- else
- llvm::dbgs() << " Block B" << B->getBlockID();
- llvm::dbgs() << ": Number of elements = " << B->size() << "\n";
- }
-}
-
llvm::ArrayRef<const Fact *>
FactManager::getBlockContaining(ProgramPoint P) const {
for (const auto &BlockToFactsVec : BlockToFacts) {
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index af3b3cc87f872..b74b2feb3174b 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -28,36 +28,30 @@
#include "llvm/Support/TimeProfiler.h"
#include <memory>
-#undef DEBUG_TYPE
-#define DEBUG_TYPE "lifetime-safety"
-
namespace clang::lifetimes {
namespace internal {
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold)
- : CfgBlocknumThreshold(CfgBlocknumThreshold), AC(AC), Reporter(Reporter) {
- FactMgr.setBlockNumThreshold(CfgBlocknumThreshold);
-}
-
-bool LifetimeSafetyAnalysis::shouldBailOutCFGPreFactGeneration(const CFG& Cfg) const {
- if ((CfgBlocknumThreshold > 0) &&
- (Cfg.getNumBlockIDs() > CfgBlocknumThreshold)) {
- LLVM_DEBUG(llvm::dbgs()
- << "Aborting Lifetime Safety analysis for current CFG as it has "
- "blocks exceeding the thresold. Number of blocks: "
- << Cfg.getNumBlockIDs() << "\n");
- return true;
- }
- return false;
+ size_t MaxCFGBlocks)
+ : MaxCFGBlocks(MaxCFGBlocks), AC(AC), Reporter(Reporter) {
+ FactMgr.setMaxCFGBlocksThreshold(MaxCFGBlocks);
}
void LifetimeSafetyAnalysis::run() {
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
const CFG &Cfg = *AC.getCFG();
- if (shouldBailOutCFGPreFactGeneration(Cfg)) {
+ if (MaxCFGBlocks > 0 && Cfg.getNumBlockIDs() > MaxCFGBlocks) {
+ std::string FuncName = "<unknown>";
+ if (const Decl *D = AC.getDecl())
+ if (const auto *ND = dyn_cast<NamedDecl>(D))
+ FuncName = ND->getQualifiedNameAsString();
+ DEBUG_WITH_TYPE("LifetimeSafety",
+ llvm::dbgs()
+ << "LifetimeSafety: Skipping function " << FuncName
+ << "due to large CFG: <count> blocks (threshold: "
+ << MaxCFGBlocks << ")\n");
return;
}
DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
@@ -67,7 +61,6 @@ void LifetimeSafetyAnalysis::run() {
FactsGenerator FactGen(FactMgr, AC);
FactGen.run();
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr.dump(Cfg, AC));
- DEBUG_WITH_TYPE("LifetimeCFGSizes", FactMgr.dumpBlockSizes(Cfg, AC));
/// TODO(opt): Consider optimizing individual blocks before running the
/// dataflow analysis.
@@ -93,9 +86,10 @@ void LifetimeSafetyAnalysis::run() {
} // namespace internal
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter,
- uint32_t CfgBlocknumThreshold) {
- internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, CfgBlocknumThreshold);
+ LifetimeSafetyReporter *Reporter) {
+ internal::LifetimeSafetyAnalysis Analysis(
+ AC, Reporter,
+ AC.getASTContext().getLangOpts().LifetimeSafetyMaxCFGBlocks);
Analysis.run();
}
} // namespace clang::lifetimes
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 00d8e52bcbbea..43d2b9a829545 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -3107,8 +3107,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
if (AC.getCFG()) {
lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
- lifetimes::runLifetimeSafetyAnalysis(
- AC, &LifetimeSafetyReporter, S.getLangOpts().CfgBlocknumThreshold);
+ lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter);
}
}
// Check for violations of "called once" parameter properties.
>From c1d711228db59ab3ff065ad8eb404f5dd1006cbf Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Mon, 15 Dec 2025 09:26:34 +0000
Subject: [PATCH 07/13] Adding LifetimeSafetyOpts struct to track different
options for bailout
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 11 +++++--
clang/include/clang/Options/Options.td | 7 ++--
.../LifetimeSafety/LifetimeSafety.cpp | 32 +++++++++----------
.../unittests/Analysis/LifetimeSafetyTest.cpp | 4 ++-
4 files changed, 30 insertions(+), 24 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 0173c872cbee6..f07867f311990 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -35,6 +35,12 @@ enum class Confidence : uint8_t {
Definite // Reported as a definite error (-Wlifetime-safety-permissive)
};
+struct LifetimeSafetyOpts {
+ /// Maximum number of CFG blocks to analyze. Functions with larger CFGs will
+ /// be skipped.
+ size_t MaxCFGBlocks;
+};
+
class LifetimeSafetyReporter {
public:
LifetimeSafetyReporter() = default;
@@ -68,7 +74,8 @@ struct LifetimeFactory {
class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
- LifetimeSafetyReporter *Reporter, size_t MaxCFGBlocks);
+ LifetimeSafetyReporter *Reporter,
+ const LifetimeSafetyOpts &LSOpts);
void run();
@@ -80,7 +87,7 @@ class LifetimeSafetyAnalysis {
FactManager &getFactManager() { return FactMgr; }
private:
- size_t MaxCFGBlocks;
+ const LifetimeSafetyOpts &LSOpts;
AnalysisDeclContext &AC;
LifetimeSafetyReporter *Reporter;
LifetimeFactory Factory;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index c208179925b87..e7b1ba2cf9ac8 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5171,10 +5171,9 @@ def mmlir : Separate<["-"], "mmlir">,
HelpText<"Additional arguments to forward to MLIR's option processing">,
MarshallingInfoStringVector<FrontendOpts<"MLIRArgs">>;
def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">,
- Group<m_Group>,
- Visibility<[ClangOption, CC1Option]>,
- HelpText<"Set Fuchsia API level">,
- MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
+ Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set Fuchsia API level">,
+ MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
Visibility<[ClangOption, CC1Option, FlangOption]>,
Group<m_Group>, HelpText<"Set macOS deployment target">;
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index b74b2feb3174b..1c662cd87f607 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -33,25 +33,22 @@ namespace internal {
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
- size_t MaxCFGBlocks)
- : MaxCFGBlocks(MaxCFGBlocks), AC(AC), Reporter(Reporter) {
- FactMgr.setMaxCFGBlocksThreshold(MaxCFGBlocks);
-}
+ const LifetimeSafetyOpts &LSOpts)
+ : LSOpts(LSOpts), AC(AC), Reporter(Reporter) {}
void LifetimeSafetyAnalysis::run() {
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
const CFG &Cfg = *AC.getCFG();
- if (MaxCFGBlocks > 0 && Cfg.getNumBlockIDs() > MaxCFGBlocks) {
- std::string FuncName = "<unknown>";
- if (const Decl *D = AC.getDecl())
- if (const auto *ND = dyn_cast<NamedDecl>(D))
- FuncName = ND->getQualifiedNameAsString();
- DEBUG_WITH_TYPE("LifetimeSafety",
- llvm::dbgs()
- << "LifetimeSafety: Skipping function " << FuncName
- << "due to large CFG: <count> blocks (threshold: "
- << MaxCFGBlocks << ")\n");
+ if (LSOpts.MaxCFGBlocks > 0 && Cfg.getNumBlockIDs() > LSOpts.MaxCFGBlocks) {
+ DEBUG_WITH_TYPE(
+ "LifetimeSafety", std::string FuncName = "<unknown>";
+ if (const Decl *D = AC.getDecl()) if (const auto *ND =
+ dyn_cast<NamedDecl>(D))
+ FuncName = ND->getQualifiedNameAsString();
+ llvm::dbgs() << "LifetimeSafety: Skipping function " << FuncName
+ << "due to large CFG: <count> blocks (threshold: "
+ << LSOpts.MaxCFGBlocks << ")\n");
return;
}
DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
@@ -87,9 +84,10 @@ void LifetimeSafetyAnalysis::run() {
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter) {
- internal::LifetimeSafetyAnalysis Analysis(
- AC, Reporter,
- AC.getASTContext().getLangOpts().LifetimeSafetyMaxCFGBlocks);
+ LifetimeSafetyOpts LSOpts;
+ LSOpts.MaxCFGBlocks =
+ AC.getASTContext().getLangOpts().LifetimeSafetyMaxCFGBlocks;
+ internal::LifetimeSafetyAnalysis Analysis(AC, Reporter, LSOpts);
Analysis.run();
}
} // namespace clang::lifetimes
diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
index 1f27df26d30f6..20afe0d93a2d7 100644
--- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp
+++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp
@@ -62,8 +62,10 @@ class LifetimeTestRunner {
BuildOptions.AddLifetime = true;
// Run the main analysis.
+ LifetimeSafetyOpts LSOpts;
+ LSOpts.MaxCFGBlocks = 0;
Analysis =
- std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, 0);
+ std::make_unique<LifetimeSafetyAnalysis>(*AnalysisCtx, nullptr, LSOpts);
Analysis->run();
AnnotationToPointMap = Analysis->getFactManager().getTestPoints();
>From b83eb55a25fe19a2ccac6075b3f0df7f1018f4b6 Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Mon, 15 Dec 2025 09:29:29 +0000
Subject: [PATCH 08/13] Remvoing unused members and functions from Fact class
---
clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
index 82e14832208b3..b5f7f8746186a 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h
@@ -238,7 +238,6 @@ class FactManager {
const LoanManager &getLoanMgr() const { return LoanMgr; }
OriginManager &getOriginMgr() { return OriginMgr; }
const OriginManager &getOriginMgr() const { return OriginMgr; }
- void setMaxCFGBlocksThreshold(size_t Threshold) { MaxCFGBlocks = Threshold; }
private:
FactID NextFactID{0};
@@ -247,7 +246,6 @@ class FactManager {
/// Facts for each CFG block, indexed by block ID.
llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts;
llvm::BumpPtrAllocator FactAllocator;
- size_t MaxCFGBlocks = 0;
};
} // namespace clang::lifetimes::internal
>From 90d60063aa8f018154357d1c9be7439fb68b09c7 Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Fri, 19 Dec 2025 10:34:17 +0000
Subject: [PATCH 09/13] Adding a test for bailout strategy based on CFG block
numbers
---
.../Sema/warn-lifetime-safety-cfg-bailout.cpp | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
diff --git a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
new file mode 100644
index 0000000000000..8c2d671f3fc17
--- /dev/null
+++ b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -fexperimental-lifetime-safety-max-cfg-blocks=3 -Wno-dangling %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAILOUT
+// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOBAILOUT
+
+struct MyObj {
+ int id;
+ ~MyObj() {} // Non-trivial destructor
+ MyObj operator+(MyObj);
+};
+
+struct [[gsl::Pointer()]] View {
+ View(const MyObj&); // Borrows from MyObj
+ View();
+ void use() const;
+};
+
+class TriviallyDestructedClass {
+ View a, b;
+};
+
+//===----------------------------------------------------------------------===//
+// Basic Definite Use-After-Free (-W...permissive)
+// These are cases where the pointer is guaranteed to be dangling at the use site.
+//===----------------------------------------------------------------------===//
+
+void single_block_cfg() {
+ MyObj* p;
+ {
+ MyObj s;
+ p = &s; // CHECK-BAILOUT: warning: object whose reference is captured does not live long enough
+ } // CHECK-BAILOUT: note: destroyed here
+ (void)*p; // CHECK-BAILOUT: note: later used here
+}
+
+void multiple_block_cfg() {
+ View v;
+ int a = 10;
+ MyObj safe;
+ {
+ if (a > 5) {
+ MyObj s;
+ v = s; // CHECK-NOBAILOUT: warning: object whose reference is captured does not live long enough
+ } else {
+ v = safe;
+ }
+ } // CHECK-NOBAILOUT: note: destroyed here
+ v.use(); // CHECK-NOBAILOUT: note: later used here
+}
>From 7d4536c48ecc13af4f247b74ad1e07c9845d1dbd Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Wed, 7 Jan 2026 09:25:17 +0000
Subject: [PATCH 10/13] Passing Lifetime Safety opts by copy instead of
reference
---
.../clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index cb8d15771ef5e..636dede3f4dc9 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -105,7 +105,7 @@ class LifetimeSafetyAnalysis {
FactManager &getFactManager() { return *FactMgr; }
private:
- const LifetimeSafetyOpts &LSOpts;
+ const LifetimeSafetyOpts LSOpts;
AnalysisDeclContext &AC;
LifetimeSafetyReporter *Reporter;
LifetimeFactory Factory;
>From 56b01dcded446816193c7288c3af4f9692c81703 Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Fri, 30 Jan 2026 17:12:55 +0000
Subject: [PATCH 11/13] Fixing formatting issue and modifying the tests to user
verify command
---
.../Analyses/LifetimeSafety/LifetimeSafety.h | 2 +-
clang/include/clang/Options/Options.td | 4 ++--
.../LifetimeSafety/LifetimeSafety.cpp | 4 ++--
.../Sema/warn-lifetime-safety-cfg-bailout.cpp | 23 ++++++++++---------
4 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 2bc647d21a561..81bfeffeef292 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -123,7 +123,7 @@ class LifetimeSafetyAnalysis {
public:
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetySemaHelper *SemaHelper,
- const LifetimeSafetyOpts &LSOpts);
+ const LifetimeSafetyOpts &LSOpts);
void run();
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 3d51c63dae681..1eae3a5d5fb51 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -1968,8 +1968,8 @@ defm lifetime_safety : BoolFOption<
BothFlags<[], [CC1Option],
" experimental lifetime safety for C++">>;
-def fexperimental_lifetime_safety_max_cfg_blocks
- : Joined<["-"], "fexperimental-lifetime-safety-max-cfg-blocks=">,
+def lifetime_safety_max_cfg_blocks
+ : Joined<["-"], "lifetime-safety-max-cfg-blocks=">,
Group<m_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Skip LifetimeSafety analysis for functions with CFG block "
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 61c5b837d6d73..618292da08be6 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -48,9 +48,9 @@ static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg,
}
#endif
-
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(
- AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper, const LifetimeSafetyOpts &LSOpts)
+ AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper,
+ const LifetimeSafetyOpts &LSOpts)
: AC(AC), SemaHelper(SemaHelper), LSOpts(LSOpts) {}
void LifetimeSafetyAnalysis::run() {
diff --git a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
index 8c2d671f3fc17..cce1279ef8d59 100644
--- a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
@@ -1,10 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -fexperimental-lifetime-safety-max-cfg-blocks=3 -Wno-dangling %s 2>&1 | FileCheck %s --check-prefix=CHECK-BAILOUT
-// RUN: %clang_cc1 -fsyntax-only -fexperimental-lifetime-safety -Wexperimental-lifetime-safety -Wno-dangling %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOBAILOUT
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety -Wlifetime-safety -lifetime-safety-max-cfg-blocks=3 -Wno-dangling -verify=CHECK-BAILOUT %s
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety -Wlifetime-safety -Wno-dangling -verify=CHECK-BAILOUT -verify=CHECK-NOBAILOUT %s
struct MyObj {
int id;
~MyObj() {} // Non-trivial destructor
MyObj operator+(MyObj);
+ void use() const;
};
struct [[gsl::Pointer()]] View {
@@ -26,22 +27,22 @@ void single_block_cfg() {
MyObj* p;
{
MyObj s;
- p = &s; // CHECK-BAILOUT: warning: object whose reference is captured does not live long enough
- } // CHECK-BAILOUT: note: destroyed here
- (void)*p; // CHECK-BAILOUT: note: later used here
+ p = &s; // CHECK-BAILOUT-warning {{object whose reference is captured does not live long enough}}
+ } // CHECK-BAILOUT-note {{destroyed here}}
+ (void)*p; // CHECK-BAILOUT-note {{later used here}}
}
void multiple_block_cfg() {
- View v;
+ MyObj* p;
int a = 10;
MyObj safe;
{
if (a > 5) {
MyObj s;
- v = s; // CHECK-NOBAILOUT: warning: object whose reference is captured does not live long enough
- } else {
- v = safe;
+ p = &s; // CHECK-NOBAILOUT-warning {{object whose reference is captured does not live long enough}}
+ } else { // CHECK-NOBAILOUT-note {{destroyed here}}
+ p = &safe;
}
- } // CHECK-NOBAILOUT: note: destroyed here
- v.use(); // CHECK-NOBAILOUT: note: later used here
+ }
+ p->use(); // CHECK-NOBAILOUT-note {{later used here}}
}
>From 02e087750d7474cab266222d0cb6362a3a2f1fdd Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Thu, 5 Feb 2026 06:15:35 +0000
Subject: [PATCH 12/13] Removing -flifetime-safety flag from test since it is
turned on by default
---
.../clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h | 2 +-
clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp | 2 +-
clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
index 81bfeffeef292..ba7e8a8544594 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -135,9 +135,9 @@ class LifetimeSafetyAnalysis {
FactManager &getFactManager() { return *FactMgr; }
private:
- const LifetimeSafetyOpts LSOpts;
AnalysisDeclContext &AC;
LifetimeSafetySemaHelper *SemaHelper;
+ const LifetimeSafetyOpts LSOpts;
LifetimeFactory Factory;
std::unique_ptr<FactManager> FactMgr;
std::unique_ptr<LiveOriginsAnalysis> LiveOrigins;
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 618292da08be6..9ae92ffa02f4a 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -64,7 +64,7 @@ void LifetimeSafetyAnalysis::run() {
dyn_cast<NamedDecl>(D))
FuncName = ND->getQualifiedNameAsString();
llvm::dbgs() << "LifetimeSafety: Skipping function " << FuncName
- << "due to large CFG: <count> blocks (threshold: "
+ << "due to large CFG: " << Cfg.getNumBlockIDs() << " blocks (threshold: "
<< LSOpts.MaxCFGBlocks << ")\n");
return;
}
diff --git a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
index cce1279ef8d59..94da3730f0e37 100644
--- a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety -Wlifetime-safety -lifetime-safety-max-cfg-blocks=3 -Wno-dangling -verify=CHECK-BAILOUT %s
-// RUN: %clang_cc1 -fsyntax-only -flifetime-safety -Wlifetime-safety -Wno-dangling -verify=CHECK-BAILOUT -verify=CHECK-NOBAILOUT %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -lifetime-safety-max-cfg-blocks=3 -Wno-dangling -verify=CHECK-BAILOUT %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify=CHECK-BAILOUT -verify=CHECK-NOBAILOUT %s
struct MyObj {
int id;
>From 9e31fd9b4eeea3c03205d3a6cbbc33130bc87a5e Mon Sep 17 00:00:00 2001
From: Debadri Basak <debadri1010 at gmail.com>
Date: Tue, 17 Feb 2026 10:20:46 +0000
Subject: [PATCH 13/13] Formatting changes and verify prefix changes in tests
---
.../Analysis/LifetimeSafety/LifetimeSafety.cpp | 4 ++--
.../Sema/warn-lifetime-safety-cfg-bailout.cpp | 16 ++++++++--------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 7d989edea7c79..714f979fa5ee7 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -64,8 +64,8 @@ void LifetimeSafetyAnalysis::run() {
dyn_cast<NamedDecl>(D))
FuncName = ND->getQualifiedNameAsString();
llvm::dbgs() << "LifetimeSafety: Skipping function " << FuncName
- << "due to large CFG: " << Cfg.getNumBlockIDs() << " blocks (threshold: "
- << LSOpts.MaxCFGBlocks << ")\n");
+ << "due to large CFG: " << Cfg.getNumBlockIDs()
+ << " blocks (threshold: " << LSOpts.MaxCFGBlocks << ")\n");
return;
}
diff --git a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
index 94da3730f0e37..7c5d61e23e710 100644
--- a/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
+++ b/clang/test/Sema/warn-lifetime-safety-cfg-bailout.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -lifetime-safety-max-cfg-blocks=3 -Wno-dangling -verify=CHECK-BAILOUT %s
-// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify=CHECK-BAILOUT -verify=CHECK-NOBAILOUT %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -lifetime-safety-max-cfg-blocks=3 -Wno-dangling -verify=bailout %s
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify=bailout -verify=nobailout %s
struct MyObj {
int id;
@@ -27,9 +27,9 @@ void single_block_cfg() {
MyObj* p;
{
MyObj s;
- p = &s; // CHECK-BAILOUT-warning {{object whose reference is captured does not live long enough}}
- } // CHECK-BAILOUT-note {{destroyed here}}
- (void)*p; // CHECK-BAILOUT-note {{later used here}}
+ p = &s; // bailout-warning {{object whose reference is captured does not live long enough}}
+ } // bailout-note {{destroyed here}}
+ (void)*p; // bailout-note {{later used here}}
}
void multiple_block_cfg() {
@@ -39,10 +39,10 @@ void multiple_block_cfg() {
{
if (a > 5) {
MyObj s;
- p = &s; // CHECK-NOBAILOUT-warning {{object whose reference is captured does not live long enough}}
- } else { // CHECK-NOBAILOUT-note {{destroyed here}}
+ p = &s; // nobailout-warning {{object whose reference is captured does not live long enough}}
+ } else { // nobailout-note {{destroyed here}}
p = &safe;
}
}
- p->use(); // CHECK-NOBAILOUT-note {{later used here}}
+ p->use(); // nobailout-note {{later used here}}
}
More information about the cfe-commits
mailing list