diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 314af14e158..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,6 +377,10 @@ void CheckClassImpl::constructors() if (var.typeScope() && var.typeScope()->numConstructors > 0) continue; + // 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) 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..845e27ccd76 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -797,6 +797,42 @@ 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" // #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: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" + " 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."