Skip to content

Fix #15080 FP uninitMemberVarNoCtor for const and reference members - #8910

Open
autoantwort wants to merge 2 commits into
cppcheck-opensource:mainfrom
autoantwort:fix-noctor-const-member
Open

autoantwort wants to merge 2 commits into
cppcheck-opensource:mainfrom
autoantwort:fix-noctor-const-member

Conversation

@autoantwort

Copy link
Copy Markdown
Contributor

https://trac.cppcheck.net/ticket/15080

struct S {
    const std::array<std::uint8_t, 2> a;
    const std::vector<std::uint8_t>::const_iterator it;
};
S f(const std::vector<std::uint8_t>& v) {
    return S{ {}, v.cbegin() };
}

gives Member variable 'S::it' has no initializer. [uninitMemberVarNoCtor], and struct S { int a = 0; const int b; int& c; }; warns for b and c.

A non-static const or reference member without default member initializer can't stay uninitialized: for trivial types the implicit default constructor is deleted, so every instance must initialize it, and a const class type is default-constructed. These members are now skipped by the no-constructor check.

Since f90a76f (#15072) this also shows up for class templates whose member type is a using alias.

This PR was created by Claude Code (an AI coding agent) on behalf of @autoantwort.

🤖 Generated with Claude Code

A class without constructor whose non-static const or reference member has
no default member initializer is not default constructible (or, for a const
class type with a default constructor, default constructs it), so the member
can never be left uninitialized.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread lib/checkclass.cpp Outdated
…or for all members

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread test/testconstructors.cpp
@autoantwort

Copy link
Copy Markdown
Contributor Author

Any further changes requested?

@danmar

danmar commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

@claude review

Comment thread lib/checkclass.cpp
if (var.hasDefault()) {
usage.init = true;
hasAnyDefaultInit = true;
} else if (var.isReference() || (var.isConst() && !var.isClass())) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This branch also catches static members. createUsageList() keeps static members because isInitialized() filters them out later, so a static const or static reference member without an in-class initializer now marks the class as not default constructible. That suppresses every warning for the class, which is a new false negative:

struct S {
    int a = 0;
    static const int N;   // defined out of class
    int k;                // warned before this PR, not anymore
};

Suggest excluding static members, and adding a test for this case:

Suggested change
} else if (var.isReference() || (var.isConst() && !var.isClass())) {
} else if (!var.isStatic() && (var.isReference() || (var.isConst() && !var.isClass()))) {

@claude

claude Bot commented Oct 7, 2026

Copy link
Copy Markdown

The approach makes sense: a const member of trivial type, or a reference member, with no initializer deletes the implicit default constructor, so every instance has to be initialized another way.

One issue (inline): static const and static reference members are in the usage list too. The new check doesn't exclude them, so a declaration like static const int N; turns off uninitMemberVarNoCtor for the whole class. That's a new false negative. It needs a !var.isStatic() guard and a regression test.

Minor: it would be good to add a test for a const pointer member (int* const p;).

🤖 Generated with Claude Code

@danmar

danmar commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

please check the results here:
http://ec2-16-170-140-253.eu-north-1.compute.amazonaws.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants