[clang] Control analysis-based diagnostics with #pragma (PR #136323)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 23 08:01:55 PDT 2025


AaronBallman wrote:

> > FYI this introduces some overhead: https://llvm-compile-time-tracker.com/compare.php?from=2a9f77f6bd48d757b2d45aadcb6cf76ef4b4ef32&to=71ce9e26aec00e4af27a69ccfab8ca1773ed7018&stat=instructions:u About 0.3% on clang files.
> 
> Thank you for the notification! Shoot. I'm not certain if there's a better way to do this or if this is just the cost of doing business, but that is unfortunate.

I tried a different approach:
```
diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h
index 4103c3f006a8..32bfddec9894 100644
--- a/clang/include/clang/Sema/AnalysisBasedWarnings.h
+++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h
@@ -58,7 +58,7 @@ private:
   enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 };
   llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD;
 
-  Policy PolicyOverrides;
+  Policy DefaultPolicy, PolicyOverrides;
   void clearOverrides();
 
   /// \name Statistics
@@ -107,8 +107,8 @@ public:
   // Issue warnings that require whole-translation-unit analysis.
   void IssueWarnings(TranslationUnitDecl *D);
 
-  // Gets the default policy which is in effect at the given source location.
-  Policy getPolicyInEffectAt(SourceLocation Loc);
+  // Gets the policy which is currently in effect.
+  Policy getPolicyInEffect() const;
 
   // Get the policies we may want to override due to things like #pragma clang
   // diagnostic handling. If a caller sets any of these policies to true, that
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 2418aaf8de8e..8726389f43f1 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2493,9 +2493,8 @@ public:
 };
 
 template <typename... Ts>
-static bool areAnyEnabled(DiagnosticsEngine &D, SourceLocation Loc,
-                          Ts... Diags) {
-  return (!D.isIgnored(Diags, Loc) || ...);
+static bool areAnyGloballyEnabled(DiagnosticsEngine &D, Ts... Diags) {
+  return (!D.isIgnored(Diags, {}) || ...);
 }
 
 sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
@@ -2505,29 +2504,35 @@ sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
       NumUninitAnalysisVariables(0), MaxUninitAnalysisVariablesPerFunction(0),
       NumUninitAnalysisBlockVisits(0),
       MaxUninitAnalysisBlockVisitsPerFunction(0) {
+  using namespace diag;
+  DiagnosticsEngine &D = S.getDiagnostics();
+  // Note: The enabled checks should be kept in sync with the switch in
+  // SemaPPCallbacks::PragmaDiagnostic().
+  DefaultPolicy.enableCheckUnreachable = areAnyGloballyEnabled(
+      D, warn_unreachable, warn_unreachable_break, warn_unreachable_return,
+      warn_unreachable_loop_increment);
+
+  DefaultPolicy.enableThreadSafetyAnalysis =
+      areAnyGloballyEnabled(D, warn_double_lock);
+
+  DefaultPolicy.enableConsumedAnalysis =
+      areAnyGloballyEnabled(D, warn_use_in_invalid_state);
 }
 
 // We need this here for unique_ptr with forward declared class.
 sema::AnalysisBasedWarnings::~AnalysisBasedWarnings() = default;
 
 sema::AnalysisBasedWarnings::Policy
-sema::AnalysisBasedWarnings::getPolicyInEffectAt(SourceLocation Loc) {
-  using namespace diag;
-  DiagnosticsEngine &D = S.getDiagnostics();
+sema::AnalysisBasedWarnings::getPolicyInEffect() const {
   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.enableCheckUnreachable = PolicyOverrides.enableCheckUnreachable ||
+                             DefaultPolicy.enableCheckUnreachable;
 
   P.enableThreadSafetyAnalysis = PolicyOverrides.enableThreadSafetyAnalysis ||
-                                 areAnyEnabled(D, Loc, warn_double_lock);
+                                 DefaultPolicy.enableThreadSafetyAnalysis;
 
   P.enableConsumedAnalysis = PolicyOverrides.enableConsumedAnalysis ||
-                             areAnyEnabled(D, Loc, warn_use_in_invalid_state);
+                             DefaultPolicy.enableConsumedAnalysis;
   return P;
 }
 
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 4039601612c6..5c0c17cfa5e4 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -219,7 +219,7 @@ public:
 
     for (diag::kind K : GroupDiags) {
       // Note: the cases in this switch should be kept in sync with the
-      // diagnostics in AnalysisBasedWarnings::getPolicyInEffectAt().
+      // diagnostics in the AnalysisBasedWarnings constructor.
       AnalysisBasedWarnings::Policy &Override =
           S->AnalysisWarnings.getPolicyOverrides();
       switch (K) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d28a2107d58a..372ea1cfd29c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16150,13 +16150,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
   if (FSI->UsesFPIntrin && FD && !FD->hasAttr<StrictFPAttr>())
     FD->addAttr(StrictFPAttr::CreateImplicit(Context));
 
-  SourceLocation AnalysisLoc;
-  if (Body)
-    AnalysisLoc = Body->getEndLoc();
-  else if (FD)
-    AnalysisLoc = FD->getEndLoc();
-  sema::AnalysisBasedWarnings::Policy WP =
-      AnalysisWarnings.getPolicyInEffectAt(AnalysisLoc);
+  sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getPolicyInEffect();
   sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
 
   // If we skip function body, we can't tell if a function is a coroutine.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2e6ce17f8bf9..6b8d1274969c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -16597,8 +16597,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
   BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0);
 
   // Pop the block scope now but keep it alive to the end of this function.
-  AnalysisBasedWarnings::Policy WP =
-      AnalysisWarnings.getPolicyInEffectAt(Body->getEndLoc());
+  AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getPolicyInEffect();
   PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy);
 
   BlockExpr *Result = new (Context)
```
but this causes test case failures. We process the pragma when we consume the closing `}` from a preceding function body. Without checking for the diagnostic being enabled at a particular source location, we'll fail to catch the diagnostic here:
```
int a() {	
  Linear l;
  return 0; // No -Wconsumed diagnostic, analysis is not enabled.
}

#pragma clang diagnostic push
#pragma clang diagnostic error "-Wconsumed"
int b() {
  Linear l;
  return 0;  // expected-error {{invalid invocation of method '~Linear' on object 'l' while it is in the 'unconsumed' state}}
}
#pragma clang diagnostic pop
```
because we set the override at the end of `a`, reset the override at the end of `a`, and then miss that it's enabled at the end of `b`.

https://github.com/llvm/llvm-project/pull/136323


More information about the cfe-commits mailing list