https://github.com/jpjepko updated 
https://github.com/llvm/llvm-project/pull/178342

>From abb706af37605b5e8d664882d996e307aa2994cf Mon Sep 17 00:00:00 2001
From: John Jepko <[email protected]>
Date: Wed, 28 Jan 2026 02:37:45 +0100
Subject: [PATCH 1/6] [clang] Extend -Wunused-but-set-variable to static
 globals

This change extends -Wunused-but-set-variable to diagnose static globals
within the translation unit that are assigned to within function bodies,
but whose values are never used.

Fixes #148361
---
 clang/lib/Sema/Sema.cpp                       | 32 +++++++
 clang/lib/Sema/SemaExpr.cpp                   |  6 +-
 clang/test/C/C2y/n3622.c                      |  8 +-
 .../Sema/warn-unused-but-set-static-global.c  | 84 +++++++++++++++++++
 4 files changed, 125 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/Sema/warn-unused-but-set-static-global.c

diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index d53527af38653..a533593f25c59 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1620,6 +1620,38 @@ void Sema::ActOnEndOfTranslationUnit() {
   if (Context.hasAnyFunctionEffects())
     performFunctionEffectAnalysis(Context.getTranslationUnitDecl());
 
+  // diagnose unused-but-set static globals in a deterministic order
+  //
+  // not trackings shadowing info for static globals; there's nothing to shadow
+  struct LocAndDiag {
+    SourceLocation Loc;
+    PartialDiagnostic PD;
+  };
+  SmallVector<LocAndDiag, 16> DeclDiags;
+  auto addDiag = [&DeclDiags](SourceLocation Loc, PartialDiagnostic PD) {
+    DeclDiags.push_back(LocAndDiag{Loc, std::move(PD)});
+  };
+
+  // for -Wunused-but-set-variable we only care about variables that were
+  // referenced by the TU end
+  for (const auto &Ref : RefsMinusAssignments) {
+    const VarDecl *VD = Ref.first;
+    if (VD->isFileVarDecl() && VD->getStorageClass() == SC_Static) {
+      DiagnoseUnusedButSetDecl(VD, addDiag);
+      RefsMinusAssignments.erase(VD);
+    }
+  }
+
+  llvm::sort(DeclDiags,
+             [](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool {
+               // sorting purely for determinism; matches behavior in
+               // SemaDecl.cpp
+               return LHS.Loc.getRawEncoding() < RHS.Loc.getRawEncoding();
+             });
+  for (const LocAndDiag &D : DeclDiags) {
+    Diag(D.Loc, D.PD);
+  }
+
   // Check we've noticed that we're no longer parsing the initializer for every
   // variable. If we miss cases, then at best we have a performance issue and
   // at worst a rejects-valid bug.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5795a71b5cae8..46434ce1511e5 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -20257,7 +20257,11 @@ static void DoMarkVarDeclReferenced(
   bool UsableInConstantExpr =
       Var->mightBeUsableInConstantExpressions(SemaRef.Context);
 
-  if (Var->isLocalVarDeclOrParm() && !Var->hasExternalStorage()) {
+  bool StaticGlobalReferenced = Var->isFileVarDecl() &&
+                                Var->getStorageClass() == SC_Static &&
+                                !Var->isStaticDataMember();
+  if ((Var->isLocalVarDeclOrParm() || StaticGlobalReferenced) &&
+      !Var->hasExternalStorage()) {
     RefsMinusAssignments.insert({Var, 0}).first->getSecond()++;
   }
 
diff --git a/clang/test/C/C2y/n3622.c b/clang/test/C/C2y/n3622.c
index 95b92e8f235a8..d90b0c51d3ccf 100644
--- a/clang/test/C/C2y/n3622.c
+++ b/clang/test/C/C2y/n3622.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -verify=good -pedantic -Wall -std=c2y %s
-// RUN: %clang_cc1 -verify=compat,expected -pedantic -Wall -Wpre-c2y-compat 
-std=c2y %s
-// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall -std=c23 %s
-// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall -std=c17 %s
+// RUN: %clang_cc1 -verify=good -pedantic -Wall -Wno-unused-but-set-variable 
-std=c2y %s
+// RUN: %clang_cc1 -verify=compat,expected -pedantic -Wall 
-Wno-unused-but-set-variable -Wpre-c2y-compat -std=c2y %s
+// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall 
-Wno-unused-but-set-variable -std=c23 %s
+// RUN: %clang_cc1 -verify=ped,expected -pedantic -Wall 
-Wno-unused-but-set-variable -std=c17 %s
 // good-no-diagnostics
 
 /* WG14 N3622: Clang 22
diff --git a/clang/test/Sema/warn-unused-but-set-static-global.c 
b/clang/test/Sema/warn-unused-but-set-static-global.c
new file mode 100644
index 0000000000000..a68136749047d
--- /dev/null
+++ b/clang/test/Sema/warn-unused-but-set-static-global.c
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-but-set-variable -verify %s
+
+static int set_unused; // expected-warning {{variable 'set_unused' set but not 
used}}
+static int set_and_used;
+static int only_used;
+static int addr_taken;
+extern int external_var;  // no warning (external linkage)
+extern int global_var;  // no warning (not static)
+
+void f1() {
+  set_unused = 1;
+  set_and_used = 2;
+
+  int x = set_and_used;
+  (void)x;
+
+  int y = only_used;
+  (void)y;
+
+  int *p = &addr_taken;
+  (void)p;
+
+  external_var = 3;
+  global_var = 4;
+}
+
+// test across multiple functions
+static int set_used1;
+static int set_used2;
+
+static int set1; // expected-warning {{variable 'set1' set but not used}}
+static int set2; // expected-warning {{variable 'set2' set but not used}}
+
+void f2() {
+  set1 = 1;
+  set_used1 = 1;
+
+  int x = set_used2;
+  (void)x;
+}
+
+void f3() {
+  set2 = 2;
+  set_used2 = 2;
+
+  int x = set_used1;
+  (void)x;
+}
+
+static volatile int vol_set; // expected-warning {{variable 'vol_set' set but 
not used}}
+void f4() {
+  vol_set = 1;
+}
+
+// read and use
+static int compound; // expected-warning{{variable 'compound' set but not 
used}}
+static volatile int vol_compound;
+static int unary; // expected-warning{{variable 'unary' set but not used}}
+static volatile int vol_unary;
+void f5() {
+  compound += 1;
+  vol_compound += 1;
+  unary++;
+  vol_unary++;
+}
+
+struct S {
+  int i;
+};
+static struct S s_set;  // expected-warning{{variable 's_set' set but not 
used}}
+static struct S s_used;
+void f6() {
+  struct S t;
+  s_set = t;
+  t = s_used;
+}
+
+// multiple assignments
+static int multi; // expected-warning{{variable 'multi' set but not used}}
+void f7() {
+  multi = 1;
+  multi = 2;
+  multi = 3;
+}

>From ca8f1b1da932dfe12a4f1ed5e3b73a4610c8843e Mon Sep 17 00:00:00 2001
From: John Jepko <[email protected]>
Date: Wed, 28 Jan 2026 18:32:20 +0100
Subject: [PATCH 2/6] fix function ptr and namespace issues, add tests

---
 clang/lib/Sema/SemaExpr.cpp                   |  6 ++--
 .../Sema/warn-unused-but-set-static-global.c  | 35 +++++++++++++++++++
 .../warn-unused-but-set-static-global.cpp     | 28 +++++++++++++++
 3 files changed, 66 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/Sema/warn-unused-but-set-static-global.cpp

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 46434ce1511e5..0c29bb40fe6e7 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -20257,9 +20257,9 @@ static void DoMarkVarDeclReferenced(
   bool UsableInConstantExpr =
       Var->mightBeUsableInConstantExpressions(SemaRef.Context);
 
-  bool StaticGlobalReferenced = Var->isFileVarDecl() &&
-                                Var->getStorageClass() == SC_Static &&
-                                !Var->isStaticDataMember();
+  bool StaticGlobalReferenced =
+      Var->isFileVarDecl() && Var->getStorageClass() == SC_Static &&
+      !Var->isStaticDataMember() && !Var->getType()->isFunctionPointerType();
   if ((Var->isLocalVarDeclOrParm() || StaticGlobalReferenced) &&
       !Var->hasExternalStorage()) {
     RefsMinusAssignments.insert({Var, 0}).first->getSecond()++;
diff --git a/clang/test/Sema/warn-unused-but-set-static-global.c 
b/clang/test/Sema/warn-unused-but-set-static-global.c
index a68136749047d..406b9af116646 100644
--- a/clang/test/Sema/warn-unused-but-set-static-global.c
+++ b/clang/test/Sema/warn-unused-but-set-static-global.c
@@ -1,5 +1,10 @@
 // RUN: %clang_cc1 -fsyntax-only -Wunused-but-set-variable -verify %s
 
+#define NULL (void*)0
+
+void *set(int size);
+void func_call(void *);
+
 static int set_unused; // expected-warning {{variable 'set_unused' set but not 
used}}
 static int set_and_used;
 static int only_used;
@@ -82,3 +87,33 @@ void f7() {
   multi = 2;
   multi = 3;
 }
+
+// unused pointers
+static int *unused_ptr; // expected-warning{{variable 'unused_ptr' set but not 
used}}
+static char *str_ptr; // expected-warning{{variable 'str_ptr' set but not 
used}}
+void f8() {
+  unused_ptr = set(5);
+  str_ptr = "hello";
+}
+
+// used pointers
+void a(void *);
+static int *used_ptr;
+static int *param_ptr;
+static int *null_check_ptr;
+void f9() {
+  used_ptr = set(5);
+  *used_ptr = 5;
+
+  param_ptr = set(5);
+  func_call(param_ptr);
+
+  null_check_ptr = set(5);
+  if (null_check_ptr == NULL) {}
+}
+
+// function pointers
+static void (*sandboxing_callback)();
+void SetSandboxingCallback(void (*f)()) {
+  sandboxing_callback = f;
+}
diff --git a/clang/test/Sema/warn-unused-but-set-static-global.cpp 
b/clang/test/Sema/warn-unused-but-set-static-global.cpp
new file mode 100644
index 0000000000000..ead7599d6cc78
--- /dev/null
+++ b/clang/test/Sema/warn-unused-but-set-static-global.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-but-set-variable -verify -std=c++11 
%s
+
+namespace test {
+  static int set_unused;  // expected-warning {{variable 'set_unused' set but 
not used}}
+  static int set_and_used;
+
+  void f1() {
+    set_unused = 1;
+    set_and_used = 2;
+    int x = set_and_used;
+    (void)x;
+  }
+
+  // function pointer in namespace
+  static void (*sandboxing_callback)();
+  void SetSandboxingCallback(void (*f)()) {
+    sandboxing_callback = f;
+  }
+}
+
+namespace outer {
+namespace inner {
+static int nested_unused; // expected-warning {{variable 'nested_unused' set 
but not used}}
+void f2() {
+  nested_unused = 5;
+}
+}
+}

>From 68a66bfeefbae121948d15a8c6ef58d21b962cfe Mon Sep 17 00:00:00 2001
From: John Jepko <[email protected]>
Date: Thu, 29 Jan 2026 21:56:23 +0100
Subject: [PATCH 3/6] ensure static globals only diagnosed at end of TU

---
 clang/lib/Sema/SemaDecl.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 907b7b367f19b..2b9218db95355 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2294,8 +2294,13 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
       if (const auto *RD = dyn_cast<RecordDecl>(D))
         DiagnoseUnusedNestedTypedefs(RD, addDiag);
       if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
-        DiagnoseUnusedButSetDecl(VD, addDiag);
-        RefsMinusAssignments.erase(VD);
+        // wait until end of TU to diagnose static globals
+        bool isStaticGlobal =
+            VD->isFileVarDecl() && VD->getStorageClass() == SC_Static;
+        if (!isStaticGlobal) {
+          DiagnoseUnusedButSetDecl(VD, addDiag);
+          RefsMinusAssignments.erase(VD);
+        }
       }
     }
 

>From c06baa6cdf50a4a080c2a8570f91732ca15d02c2 Mon Sep 17 00:00:00 2001
From: John Jepko <[email protected]>
Date: Mon, 2 Feb 2026 23:05:06 +0100
Subject: [PATCH 4/6] skip header-defined static globals, add tests and
 refactor

---
 clang/include/clang/AST/Decl.h                            | 5 +++++
 clang/lib/Sema/Sema.cpp                                   | 4 +++-
 clang/lib/Sema/SemaDecl.cpp                               | 4 +---
 clang/lib/Sema/SemaExpr.cpp                               | 8 ++++----
 .../warn-unused-but-set-static-global-header-test.c       | 3 +++
 .../Inputs/warn-unused-but-set-static-global-header.h     | 3 +++
 clang/test/Sema/warn-unused-but-set-static-global.c       | 1 +
 7 files changed, 20 insertions(+), 8 deletions(-)
 create mode 100644 
clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c
 create mode 100644 
clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 5c46c912186c4..3040514ab7dad 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1212,6 +1212,11 @@ class VarDecl : public DeclaratorDecl, public 
Redeclarable<VarDecl> {
       && !isFileVarDecl();
   }
 
+  /// Returns true if a variable is a static file-scope variable.
+  bool isStaticFileVar() const {
+    return isFileVarDecl() && getStorageClass() == SC_Static;
+  }
+
   /// Returns true if a variable has extern or __private_extern__
   /// storage.
   bool hasExternalStorage() const {
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index a533593f25c59..4266d073f358e 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1636,7 +1636,9 @@ void Sema::ActOnEndOfTranslationUnit() {
   // referenced by the TU end
   for (const auto &Ref : RefsMinusAssignments) {
     const VarDecl *VD = Ref.first;
-    if (VD->isFileVarDecl() && VD->getStorageClass() == SC_Static) {
+    // only diagnose static file vars defined in the main file to match
+    // -Wunused-variable behavior and avoid false positives from header vars
+    if (VD->isStaticFileVar() && SourceMgr.isInMainFile(VD->getLocation())) {
       DiagnoseUnusedButSetDecl(VD, addDiag);
       RefsMinusAssignments.erase(VD);
     }
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2b9218db95355..b86bff897289a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2295,9 +2295,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
         DiagnoseUnusedNestedTypedefs(RD, addDiag);
       if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
         // wait until end of TU to diagnose static globals
-        bool isStaticGlobal =
-            VD->isFileVarDecl() && VD->getStorageClass() == SC_Static;
-        if (!isStaticGlobal) {
+        if (!VD->isStaticFileVar()) {
           DiagnoseUnusedButSetDecl(VD, addDiag);
           RefsMinusAssignments.erase(VD);
         }
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0c29bb40fe6e7..d03f6cf4636e0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -20257,10 +20257,10 @@ static void DoMarkVarDeclReferenced(
   bool UsableInConstantExpr =
       Var->mightBeUsableInConstantExpressions(SemaRef.Context);
 
-  bool StaticGlobalReferenced =
-      Var->isFileVarDecl() && Var->getStorageClass() == SC_Static &&
-      !Var->isStaticDataMember() && !Var->getType()->isFunctionPointerType();
-  if ((Var->isLocalVarDeclOrParm() || StaticGlobalReferenced) &&
+  bool ShouldTrackForUnusedButSet = Var->isStaticFileVar() &&
+                                    !Var->isStaticDataMember() &&
+                                    !Var->getType()->isFunctionPointerType();
+  if ((Var->isLocalVarDeclOrParm() || ShouldTrackForUnusedButSet) &&
       !Var->hasExternalStorage()) {
     RefsMinusAssignments.insert({Var, 0}).first->getSecond()++;
   }
diff --git 
a/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c 
b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c
new file mode 100644
index 0000000000000..e4c316b37d15f
--- /dev/null
+++ b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c
@@ -0,0 +1,3 @@
+// expected-no-diagnostics
+// test that header-defined static globals don't warn
+#include "warn-unused-but-set-static-global-header.h"
diff --git a/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h 
b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h
new file mode 100644
index 0000000000000..a06e9e66a34f4
--- /dev/null
+++ b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h
@@ -0,0 +1,3 @@
+// header file for testing that header-defined static globals don't warn
+static int header_set_unused = 0;
+static void header_init() { header_set_unused = 1; }
diff --git a/clang/test/Sema/warn-unused-but-set-static-global.c 
b/clang/test/Sema/warn-unused-but-set-static-global.c
index 406b9af116646..bf099d3c5759c 100644
--- a/clang/test/Sema/warn-unused-but-set-static-global.c
+++ b/clang/test/Sema/warn-unused-but-set-static-global.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wunused-but-set-variable -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-but-set-variable -I %S -verify 
%S/Inputs/warn-unused-but-set-static-global-header-test.c
 
 #define NULL (void*)0
 

>From 44c2f6f464094b547a04a66958fb2cac4e570bc8 Mon Sep 17 00:00:00 2001
From: John Jepko <[email protected]>
Date: Tue, 3 Feb 2026 01:43:14 +0100
Subject: [PATCH 5/6] fix comment formatting

---
 clang/lib/Sema/Sema.cpp                         | 17 ++++++++---------
 clang/lib/Sema/SemaDecl.cpp                     |  2 +-
 ...n-unused-but-set-static-global-header-test.c |  2 +-
 .../warn-unused-but-set-static-global-header.h  |  2 +-
 .../Sema/warn-unused-but-set-static-global.c    | 16 ++++++++--------
 .../Sema/warn-unused-but-set-static-global.cpp  |  2 +-
 6 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 4266d073f358e..0f0a749701615 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1620,9 +1620,8 @@ void Sema::ActOnEndOfTranslationUnit() {
   if (Context.hasAnyFunctionEffects())
     performFunctionEffectAnalysis(Context.getTranslationUnitDecl());
 
-  // diagnose unused-but-set static globals in a deterministic order
-  //
-  // not trackings shadowing info for static globals; there's nothing to shadow
+  // Diagnose unused-but-set static globals in a deterministic order.
+  // Not tracking shadowing info for static globals; there's nothing to shadow.
   struct LocAndDiag {
     SourceLocation Loc;
     PartialDiagnostic PD;
@@ -1632,12 +1631,12 @@ void Sema::ActOnEndOfTranslationUnit() {
     DeclDiags.push_back(LocAndDiag{Loc, std::move(PD)});
   };
 
-  // for -Wunused-but-set-variable we only care about variables that were
-  // referenced by the TU end
+  // For -Wunused-but-set-variable we only care about variables that were
+  // referenced by the TU end.
   for (const auto &Ref : RefsMinusAssignments) {
     const VarDecl *VD = Ref.first;
-    // only diagnose static file vars defined in the main file to match
-    // -Wunused-variable behavior and avoid false positives from header vars
+    // Only diagnose static file vars defined in the main file to match
+    // -Wunused-variable behavior and avoid false positives from header vars.
     if (VD->isStaticFileVar() && SourceMgr.isInMainFile(VD->getLocation())) {
       DiagnoseUnusedButSetDecl(VD, addDiag);
       RefsMinusAssignments.erase(VD);
@@ -1646,8 +1645,8 @@ void Sema::ActOnEndOfTranslationUnit() {
 
   llvm::sort(DeclDiags,
              [](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool {
-               // sorting purely for determinism; matches behavior in
-               // SemaDecl.cpp
+               // Sorting purely for determinism; matches behavior in
+               // SemaDecl.cpp.
                return LHS.Loc.getRawEncoding() < RHS.Loc.getRawEncoding();
              });
   for (const LocAndDiag &D : DeclDiags) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b86bff897289a..82f56b60aef65 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2294,7 +2294,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
       if (const auto *RD = dyn_cast<RecordDecl>(D))
         DiagnoseUnusedNestedTypedefs(RD, addDiag);
       if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
-        // wait until end of TU to diagnose static globals
+        // Wait until end of TU to diagnose static globals.
         if (!VD->isStaticFileVar()) {
           DiagnoseUnusedButSetDecl(VD, addDiag);
           RefsMinusAssignments.erase(VD);
diff --git 
a/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c 
b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c
index e4c316b37d15f..f26c90733a2bd 100644
--- a/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c
+++ b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header-test.c
@@ -1,3 +1,3 @@
 // expected-no-diagnostics
-// test that header-defined static globals don't warn
+// Test that header-defined static globals don't warn.
 #include "warn-unused-but-set-static-global-header.h"
diff --git a/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h 
b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h
index a06e9e66a34f4..40637d644f717 100644
--- a/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h
+++ b/clang/test/Sema/Inputs/warn-unused-but-set-static-global-header.h
@@ -1,3 +1,3 @@
-// header file for testing that header-defined static globals don't warn
+// Header file for testing that header-defined static globals don't warn.
 static int header_set_unused = 0;
 static void header_init() { header_set_unused = 1; }
diff --git a/clang/test/Sema/warn-unused-but-set-static-global.c 
b/clang/test/Sema/warn-unused-but-set-static-global.c
index bf099d3c5759c..12679a4de8a34 100644
--- a/clang/test/Sema/warn-unused-but-set-static-global.c
+++ b/clang/test/Sema/warn-unused-but-set-static-global.c
@@ -10,8 +10,8 @@ static int set_unused; // expected-warning {{variable 
'set_unused' set but not u
 static int set_and_used;
 static int only_used;
 static int addr_taken;
-extern int external_var;  // no warning (external linkage)
-extern int global_var;  // no warning (not static)
+extern int external_var;  // No warning (external linkage).
+extern int global_var;  // No warning (not static).
 
 void f1() {
   set_unused = 1;
@@ -30,7 +30,7 @@ void f1() {
   global_var = 4;
 }
 
-// test across multiple functions
+// Test across multiple functions.
 static int set_used1;
 static int set_used2;
 
@@ -58,7 +58,7 @@ void f4() {
   vol_set = 1;
 }
 
-// read and use
+// Read and use
 static int compound; // expected-warning{{variable 'compound' set but not 
used}}
 static volatile int vol_compound;
 static int unary; // expected-warning{{variable 'unary' set but not used}}
@@ -81,7 +81,7 @@ void f6() {
   t = s_used;
 }
 
-// multiple assignments
+// Multiple assignments
 static int multi; // expected-warning{{variable 'multi' set but not used}}
 void f7() {
   multi = 1;
@@ -89,7 +89,7 @@ void f7() {
   multi = 3;
 }
 
-// unused pointers
+// Unused pointers
 static int *unused_ptr; // expected-warning{{variable 'unused_ptr' set but not 
used}}
 static char *str_ptr; // expected-warning{{variable 'str_ptr' set but not 
used}}
 void f8() {
@@ -97,7 +97,7 @@ void f8() {
   str_ptr = "hello";
 }
 
-// used pointers
+// Used pointers
 void a(void *);
 static int *used_ptr;
 static int *param_ptr;
@@ -113,7 +113,7 @@ void f9() {
   if (null_check_ptr == NULL) {}
 }
 
-// function pointers
+// Function pointers
 static void (*sandboxing_callback)();
 void SetSandboxingCallback(void (*f)()) {
   sandboxing_callback = f;
diff --git a/clang/test/Sema/warn-unused-but-set-static-global.cpp 
b/clang/test/Sema/warn-unused-but-set-static-global.cpp
index ead7599d6cc78..66d20bc242ca0 100644
--- a/clang/test/Sema/warn-unused-but-set-static-global.cpp
+++ b/clang/test/Sema/warn-unused-but-set-static-global.cpp
@@ -11,7 +11,7 @@ namespace test {
     (void)x;
   }
 
-  // function pointer in namespace
+  // Function pointer in namespace.
   static void (*sandboxing_callback)();
   void SetSandboxingCallback(void (*f)()) {
     sandboxing_callback = f;

>From 0c837b08d43e2e47194e27013f0471c7de167285 Mon Sep 17 00:00:00 2001
From: John Jepko <[email protected]>
Date: Tue, 3 Feb 2026 02:10:11 +0100
Subject: [PATCH 6/6] wait after iterating to erase decls

---
 clang/lib/Sema/Sema.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 0f0a749701615..86770549b9369 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1633,15 +1633,19 @@ void Sema::ActOnEndOfTranslationUnit() {
 
   // For -Wunused-but-set-variable we only care about variables that were
   // referenced by the TU end.
+  SmallVector<const VarDecl *, 16> DeclsToErase;
   for (const auto &Ref : RefsMinusAssignments) {
     const VarDecl *VD = Ref.first;
     // Only diagnose static file vars defined in the main file to match
     // -Wunused-variable behavior and avoid false positives from header vars.
     if (VD->isStaticFileVar() && SourceMgr.isInMainFile(VD->getLocation())) {
       DiagnoseUnusedButSetDecl(VD, addDiag);
-      RefsMinusAssignments.erase(VD);
+      DeclsToErase.push_back(VD);
     }
   }
+  for (const VarDecl *VD : DeclsToErase) {
+    RefsMinusAssignments.erase(VD);
+  }
 
   llvm::sort(DeclDiags,
              [](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to