Author: Utkarsh Saxena Date: 2026-09-07T11:54:37Z New Revision: ef23a997b4e0f555d467158c0ac47357c41b1314
URL: https://github.com/llvm/llvm-project/commit/ef23a997b4e0f555d467158c0ac47357c41b1314 DIFF: https://github.com/llvm/llvm-project/commit/ef23a997b4e0f555d467158c0ac47357c41b1314.diff LOG: [LifetimeSafety] Gate lifetime checks behind per-diagnostic opts (#221610) Granular Lifetime Safety Check Gating We split `IsLifetimeSafetyEnabled` into individual check functions in `SemaLifetimeSafety.h`. These properties are stored in `LifetimeSafetyOpts`, which are then checked inside the `Checker` to avoid invoking expensive reporting functions mapping to diagnostics that are disabled. `reportMisplacedLifetimebound` was found to be the most expensive (possibly because it iterates on redecls). Added: Modified: clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h clang/lib/Analysis/LifetimeSafety/Checker.cpp clang/lib/Sema/SemaLifetimeSafety.h Removed: ################################################################################ diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 101407e91aa65..68e84961010dd 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -41,6 +41,11 @@ struct LifetimeSafetyOpts { /// Whether to suggest lifetime annotations. bool SuggestAnnotations; + + bool CheckNoescapeViolations; + bool CheckLifetimeboundViolations; + bool CheckMisplacedLifetimebound; + bool CheckInapplicableLifetimebound; }; /// Enum to track functions visible across or within TU. diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index b136da486365a..a358215a295d1 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -105,10 +105,14 @@ class LifetimeChecker { checkAnnotations(OEF); issuePendingWarnings(); suggestAnnotations(); - reportNoescapeViolations(); - reportLifetimeboundViolations(); - reportMisplacedLifetimebound(); - reportInapplicableLifetimebound(); + if (LSOpts.CheckNoescapeViolations) + reportNoescapeViolations(); + if (LSOpts.CheckLifetimeboundViolations) + reportLifetimeboundViolations(); + if (LSOpts.CheckMisplacedLifetimebound) + reportMisplacedLifetimebound(); + if (LSOpts.CheckInapplicableLifetimebound) + reportInapplicableLifetimebound(); // Annotation inference is currently guarded by a frontend flag. In the // future, this might be replaced by a design that diff erentiates between // explicit and inferred findings with separate warning groups. @@ -254,6 +258,7 @@ class LifetimeChecker { } void issuePendingWarnings() { + llvm::TimeTraceScope TimeTrace("IssuePendingWarnings"); if (!SemaHelper) return; for (const auto &[LID, Warning] : FinalWarningsMap) { @@ -436,6 +441,7 @@ class LifetimeChecker { } void reportNoescapeViolations() { + llvm::TimeTraceScope TimeTrace("ReportNoescapeViolations"); for (auto [PVD, EscapeTarget] : NoescapeWarningsMap) { if (const auto *E = EscapeTarget.dyn_cast<const Expr *>()) SemaHelper->reportNoescapeViolation(PVD, E); @@ -449,6 +455,7 @@ class LifetimeChecker { } void reportLifetimeboundViolations() { + llvm::TimeTraceScope TimeTrace("ReportLifetimeboundViolations"); if (!isa<FunctionDecl>(FD)) return; if (const auto *MD = dyn_cast<CXXMethodDecl>(FD); @@ -471,6 +478,7 @@ class LifetimeChecker { // Reports lifetimebound attributes that are placed on a function definition // but not on the corresponding declaration. void reportMisplacedLifetimebound() { + llvm::TimeTraceScope TimeTrace("ReportMisplacedLifetimebound"); const FunctionDecl *FDef = dyn_cast<FunctionDecl>(FD); if (!FDef) return; @@ -501,6 +509,7 @@ class LifetimeChecker { } void reportInapplicableLifetimebound() { + llvm::TimeTraceScope TimeTrace("ReportInapplicableLifetimebound"); const auto *FDef = dyn_cast<FunctionDecl>(FD); if (!FDef) return; diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index d87c9003e83cf..0fd3486bcee46 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -25,28 +25,7 @@ namespace clang::lifetimes { -inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) { - // TODO: Enable ObjectiveC later when we know it's stable enough. - if (S.getLangOpts().ObjC) - return false; - - // TODO: Default this flag to on in the future. - if (!S.getLangOpts().CPlusPlus && !S.getLangOpts().EnableLifetimeSafetyInC) - return false; - - // Translation-unit mode: whole-program analysis runs once on TU. - // Individual function analysis is disabled when TU mode is enabled. - if (S.getLangOpts().EnableLifetimeSafetyTUAnalysis) - return isa<TranslationUnitDecl>(D); - - // Per-function mode: analysis runs on each function/method individually. - // Skip TU-level calls when per-function mode is enabled. - if (isa<TranslationUnitDecl>(D)) - return false; - - // Enable per-function mode via debug flag or specific diagnostics. - if (S.getLangOpts().DebugRunLifetimeSafety) - return true; +inline bool ShouldCheckSafety(Sema &S, const Decl *D) { DiagnosticsEngine &Diags = S.getDiagnostics(); constexpr unsigned DiagIDs[] = { diag::warn_lifetime_safety_use_after_scope, @@ -59,25 +38,40 @@ inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) { diag::warn_lifetime_safety_dangling_field_moved, diag::warn_lifetime_safety_dangling_global, diag::warn_lifetime_safety_dangling_global_moved, - diag::warn_lifetime_safety_noescape_escapes, - diag::warn_lifetime_safety_lifetimebound_violation, - diag::warn_lifetime_safety_cross_tu_misplaced_lifetimebound, - diag::warn_lifetime_safety_intra_tu_misplaced_lifetimebound, diag::warn_lifetime_safety_invalidated_field, - diag::warn_lifetime_safety_invalidated_global, - diag::warn_lifetime_safety_cross_tu_param_suggestion, - diag::warn_lifetime_safety_intra_tu_param_suggestion, - diag::warn_lifetime_safety_cross_tu_ctor_param_suggestion, - diag::warn_lifetime_safety_intra_tu_ctor_param_suggestion, - diag::warn_lifetime_safety_cross_tu_this_suggestion, - diag::warn_lifetime_safety_intra_tu_this_suggestion, - diag::warn_lifetime_safety_inapplicable_lifetimebound}; + diag::warn_lifetime_safety_invalidated_global}; + for (unsigned DiagID : DiagIDs) + if (!Diags.isIgnored(DiagID, D->getBeginLoc())) + return true; + return false; +} + +inline bool ShouldCheckNoescapeViolations(Sema &S, const Decl *D) { + return !S.getDiagnostics().isIgnored( + diag::warn_lifetime_safety_noescape_escapes, D->getBeginLoc()); +} + +inline bool ShouldCheckLifetimeboundViolations(Sema &S, const Decl *D) { + return !S.getDiagnostics().isIgnored( + diag::warn_lifetime_safety_lifetimebound_violation, D->getBeginLoc()); +} + +inline bool ShouldCheckMisplacedLifetimebound(Sema &S, const Decl *D) { + DiagnosticsEngine &Diags = S.getDiagnostics(); + constexpr unsigned DiagIDs[] = { + diag::warn_lifetime_safety_cross_tu_misplaced_lifetimebound, + diag::warn_lifetime_safety_intra_tu_misplaced_lifetimebound}; for (unsigned DiagID : DiagIDs) if (!Diags.isIgnored(DiagID, D->getBeginLoc())) return true; return false; } +inline bool ShouldCheckInapplicableLifetimebound(Sema &S, const Decl *D) { + return !S.getDiagnostics().isIgnored( + diag::warn_lifetime_safety_inapplicable_lifetimebound, D->getBeginLoc()); +} + inline bool ShouldSuggestLifetimeAnnotations(Sema &S, const Decl *D) { DiagnosticsEngine &Diags = S.getDiagnostics(); constexpr unsigned DiagIDs[] = { @@ -93,10 +87,46 @@ inline bool ShouldSuggestLifetimeAnnotations(Sema &S, const Decl *D) { return false; } +inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) { + // TODO: Enable ObjectiveC later when we know it's stable enough. + if (S.getLangOpts().ObjC) + return false; + + // TODO: Default this flag to on in the future. + if (!S.getLangOpts().CPlusPlus && !S.getLangOpts().EnableLifetimeSafetyInC) + return false; + + // Translation-unit mode: whole-program analysis runs once on TU. + // Individual function analysis is disabled when TU mode is enabled. + if (S.getLangOpts().EnableLifetimeSafetyTUAnalysis) + return isa<TranslationUnitDecl>(D); + + // Per-function mode: analysis runs on each function/method individually. + // Skip TU-level calls when per-function mode is enabled. + if (isa<TranslationUnitDecl>(D)) + return false; + + // Enable per-function mode via debug flag or specific diagnostics. + if (S.getLangOpts().DebugRunLifetimeSafety) + return true; + + return ShouldCheckSafety(S, D) || ShouldCheckNoescapeViolations(S, D) || + ShouldCheckLifetimeboundViolations(S, D) || + ShouldCheckMisplacedLifetimebound(S, D) || + ShouldCheckInapplicableLifetimebound(S, D) || + ShouldSuggestLifetimeAnnotations(S, D); +} + inline LifetimeSafetyOpts GetLifetimeSafetyOpts(Sema &S, const Decl *D) { LifetimeSafetyOpts LSOpts; LSOpts.MaxCFGBlocks = S.getLangOpts().LifetimeSafetyMaxCFGBlocks; LSOpts.SuggestAnnotations = ShouldSuggestLifetimeAnnotations(S, D); + LSOpts.CheckNoescapeViolations = ShouldCheckNoescapeViolations(S, D); + LSOpts.CheckLifetimeboundViolations = + ShouldCheckLifetimeboundViolations(S, D); + LSOpts.CheckMisplacedLifetimebound = ShouldCheckMisplacedLifetimebound(S, D); + LSOpts.CheckInapplicableLifetimebound = + ShouldCheckInapplicableLifetimebound(S, D); return LSOpts; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
