[clang] [clang] Cache the analysis-based warning policy in effect (PR #212213)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 28 07:55:25 PDT 2026
https://github.com/AnonMiraj updated https://github.com/llvm/llvm-project/pull/212213
>From a61503b54e9568254885777cf89f5ca1586ec99f Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Mon, 27 Jul 2026 11:56:36 +0300
Subject: [PATCH 1/2] [clang] Cache the analysis-based warning policy in effect
---
clang/include/clang/Basic/Diagnostic.h | 11 +++++
.../clang/Sema/AnalysisBasedWarnings.h | 7 +++
clang/lib/Sema/AnalysisBasedWarnings.cpp | 46 +++++++++++++++++--
clang/lib/Sema/Sema.cpp | 4 ++
4 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index 826b747f2c751..18cbd34c29ce5 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -583,6 +583,17 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
DiagSuppressionMapping;
public:
+ /// Returns a cache key representing the diagnostic state at \p Loc.
+ const void *getDiagStateKeyForLoc(SourceLocation Loc) const {
+ return GetDiagStateForLoc(Loc);
+ }
+
+ /// True if an active diagnostic suppression mapping makes severity dependent
+ /// on the file path.
+ bool hasDiagSuppressionMapping() const {
+ return static_cast<bool>(DiagSuppressionMapping);
+ }
+
explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
DiagnosticOptions &DiagOpts,
DiagnosticConsumer *client = nullptr,
diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h
index 0ed61e56825be..c79e72bf3037f 100644
--- a/clang/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h
@@ -66,6 +66,10 @@ class AnalysisBasedWarnings {
Policy PolicyOverrides;
void clearOverrides();
+ /// Caches results for getPolicyInEffectAt().
+ /// Flushed whenever a diagnostic pragma changes severities.
+ llvm::DenseMap<const void *, Policy> PolicyCache[4];
+
/// \name Statistics
/// @{
@@ -129,6 +133,9 @@ class AnalysisBasedWarnings {
// will override the policy used to issue warnings.
Policy &getPolicyOverrides() { return PolicyOverrides; }
+ /// Drop cached getPolicyInEffectAt() results (diagnostic state changed).
+ void clearPolicyCache();
+
void PrintStats() const;
};
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index e070d9f1a9b85..f0674f80a825c 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2759,23 +2759,59 @@ sema::AnalysisBasedWarnings::Policy
sema::AnalysisBasedWarnings::getPolicyInEffectAt(SourceLocation Loc) {
using namespace diag;
DiagnosticsEngine &D = S.getDiagnostics();
+
+ // This runs at the end of every function definition, and the checks below
+ // resolve Loc against the pragma diagnostic state (and system header/macro
+ // classification) once per queried diagnostic. Those inputs fully determine
+ // the result, so cache the policy on them instead (PolicyOverrides are
+ // transient per-function state and are applied after the cache lookup).
+ const bool Cacheable = !D.hasDiagSuppressionMapping();
+ const void *StateKey = nullptr;
+ unsigned SysIdx = 0;
+ if (Cacheable) {
+ StateKey = D.getDiagStateKeyForLoc(Loc);
+ if (Loc.isValid() && D.hasSourceManager()) {
+ const SourceManager &SM = D.getSourceManager();
+ SysIdx = (SM.isInSystemHeader(SM.getExpansionLoc(Loc)) ? 2u : 0u) |
+ (SM.isInSystemMacro(Loc) ? 1u : 0u);
+ }
+ auto It = PolicyCache[SysIdx].find(StateKey);
+ if (It != PolicyCache[SysIdx].end()) {
+ Policy P = It->second;
+ P.enableCheckUnreachable |= PolicyOverrides.enableCheckUnreachable;
+ P.enableThreadSafetyAnalysis |=
+ PolicyOverrides.enableThreadSafetyAnalysis;
+ P.enableConsumedAnalysis |= PolicyOverrides.enableConsumedAnalysis;
+ return P;
+ }
+ }
+
Policy P;
// Note: The enabled checks should be kept in sync with the switch in
// SemaPPCallbacks::PragmaDiagnostic().
P.enableCheckUnreachable =
- PolicyOverrides.enableCheckUnreachable ||
areAnyEnabled(D, Loc, warn_unreachable, warn_unreachable_break,
warn_unreachable_return, warn_unreachable_loop_increment);
- P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
- areAnyEnabled(D, Loc, warn_double_lock);
+ P.enableThreadSafetyAnalysis = areAnyEnabled(D, Loc, warn_double_lock);
- P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
- areAnyEnabled(D, Loc, warn_use_in_invalid_state);
+ P.enableConsumedAnalysis = areAnyEnabled(D, Loc, warn_use_in_invalid_state);
+
+ if (Cacheable)
+ PolicyCache[SysIdx][StateKey] = P;
+
+ P.enableCheckUnreachable |= PolicyOverrides.enableCheckUnreachable;
+ P.enableThreadSafetyAnalysis |= PolicyOverrides.enableThreadSafetyAnalysis;
+ P.enableConsumedAnalysis |= PolicyOverrides.enableConsumedAnalysis;
return P;
}
+void sema::AnalysisBasedWarnings::clearPolicyCache() {
+ for (auto &M : PolicyCache)
+ M.clear();
+}
+
void sema::AnalysisBasedWarnings::clearOverrides() {
PolicyOverrides.enableCheckUnreachable = false;
PolicyOverrides.enableConsumedAnalysis = false;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 78fbc9e31842d..322ae410ed6cd 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -227,6 +227,10 @@ class SemaPPCallbacks : public PPCallbacks {
}
void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace,
diag::Severity Mapping, StringRef Str) override {
+ // The pragma changed diagnostic severities; drop any cached analysis
+ // warning policies derived from the previous state.
+ S->AnalysisWarnings.clearPolicyCache();
+
// If one of the analysis-based diagnostics was enabled while processing
// a function, we want to note it in the analysis-based warnings so they
// can be run at the end of the function body even if the analysis warnings
>From c5f626c2e6f28160df043263e179f5b257c13249 Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Tue, 28 Jul 2026 10:49:33 +0300
Subject: [PATCH 2/2] Don't cache when SourceLocation is invalid
---
clang/lib/Sema/AnalysisBasedWarnings.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index f0674f80a825c..a70f1b0c77236 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2765,16 +2765,14 @@ sema::AnalysisBasedWarnings::getPolicyInEffectAt(SourceLocation Loc) {
// classification) once per queried diagnostic. Those inputs fully determine
// the result, so cache the policy on them instead (PolicyOverrides are
// transient per-function state and are applied after the cache lookup).
- const bool Cacheable = !D.hasDiagSuppressionMapping();
+ const bool Cacheable = !D.hasDiagSuppressionMapping() && Loc.isValid();
const void *StateKey = nullptr;
unsigned SysIdx = 0;
if (Cacheable) {
StateKey = D.getDiagStateKeyForLoc(Loc);
- if (Loc.isValid() && D.hasSourceManager()) {
- const SourceManager &SM = D.getSourceManager();
- SysIdx = (SM.isInSystemHeader(SM.getExpansionLoc(Loc)) ? 2u : 0u) |
- (SM.isInSystemMacro(Loc) ? 1u : 0u);
- }
+ const SourceManager &SM = D.getSourceManager();
+ SysIdx = (SM.isInSystemHeader(SM.getExpansionLoc(Loc)) ? 2u : 0u) |
+ (SM.isInSystemMacro(Loc) ? 1u : 0u);
auto It = PolicyCache[SysIdx].find(StateKey);
if (It != PolicyCache[SysIdx].end()) {
Policy P = It->second;
More information about the cfe-commits
mailing list