Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 7 additions & 12 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8690,7 +8690,6 @@ template<class F>
static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy, const Settings& settings)
{
size_t total = 0;
std::set<const Scope*> anonScopes;
for (const Variable& var : scope->varlist) {
if (var.isStatic())
continue;
Expand All @@ -8701,17 +8700,12 @@ static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accura
const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), MathLib::bigint(1), [](MathLib::bigint i1, const Dimension& dim) {
return i1 * dim.num;
});
if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union
const auto ret = anonScopes.insert(var.nameToken()->scope());
if (ret.second)
total = f(total, *vt, dim, bits);
}
else if (vt->container && vt->container->startPattern == "std :: array <") {
if (vt->container && vt->container->startPattern == "std :: array <") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review

Removing the anonScopes handling means every member of an anonymous union is now passed to f. getAlignOf is fine with this because it takes the max. In getSizeOf, though, these members are now added together unless the new isUnion heuristic matches, and it doesn't match plain-typed members. That causes the regressions described on line 8837.

const ValueType vtElement = ValueType::parseDecl(vt->containerTypeToken, settings);
total = f(total, vtElement, dim, bits);
total = f(total, vtElement, dim, bits, /*isAnonUnion*/ false);
}
else
total = f(total, *vt, dim, bits);
total = f(total, *vt, dim, bits, var.nameToken()->scope() != scope);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review

var.nameToken()->scope() != scope is also true for members of an anonymous struct, so getSizeOf overlaps them with std::max as if they were in a union. struct X { struct { char a[12]; }; struct { char b[12]; }; }; now gives sizeof(X) = 12; base and g++ give 24. Because of this, int f(X x) no longer gets the passedByValue warning that base reports. This flag should only be set when var.nameToken()->scope()->type == ScopeType::eUnion, and members of an anonymous struct still need to be added up, with padding.

}
if (accuracy == ValueType::Accuracy::ExactOrZero && total == 0 && bits == -1)
return {0, false};
Expand Down Expand Up @@ -8745,7 +8739,7 @@ static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueTyp
return align == 0 ? 0 : bitCeil(align);
}
if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/) {
auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/, bool /*isAnonUnion*/) {
size_t a = getAlignOf(vt2, settings, accuracy, ValueType::SizeOf::Pointer, ++maxRecursion);
return std::max(max, a);
};
Expand Down Expand Up @@ -8797,7 +8791,7 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf
if (type == ValueType::Type::RECORD && typeScope) {
size_t currentBitCount = 0;
size_t currentBitfieldAlloc = 0;
auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint nBits) -> size_t {
auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint nBits, bool isAnonUnion) -> size_t {
const size_t charBit = settings.platform.char_bit;
size_t n = vt2.getSizeOf(settings, accuracy, SizeOf::Pointer, ++maxRecursion);
size_t a = getAlignOf(vt2, settings, accuracy, SizeOf::Pointer);
Expand Down Expand Up @@ -8840,7 +8834,8 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf
currentBitfieldAlloc = 0;
currentBitCount = 0;
}
return typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n;
const bool isUnion = isAnonUnion || typeScope->type == ScopeType::eUnion;
return isUnion ? std::max(total, n) : total + padding + n;
};
Result result = accumulateStructMembers(typeScope, accHelper, accuracy, settings);
size_t total = result.total;
Expand Down
11 changes: 11 additions & 0 deletions test/testother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2787,6 +2787,17 @@ class TestOther : public TestFixture {
"}\n");
ASSERT_EQUALS("", errout_str());

check("struct S {\n" // #15130
" union {\n"
" int i;\n"
" struct {\n"
" char a[24];\n"
" } x;\n"
" };\n"
"};\n"
"int f(S s) { return s.i; }\n");
ASSERT_EQUALS("[test.cpp:9:9]: (performance) Function parameter 's' should be passed by const reference. [passedByValue]\n", errout_str());

/*const*/ Settings settingsWin64 = settingsBuilder().platform(Platform::Type::Win64).build();
check("using ui64 = unsigned __int64;\n"
"ui64 Test(ui64 one, ui64 two) { return one + two; }\n",
Expand Down
26 changes: 26 additions & 0 deletions test/testvalueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1862,6 +1862,32 @@ class TestValueFlow : public TestFixture {
ASSERT_EQUALS(1U, values.size());
ASSERT_EQUALS(settings.platform.sizeof_int, values.back().intvalue);
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind);

code = "struct S {\n"
" union {\n"
" int i;\n"
" struct {\n"
" char a[24];\n"
" } x;\n"
" };\n"
"};\n"
"int f() { return sizeof(S); }\n";
values = tokenValues(code, "( S");
ASSERT_EQUALS(1U, values.size());
ASSERT_EQUALS(24, values.back().intvalue);
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind);

code = "struct S {\n"
" union {\n"
" int i;\n"
" double d;\n"
" };\n"
"};\n"
"int f() { return sizeof(S); }\n";
values = tokenValues(code, "( S");
ASSERT_EQUALS(1U, values.size());
ASSERT_EQUALS(settings.platform.sizeof_double, values.back().intvalue);
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind);
}

void valueFlowComma()
Expand Down
Loading