From ba74606e7d4decf5c9ff29876639b3fc7771e0fe Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 30 Sep 2026 21:29:32 +0200 Subject: [PATCH 1/2] Fix #15080 FP uninitMemberVarNoCtor for const and reference members 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 --- lib/checkclass.cpp | 4 ++++ test/testconstructors.cpp | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 314af14e158..fdacd5c270a 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -373,6 +373,10 @@ void CheckClassImpl::constructors() if (var.typeScope() && var.typeScope()->numConstructors > 0) continue; + // const and reference members without default initializer must be initialized by every instance + if (var.isConst() || var.isReference()) + continue; + if (diagVars.count(&var) == 0) uninitVarError(var.nameToken(), false, FunctionType::eConstructor, var.scope()->className, var.name(), false, false, true); } diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 4de49f54311..deb0ce07fce 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -797,6 +797,23 @@ class TestConstructors : public TestFixture { ASSERT_EQUALS("[test.cpp:4:9]: (warning) Member variable 'T::j' has no initializer. [uninitMemberVarNoCtor]\n" "[test.cpp:8:9]: (warning) Member variable 'U::k' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + + check("struct S {\n" // const and reference members can't stay uninitialized + " int a = 0;\n" + " const int b;\n" + " int& c;\n" + " const int* d;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:5:16]: (warning) Member variable 'S::d' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + + check("struct S {\n" + " const std::array a;\n" + " const std::vector::const_iterator it;\n" + "};\n" + "S f(const std::vector& v) {\n" + " return S{ {}, v.cbegin() };\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } // ticket #4290 "False Positive: style (noConstructor): The class 'foo' does not have a constructor." From b8fbea93a2089af2c38ccdf77e926cb5e07a188e Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 3 Oct 2026 17:22:43 +0200 Subject: [PATCH 2/2] Const/reference member of non-class type inhibits uninitMemberVarNoCtor for all members Co-Authored-By: Claude Opus 5.5 --- lib/checkclass.cpp | 10 +++++++--- test/testconstructors.cpp | 23 +++++++++++++++++++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index fdacd5c270a..e14d1484209 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -347,6 +347,7 @@ void CheckClassImpl::constructors() // Variables with default initializers bool hasAnyDefaultInit = false; bool hasAnySelfInit = false; + bool isDefaultConstructible = true; const bool cpp14OrLater = mSettings.standards.cpp >= Standards::CPP14; for (Usage& usage : usageList) { const Variable& var = *usage.var; @@ -355,11 +356,14 @@ void CheckClassImpl::constructors() if (var.hasDefault()) { usage.init = true; hasAnyDefaultInit = true; + } else if (var.isReference() || (var.isConst() && !var.isClass())) { + // the default constructor is deleted, so all members are initialized by every instance + isDefaultConstructible = false; } else if (cpp14OrLater && !hasAnySelfInit && isInitialized(usage, FunctionType::eConstructor)) { hasAnySelfInit = true; } } - if (!hasAnyDefaultInit && !hasAnySelfInit) + if (!isDefaultConstructible || (!hasAnyDefaultInit && !hasAnySelfInit)) continue; handleUnionMembers(usageList); @@ -373,8 +377,8 @@ void CheckClassImpl::constructors() if (var.typeScope() && var.typeScope()->numConstructors > 0) continue; - // const and reference members without default initializer must be initialized by every instance - if (var.isConst() || var.isReference()) + // a const member of class type is default constructed or makes the class not default constructible + if (var.isConst()) continue; if (diagVars.count(&var) == 0) diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index deb0ce07fce..845e27ccd76 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -798,13 +798,32 @@ class TestConstructors : public TestFixture { "[test.cpp:8:9]: (warning) Member variable 'U::k' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); - check("struct S {\n" // const and reference members can't stay uninitialized + check("struct S {\n" // #15080 " int a = 0;\n" " const int b;\n" + " int k;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" + " int a = 0;\n" " int& c;\n" + " int k;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct S {\n" + " int a = 0;\n" " const int* d;\n" "};\n"); - ASSERT_EQUALS("[test.cpp:5:16]: (warning) Member variable 'S::d' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + ASSERT_EQUALS("[test.cpp:3:16]: (warning) Member variable 'S::d' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + + check("struct S {\n" + " std::string a;\n" + " const std::string s;\n" + " int k;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:4:9]: (warning) Member variable 'S::k' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); check("struct S {\n" " const std::array a;\n"