diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index d98996d2337..76f28dbf2a5 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -1599,6 +1599,23 @@ void CheckUnusedVar::checkStructMemberUsage() if (bailout) continue; + // #7458 - if struct is declared inside union and any struct member is used, + // then don't warn about other struct members + if (scope.type == ScopeType::eStruct && scope.nestedIn && scope.nestedIn->type == ScopeType::eUnion) { + bool structMemberUsed = false; + + for (const Token *tok = scope.nestedIn->bodyStart; tok; tok = tok->next()) { + if (tok->variable() && tok != tok->variable()->nameToken() && tok->variable()->scope() == &scope) { + structMemberUsed = true; + break; + } + } + + // Skip reporting unused members if this struct is in a union and any member is used + if (structMemberUsed) + continue; + } + for (const Variable &var : scope.varlist) { // only warn for variables without side effects if (!var.typeStartToken()->isStandardType() && !var.isPointer() && !astIsContainer(var.nameToken()) && !isRecordTypeWithoutSideEffects(var.type())) diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index ac97629d112..13979f84e69 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -1409,6 +1409,22 @@ class TestUnusedVar : public TestFixture { ASSERT_EQUALS("[test.cpp:3:9]: (style) union member 'abc::a' is never used. [unusedStructMember]\n" "[test.cpp:4:9]: (style) union member 'abc::b' is never used. [unusedStructMember]\n" "[test.cpp:5:9]: (style) union member 'abc::c' is never used. [unusedStructMember]\n", errout_str()); + + // #7458 - union with anonymous struct should not cause false positive + checkStructMemberUsage("union DoubleInt {\n" + " double asDouble;\n" + " uint64_t asInt;\n" + " struct {\n" + " uint32_t lo, hi;\n" // <- no FP about lo because hi is used + " } asIntel;\n" + "};\n" + "void f() {\n" + " union DoubleInt di;\n" + " di.asIntel.hi = 3;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2:12]: (style) union member 'DoubleInt::asDouble' is never used. [unusedStructMember]\n" + "[test.cpp:3:14]: (style) union member 'DoubleInt::asInt' is never used. [unusedStructMember]\n", + errout_str()); } void structmember2() {