[clang] suggesionsopt-in-suggestions (PR #205764)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 25 03:13:13 PDT 2026
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/205764
>From 9ad57f3a6e129a25471d298edfc6c0fd82c8c634 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 25 Jun 2026 10:10:35 +0000
Subject: [PATCH 1/2] suggesionsopt-in-suggestions
---
.../Analysis/Analyses/LifetimeSafety/Checker.h | 3 ++-
.../Analyses/LifetimeSafety/LifetimeSafety.h | 4 ++++
clang/lib/Analysis/LifetimeSafety/Checker.cpp | 14 ++++++++++----
.../lib/Analysis/LifetimeSafety/LifetimeSafety.cpp | 7 ++-----
clang/lib/Sema/AnalysisBasedWarnings.cpp | 13 ++++++++++---
clang/lib/Sema/SemaLifetimeSafety.h | 13 +++++++++++++
6 files changed, 41 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
index 1ad3f9da61f60..99ad816311e74 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h
@@ -29,7 +29,8 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
const MovedLoansAnalysis &MovedLoans,
const LiveOriginsAnalysis &LiveOrigins,
FactManager &FactMgr, AnalysisDeclContext &ADC,
- LifetimeSafetySemaHelper *SemaHelper);
+ LifetimeSafetySemaHelper *SemaHelper,
+ const LifetimeSafetyOpts &LSOpts);
} // 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 28886b826f72f..80a23f18baebd 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h
@@ -38,6 +38,9 @@ struct LifetimeSafetyOpts {
/// Maximum number of CFG blocks to analyze. Functions with larger CFGs will
/// be skipped.
size_t MaxCFGBlocks;
+
+ /// Whether to suggest lifetime annotations.
+ bool SuggestAnnotations;
};
/// Enum to track functions visible across or within TU.
@@ -157,6 +160,7 @@ class LifetimeSafetySemaHelper {
/// The main entry point for the analysis.
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetySemaHelper *SemaHelper,
+ const LifetimeSafetyOpts &Opts,
LifetimeSafetyStats &Stats, bool CollectStats);
namespace internal {
diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
index c258a1dc3596c..746ebbfb15c39 100644
--- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp
@@ -68,6 +68,7 @@ class LifetimeChecker {
LifetimeSafetySemaHelper *SemaHelper;
ASTContext &AST;
const Decl *FD;
+ const LifetimeSafetyOpts &LSOpts;
static SourceLocation
GetFactLoc(llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> F) {
@@ -87,10 +88,11 @@ class LifetimeChecker {
const MovedLoansAnalysis &MovedLoans,
const LiveOriginsAnalysis &LiveOrigins, FactManager &FM,
AnalysisDeclContext &ADC,
- LifetimeSafetySemaHelper *SemaHelper)
+ LifetimeSafetySemaHelper *SemaHelper,
+ const LifetimeSafetyOpts &LSOpts)
: LoanPropagation(LoanPropagation), MovedLoans(MovedLoans),
LiveOrigins(LiveOrigins), FactMgr(FM), SemaHelper(SemaHelper),
- AST(ADC.getASTContext()), FD(ADC.getDecl()) {
+ AST(ADC.getASTContext()), FD(ADC.getDecl()), LSOpts(LSOpts) {
for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
for (const Fact *F : FactMgr.getFacts(B))
if (const auto *EF = F->getAs<ExpireFact>())
@@ -398,6 +400,9 @@ class LifetimeChecker {
void suggestAnnotations() {
if (!SemaHelper)
return;
+ if (!LSOpts.SuggestAnnotations)
+ return;
+ llvm::TimeTraceScope TimeTrace("SuggestAnnotations");
for (auto [Target, EscapeTarget] : AnnotationWarningsMap) {
if (const auto *PVD = Target.dyn_cast<const ParmVarDecl *>())
suggestWithScopeForParmVar(PVD, EscapeTarget);
@@ -535,9 +540,10 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LP,
const MovedLoansAnalysis &MovedLoans,
const LiveOriginsAnalysis &LO, FactManager &FactMgr,
AnalysisDeclContext &ADC,
- LifetimeSafetySemaHelper *SemaHelper) {
+ LifetimeSafetySemaHelper *SemaHelper,
+ const LifetimeSafetyOpts &LSOpts) {
llvm::TimeTraceScope TimeProfile("LifetimeChecker");
- LifetimeChecker Checker(LP, MovedLoans, LO, FactMgr, ADC, SemaHelper);
+ LifetimeChecker Checker(LP, MovedLoans, LO, FactMgr, ADC, SemaHelper, LSOpts);
}
} // namespace clang::lifetimes::internal
diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
index 714f979fa5ee7..680095a54177c 100644
--- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp
@@ -96,7 +96,7 @@ void LifetimeSafetyAnalysis::run() {
Factory.MovedLoansMapFactory);
runLifetimeChecker(*LoanPropagation, *MovedLoans, *LiveOrigins, *FactMgr, AC,
- SemaHelper);
+ SemaHelper, LSOpts);
DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
/*ShowColors=*/true));
@@ -122,11 +122,8 @@ void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetySemaHelper *SemaHelper,
+ const LifetimeSafetyOpts &LSOpts,
LifetimeSafetyStats &Stats, bool CollectStats) {
- LifetimeSafetyOpts LSOpts;
- LSOpts.MaxCFGBlocks =
- AC.getASTContext().getLangOpts().LifetimeSafetyMaxCFGBlocks;
-
internal::LifetimeSafetyAnalysis Analysis(AC, SemaHelper, LSOpts);
Analysis.run();
if (CollectStats)
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 52fe7765c6c6a..d39763a8732ca 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2928,8 +2928,12 @@ LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU,
AC.getCFGBuildOptions().AddInitializers = true;
AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;
AC.getCFGBuildOptions().setAllAlwaysAdd();
- if (AC.getCFG())
- runLifetimeSafetyAnalysis(AC, &SemaHelper, LSStats, S.CollectStats);
+ if (AC.getCFG()) {
+ lifetimes::LifetimeSafetyOpts LSOpts;
+ LSOpts.MaxCFGBlocks = S.getLangOpts().LifetimeSafetyMaxCFGBlocks;
+ LSOpts.SuggestAnnotations = lifetimes::ShouldSuggestLifetimeAnnotations(S, FD);
+ runLifetimeSafetyAnalysis(AC, &SemaHelper, LSOpts, LSStats, S.CollectStats);
+ }
}
}
@@ -3164,8 +3168,11 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (EnableLifetimeSafetyAnalysis) {
if (AC.getCFG()) {
lifetimes::LifetimeSafetySemaHelperImpl LifetimeSafetySemaHelper(S);
+ lifetimes::LifetimeSafetyOpts LSOpts;
+ LSOpts.MaxCFGBlocks = S.getLangOpts().LifetimeSafetyMaxCFGBlocks;
+ LSOpts.SuggestAnnotations = lifetimes::ShouldSuggestLifetimeAnnotations(S, D);
lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetySemaHelper,
- LSStats, S.CollectStats);
+ LSOpts, LSStats, S.CollectStats);
}
}
// Check for violations of "called once" parameter properties.
diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h
index 7c78a6a1e8c31..c15c8609845b6 100644
--- a/clang/lib/Sema/SemaLifetimeSafety.h
+++ b/clang/lib/Sema/SemaLifetimeSafety.h
@@ -76,6 +76,19 @@ inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) {
return false;
}
+inline bool ShouldSuggestLifetimeAnnotations(Sema &S, const Decl *D) {
+ DiagnosticsEngine &Diags = S.getDiagnostics();
+ constexpr unsigned DiagIDs[] = {
+ diag::warn_lifetime_safety_intra_tu_param_suggestion,
+ diag::warn_lifetime_safety_cross_tu_param_suggestion,
+ diag::warn_lifetime_safety_intra_tu_this_suggestion,
+ diag::warn_lifetime_safety_cross_tu_this_suggestion};
+ for (unsigned DiagID : DiagIDs)
+ if (!Diags.isIgnored(DiagID, D->getBeginLoc()))
+ return true;
+ return false;
+}
+
class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper {
public:
>From 761abd1fbf088a2e2799133c6abed50e3120d2ca Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 25 Jun 2026 10:12:51 +0000
Subject: [PATCH 2/2] add tests
---
.../annotation-suggestions-disabled.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 clang/test/Sema/LifetimeSafety/annotation-suggestions-disabled.cpp
diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-disabled.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions-disabled.cpp
new file mode 100644
index 0000000000000..ca5b3b7a65dd1
--- /dev/null
+++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-disabled.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -I%S -verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+struct View;
+struct [[gsl::Owner]] MyObj {
+ View getView() const [[clang::lifetimebound]];
+};
+struct [[gsl::Pointer()]] View {
+ View(const MyObj&);
+};
+
+// This would normally trigger a suggestion warning if -Wlifetime-safety-suggestions was on.
+// Since it is off, we expect NO warnings or notes here.
+// expected-no-diagnostics
+View return_view_directly(View a) {
+ return a;
+}
More information about the cfe-commits
mailing list