[clang] [clang] Extend -Wunused-but-set-variable to static globals (PR #178342)
John Paul Jepko via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 2 17:52:22 PST 2026
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 <john.jepko at ericsson.com>
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 <john.jepko at ericsson.com>
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 <john.jepko at ericsson.com>
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 <john.jepko at ericsson.com>
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 <john.jepko at ericsson.com>
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 <john.jepko at ericsson.com>
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 {
More information about the cfe-commits
mailing list