[clang] [Clang] Cache analysis-warning gates by diagnostic state (NFC) (PR #223034)
Mehdi Amini via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 12:46:46 PDT 2026
https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/223034
Avoid resolving the same disabled warning groups for every function. Reuse one cached policy for the lifetime, uninitialized-use, fallthrough, recursion, noexcept, and logical-error analysis gates.
CTMark O0 (3 samples): 29.439800 s -> 29.457833 s (+0.061%), withing the noise.
However, there is some non-trivial impact on these significant TUs in MLIR build time:
- `mlir/lib/RegisterAllDialects.cpp`: 1.5439% fewer retired instructions.
- `mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp`: 0.7746% fewer retired instructions.
Assisted-by: Codex
>From f05ee3c7b6823c66ce6a75b8aa3e10396c16f1b9 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Thu, 10 Sep 2026 09:28:05 -0700
Subject: [PATCH] Cache analysis-warning gates by diagnostic state
Avoid resolving the same disabled warning groups for every function. Reuse one
cached policy for the lifetime, uninitialized-use, fallthrough, recursion,
noexcept, and logical-error analysis gates.
CTMark O0 (3 samples, CPU 6): 29.439800 s -> 29.457833 s (+0.061%).
Impact on significant TUs in MLIR build time:
- `mlir/lib/RegisterAllDialects.cpp`: 1.5439% fewer retired
instructions.
- `mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp`: 0.7746% fewer retired
instructions.
Assisted-by: Codex
---
.../clang/Sema/AnalysisBasedWarnings.h | 16 +++++
clang/lib/Sema/AnalysisBasedWarnings.cpp | 64 ++++++++++++++-----
2 files changed, 64 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h
index f8bd867062b47..7bcdf10b3dfc4 100644
--- a/clang/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h
@@ -70,6 +70,22 @@ class AnalysisBasedWarnings {
/// Flushed whenever a diagnostic pragma changes severities.
llvm::DenseMap<const void *, Policy> PolicyCache[4];
+ struct FunctionPolicy {
+ bool enableLifetimeSafetyAnalysis;
+ bool enableUninitializedAnalysis;
+ bool enableFallthroughFull;
+ bool enableFallthroughPerFunction;
+ bool enableInfiniteRecursion;
+ bool enableThrowInNoexcept;
+ bool enableLogicalErrors;
+ };
+
+ /// Caches warning-analysis gates by diagnostic state and system-header
+ /// classification.
+ llvm::DenseMap<const void *, FunctionPolicy> FunctionPolicyCache[4];
+
+ FunctionPolicy getFunctionPolicy(const Decl *D);
+
/// \name Statistics
/// @{
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index d0500a6defd64..62f46b5114988 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2840,6 +2840,44 @@ sema::AnalysisBasedWarnings::getPolicyInEffectAt(SourceLocation Loc) {
void sema::AnalysisBasedWarnings::clearPolicyCache() {
for (auto &M : PolicyCache)
M.clear();
+ for (auto &M : FunctionPolicyCache)
+ M.clear();
+}
+
+sema::AnalysisBasedWarnings::FunctionPolicy
+sema::AnalysisBasedWarnings::getFunctionPolicy(const Decl *D) {
+ DiagnosticsEngine &Diags = S.getDiagnostics();
+ SourceLocation Loc = D->getBeginLoc();
+ const bool Cacheable = !Diags.hasDiagSuppressionMapping() && Loc.isValid();
+
+ const void *StateKey = nullptr;
+ unsigned SysIdx = 0;
+ if (Cacheable) {
+ const SourceManager &SM = Diags.getSourceManager();
+ SysIdx = (SM.isInSystemHeader(SM.getExpansionLoc(Loc)) ? 2u : 0u) |
+ (SM.isInSystemMacro(Loc) ? 1u : 0u);
+ StateKey = Diags.getDiagStateKeyForLoc(Loc);
+ auto It = FunctionPolicyCache[SysIdx].find(StateKey);
+ if (It != FunctionPolicyCache[SysIdx].end())
+ return It->second;
+ }
+
+ FunctionPolicy P{
+ lifetimes::IsLifetimeSafetyEnabled(S, D),
+ areAnyEnabled(
+ Diags, Loc, diag::warn_uninit_var, diag::warn_sometimes_uninit_var,
+ diag::warn_maybe_uninit_var, diag::warn_uninit_const_reference,
+ diag::warn_uninit_const_pointer),
+ !Diags.isIgnored(diag::warn_unannotated_fallthrough, Loc),
+ !Diags.isIgnored(diag::warn_unannotated_fallthrough_per_function, Loc),
+ !Diags.isIgnored(diag::warn_infinite_recursive_function, Loc),
+ !Diags.isIgnored(diag::warn_throw_in_noexcept_func, Loc),
+ LogicalErrorHandler::hasActiveDiagnostics(Diags, Loc),
+ };
+
+ if (Cacheable)
+ FunctionPolicyCache[SysIdx][StateKey] = P;
+ return P;
}
void sema::AnalysisBasedWarnings::clearOverrides() {
@@ -3098,7 +3136,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarningsForImplicitFunction(
return;
// In TU-end mode IsLifetimeSafetyEnabled returns false for non-TU decls, so
// such definitions are reached only via the call-graph walk, not here.
- if (!lifetimes::IsLifetimeSafetyEnabled(S, D))
+ if (!getFunctionPolicy(D).enableLifetimeSafetyAnalysis)
return;
if (shouldSkipAnalysisForDecl(S, D) || S.hasUncompilableErrorOccurred())
return;
@@ -3165,7 +3203,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
AC.getCFGBuildOptions().AddCXXNewAllocator = false;
AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true;
- bool EnableLifetimeSafetyAnalysis = lifetimes::IsLifetimeSafetyEnabled(S, D);
+ FunctionPolicy FP = getFunctionPolicy(D);
+ bool EnableLifetimeSafetyAnalysis = FP.enableLifetimeSafetyAnalysis;
// Force that certain expressions appear as CFGElements in the CFG. This
// is used to speed up various analyses.
@@ -3192,7 +3231,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// Install the logical handler.
std::optional<LogicalErrorHandler> LEH;
- if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
+ if (FP.enableLogicalErrors) {
LEH.emplace(S);
AC.getCFGBuildOptions().Observer = &*LEH;
}
@@ -3250,11 +3289,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
Analyzer.run(AC);
}
- if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) ||
- !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) ||
- !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) ||
- !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc()) ||
- !Diags.isIgnored(diag::warn_uninit_const_pointer, D->getBeginLoc())) {
+ if (FP.enableUninitializedAnalysis) {
if (CFG *cfg = AC.getCFG()) {
UninitValsDiagReporter reporter(S);
UninitVariablesAnalysisStats stats;
@@ -3295,10 +3330,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
}
}
- bool FallThroughDiagFull =
- !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getBeginLoc());
- bool FallThroughDiagPerFunction = !Diags.isIgnored(
- diag::warn_unannotated_fallthrough_per_function, D->getBeginLoc());
+ bool FallThroughDiagFull = FP.enableFallthroughFull;
+ bool FallThroughDiagPerFunction = FP.enableFallthroughPerFunction;
if (FallThroughDiagFull || FallThroughDiagPerFunction ||
fscope->HasFallthroughStmt) {
DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
@@ -3310,22 +3343,21 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
// Check for infinite self-recursion in functions
- if (!Diags.isIgnored(diag::warn_infinite_recursive_function,
- D->getBeginLoc())) {
+ if (FP.enableInfiniteRecursion) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
checkRecursiveFunction(S, FD, Body, AC);
}
}
// Check for throw out of non-throwing function.
- if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc()))
+ if (FP.enableThrowInNoexcept)
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD))
checkThrowInNonThrowingFunc(S, FD, AC);
// If none of the previous checks caused a CFG build, trigger one here
// for the logical error handler.
- if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
+ if (FP.enableLogicalErrors) {
AC.getCFG();
}
More information about the cfe-commits
mailing list