From 6e75b9607ddbf5ad834f1c61089c8eea98d0688f Mon Sep 17 00:00:00 2001 From: jketema <93738568+jketema@users.noreply.github.com> Date: Thu, 29 Oct 2026 10:23:40 +0000 Subject: [PATCH 1/3] Add maybe_unused regression tests for unused-variable queries Cover C++17 maybe_unused local and static variables in the unused-variable query tests. Record the current alerts as spurious so the regression cases pass until the queries account for the standard attribute. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Unused Entities/UnusedLocals/UnusedLocals.expected | 1 + .../Best Practices/Unused Entities/UnusedLocals/code2.cpp | 5 +++++ .../UnusedStaticVariables/UnusedStaticVariables.expected | 1 + .../Unused Entities/UnusedStaticVariables/test.cpp | 3 ++- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected index 8db9fdb3ec64..faa65e4c08fc 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected @@ -6,6 +6,7 @@ | code2.cpp:64:7:64:8 | v3 | Variable v3 is not used. | | code2.cpp:108:11:108:12 | v2 | Variable v2 is not used. | | code2.cpp:128:9:128:9 | b | Variable b is not used. | +| code2.cpp:182:23:182:28 | unused | Variable unused is not used. | | code.c:10:18:10:18 | y | Variable y is not used. | | code.c:11:18:11:18 | z | Variable z is not used. | | code.c:18:7:18:7 | x | Variable x is not used. | diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp index b0e00dc8fbe1..26706ac3c070 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp @@ -176,3 +176,8 @@ void test_switch_initializer() // ... } } + +void test_maybe_unused() +{ + [[maybe_unused]] int unused; // $ SPURIOUS: Alert // GOOD: false positive for maybe_unused +} diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected index 45367233424e..ee99c5ab2f54 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected @@ -2,3 +2,4 @@ | test.cpp:8:12:8:21 | staticVar6 | Static variable staticVar6 is never read. | | test.cpp:10:11:10:19 | constVar8 | Static variable constVar8 is never read. | | test.cpp:12:12:12:22 | staticVar10 | Static variable staticVar10 is never read. | +| test.cpp:13:29:13:39 | staticVar11 | Static variable staticVar11 is never read. | diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp index 3b60a4722d4d..9f910a42cbcc 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp @@ -1,4 +1,4 @@ - +// semmle-extractor-options: -std=c++17 int globalVar; // GOOD (not static) static int staticVar1; // GOOD (used) static int staticVar2; // GOOD (used) @@ -10,6 +10,7 @@ static __attribute__((__unused__)) int staticVar7; // GOOD (unused but this is e const int constVar8 = 8; // $ Alert // BAD (const defaults to static) extern const int constVar9 = 9; // GOOD static int staticVar10 = 10; // $ SPURIOUS: Alert // GOOD [FALSE POSITIVE] (referenced in a never instantiated template) +[[maybe_unused]] static int staticVar11; // $ SPURIOUS: Alert // GOOD (false positive for maybe_unused) void f() { From 24b6e6030b20d9e582658a4d91be8ae357d8ca3e Mon Sep 17 00:00:00 2001 From: jketema <93738568+jketema@users.noreply.github.com> Date: Thu, 29 Oct 2026 10:27:03 +0000 Subject: [PATCH 2/3] Respect maybe_unused in unused-variable queries Exclude variables annotated with the standard maybe_unused attribute from the unused-local and unused-static-variable queries, and update the regression expectations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql | 1 + .../Best Practices/Unused Entities/UnusedStaticVariables.ql | 3 ++- .../Unused Entities/UnusedLocals/UnusedLocals.expected | 1 - .../Best Practices/Unused Entities/UnusedLocals/code2.cpp | 2 +- .../UnusedStaticVariables/UnusedStaticVariables.expected | 1 - .../Unused Entities/UnusedStaticVariables/test.cpp | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql b/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql index 4ba1ad93f565..5239fe5d26ad 100644 --- a/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql +++ b/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql @@ -57,5 +57,6 @@ where not declarationHasSideEffects(v) and not exists(AsmStmt s | f = s.getEnclosingFunction()) and not v.getAnAttribute().getName() = "unused" and + not v.getAnAttribute().getName() = "maybe_unused" and not f.hasErrors() // Unextracted expressions may use `v` select v, "Variable " + v.getName() + " is not used." diff --git a/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql b/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql index 03176b8a7791..dc60d9af92b1 100644 --- a/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql +++ b/cpp/ql/src/Best Practices/Unused Entities/UnusedStaticVariables.ql @@ -26,5 +26,6 @@ where not v instanceof MemberVariable and not declarationHasSideEffects(v) and not v.getAnAttribute().hasName("used") and - not v.getAnAttribute().hasName("unused") + not v.getAnAttribute().hasName("unused") and + not v.getAnAttribute().hasName("maybe_unused") select v, "Static variable " + v.getName() + " is never read." diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected index faa65e4c08fc..8db9fdb3ec64 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/UnusedLocals.expected @@ -6,7 +6,6 @@ | code2.cpp:64:7:64:8 | v3 | Variable v3 is not used. | | code2.cpp:108:11:108:12 | v2 | Variable v2 is not used. | | code2.cpp:128:9:128:9 | b | Variable b is not used. | -| code2.cpp:182:23:182:28 | unused | Variable unused is not used. | | code.c:10:18:10:18 | y | Variable y is not used. | | code.c:11:18:11:18 | z | Variable z is not used. | | code.c:18:7:18:7 | x | Variable x is not used. | diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp index 26706ac3c070..9e92ec37b4cf 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedLocals/code2.cpp @@ -179,5 +179,5 @@ void test_switch_initializer() void test_maybe_unused() { - [[maybe_unused]] int unused; // $ SPURIOUS: Alert // GOOD: false positive for maybe_unused + [[maybe_unused]] int unused; // GOOD: explicitly marked as maybe_unused } diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected index ee99c5ab2f54..45367233424e 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/UnusedStaticVariables.expected @@ -2,4 +2,3 @@ | test.cpp:8:12:8:21 | staticVar6 | Static variable staticVar6 is never read. | | test.cpp:10:11:10:19 | constVar8 | Static variable constVar8 is never read. | | test.cpp:12:12:12:22 | staticVar10 | Static variable staticVar10 is never read. | -| test.cpp:13:29:13:39 | staticVar11 | Static variable staticVar11 is never read. | diff --git a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp index 9f910a42cbcc..0483595ba385 100644 --- a/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp +++ b/cpp/ql/test/query-tests/Best Practices/Unused Entities/UnusedStaticVariables/test.cpp @@ -10,7 +10,7 @@ static __attribute__((__unused__)) int staticVar7; // GOOD (unused but this is e const int constVar8 = 8; // $ Alert // BAD (const defaults to static) extern const int constVar9 = 9; // GOOD static int staticVar10 = 10; // $ SPURIOUS: Alert // GOOD [FALSE POSITIVE] (referenced in a never instantiated template) -[[maybe_unused]] static int staticVar11; // $ SPURIOUS: Alert // GOOD (false positive for maybe_unused) +[[maybe_unused]] static int staticVar11; // GOOD (explicitly marked as maybe_unused) void f() { From 7b47e9b99f729f21c2a1069206ffb2557cc47701 Mon Sep 17 00:00:00 2001 From: jketema <93738568+jketema@users.noreply.github.com> Date: Thu, 29 Oct 2026 10:30:54 +0000 Subject: [PATCH 3/3] Document maybe_unused query improvement Note that the unused-local and unused-static-variable queries no longer report variables marked with the C++17 maybe_unused attribute. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- cpp/ql/src/change-notes/2026-10-29-unused-maybe-unused.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 cpp/ql/src/change-notes/2026-10-29-unused-maybe-unused.md diff --git a/cpp/ql/src/change-notes/2026-10-29-unused-maybe-unused.md b/cpp/ql/src/change-notes/2026-10-29-unused-maybe-unused.md new file mode 100644 index 000000000000..a898159583fb --- /dev/null +++ b/cpp/ql/src/change-notes/2026-10-29-unused-maybe-unused.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +The `cpp/unused-local-variable` and `cpp/unused-static-variable` queries no longer report variables marked with the C++17 `[[maybe_unused]]` attribute.