From 347d63fe3d5184042bafa7a523a68a273ba66a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Sun, 31 May 2026 13:02:45 +0200 Subject: [PATCH 1/2] add tests --- test/testunusedvar.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 03ef0a14a83..8d6917b2075 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -80,6 +80,7 @@ class TestUnusedVar : public TestFixture { TEST_CASE(structmember32); // #14483 TEST_CASE(structmember33); TEST_CASE(structmember34); + TEST_CASE(structmember35); TEST_CASE(structmember_macro); TEST_CASE(structmember_template_argument); // #13887 - do not report that member used in template argument is unused TEST_CASE(classmember); @@ -2101,6 +2102,20 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("[test.cpp:2:24]: (style) struct member 'S::p' is never used. [unusedStructMember]\n", errout_str()); } + void structmember35() { + checkStructMemberUsage("struct S { int i; };\n" + "int f() { return g(); }\n"); + ASSERT_EQUALS("", errout_str()); + + checkStructMemberUsage("struct S { int i; };\n" + "int f() { A *a = nullptr; (void) a; }\n"); + ASSERT_EQUALS("", errout_str()); + + checkStructMemberUsage("struct S { int i; };\n" + "int f() { const std::vector a {}; (void) a; }\n"); + ASSERT_EQUALS("[test.cpp:1:16]: (style) struct member 'S::i' is never used. [unusedStructMember]\n", errout_str()); + } + void structmember_macro() { checkStructMemberUsageP("#define S(n) struct n { int a, b, c; };\n" "S(unused);\n"); From da45d2c34fae4d0d83c02dab174951e3bade9973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Tue, 2 Jun 2026 11:52:30 +0200 Subject: [PATCH 2/2] fix --- lib/checkunusedvar.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index fe85260fc8d..f4ced7f158d 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1676,6 +1676,27 @@ void CheckUnusedVarImpl::checkStructMemberUsage() if (use) break; } + // Class used in template with unknown definition + if (Token::Match(tok, "%name% <") && tok->linkAt(1)) { + if (tok->function()) + continue; + if (tok->type() && tok->type()->classScope) + continue; + const Token *start = tok; + while (Token::Match(start->tokAt(-2), "%name% ::")) + start = start->tokAt(-2); + if (mSettings.library.detectContainer(start)) + continue; + const Token *end = tok->linkAt(1); + for (; tok != end; tok = tok->next()) { + if (tok->type() && tok->type()->classScope == &scope) { + use = true; + break; + } + } + if (use) + break; + } if (tok->variable() != &var) continue; if (tok != var.nameToken()) {