From eb7b004313efc7f6d08444b9762ad8cd3db145fc Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Tue, 10 Nov 2026 16:17:11 +0100 Subject: [PATCH] Fix #15197 FP uninitMemberVarNoCtor for class without constructor that has a member of a type without default constructor Co-Authored-By: Claude Opus 5.5 --- lib/checkclass.cpp | 13 +++++++++- test/testconstructors.cpp | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index a6fb1aecac4..1bc1ea1fcd9 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -104,6 +104,16 @@ static bool isVclTypeInit(const Type *type) return false; }); } + +// Returns true if the class has constructors but none of them can be called without arguments +static bool hasNoDefaultConstructor(const Scope& scope) +{ + return scope.numConstructors > 0 && std::none_of(scope.functionList.cbegin(), scope.functionList.cend(), [](const Function& func) { + // a variadic constructor can be called without arguments if only the parameter pack or ellipsis is left + const size_t requiredArgs = func.isVariadic() ? 1 : 0; + return func.isConstructor() && func.minArgCount() == requiredArgs && !func.isDelete(); + }); +} //--------------------------------------------------------------------------- CheckClassImpl::CheckClassImpl(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger &errorLogger) @@ -447,7 +457,8 @@ void CheckClassImpl::constructors() if (var.hasDefault()) { usage.init = true; hasAnyDefaultInit = true; - } else if (!var.isStatic() && (var.isReference() || (var.isConst() && !var.isClass()))) { + } else if (!var.isStatic() && (var.isReference() || (var.isConst() && !var.isClass()) || + (!var.isPointer() && !var.isPointerArray() && var.typeScope() && hasNoDefaultConstructor(*var.typeScope())))) { // the default constructor is deleted, so all members are initialized by every instance isDefaultConstructible = false; } else if (cpp14OrLater && !hasAnySelfInit && checkInitialization(usage, FunctionType::eConstructor) == Initialization::Initialized) { diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 47a5512fc79..1cd9270d344 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -940,6 +940,60 @@ class TestConstructors : public TestFixture { ASSERT_EQUALS("[test.cpp:3:9]: (warning) Member variable 'S::x' has no initializer. [uninitMemberVarNoCtor]\n" "[test.cpp:7:9]: (warning) Member variable 'T::x' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); + + check("struct N {\n" // #15197 + " explicit N(int);\n" + "};\n" + "struct D {\n" + " D() = delete;\n" + "};\n" + "struct S {\n" + " N n;\n" + " int i;\n" + " bool b = true;\n" + "};\n" + "struct W {\n" + " W(int, ...);\n" + "};\n" + "struct T {\n" + " D d;\n" + " int i;\n" + " bool b = true;\n" + "};\n" + "struct U {\n" + " W w;\n" + " int i;\n" + " bool b = true;\n" + "};\n" + "struct A {\n" + " N a[2];\n" + " int i;\n" + " bool b = true;\n" + "};\n"); + ASSERT_EQUALS("", errout_str()); + + check("struct N {\n" + " explicit N(int = 0);\n" + "};\n" + "struct V {\n" + " template explicit V(A&&... a);\n" + "};\n" + "struct C {\n" + " C(...);\n" + "};\n" + "struct M {\n" + " explicit M(int);\n" + "};\n" + "struct S {\n" + " N n;\n" + " V v;\n" + " C c;\n" + " M* p;\n" + " M* q[2];\n" + " int i;\n" + " bool b = true;\n" + "};\n"); + ASSERT_EQUALS("[test.cpp:19:9]: (warning) Member variable 'S::i' has no initializer. [uninitMemberVarNoCtor]\n", errout_str()); } // ticket #4290 "False Positive: style (noConstructor): The class 'foo' does not have a constructor."