diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 99627e583..b24c462ae 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -124,6 +124,28 @@ static bool isVclTypeInit(const Type *type) return false; } +// Plain old C struct? +static bool isPodStruct(const Scope *scope) { + if (scope->type != Scope::ScopeType::eStruct && scope->type != Scope::ScopeType::eUnion) + return false; + if (!scope->functionList.empty()) + return false; + for (const Variable& var: scope->varlist) { + if (!var.valueType()) + return false; + if (var.valueType()->isIntegral() || var.valueType()->pointer || var.valueType()->isFloat()) + continue; + if (var.valueType()->typeScope && isPodStruct(var.valueType()->typeScope)) + continue; + return false; + } + for (const Scope* childScope: scope->nestedList) { + if (!isPodStruct(childScope)) + return false; + } + return true; +} + //--------------------------------------------------------------------------- CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) @@ -298,17 +320,30 @@ void CheckClass::constructors() const Scope *varType = var.typeScope(); if (!varType || varType->type != Scope::eUnion) { const bool derived = scope != var.scope(); + // is the derived variable declared in a plain old C struct + bool varScopeIsPodStruct = false; + if (derived && scope->definedType && scope->definedType->derivedFrom.size() > 0) { + for (const Scope* s = var.scope(); s; s = s ? s->nestedIn : nullptr) { + for (const Type::BaseInfo& baseInfo: scope->definedType->derivedFrom) { + if (s->definedType == baseInfo.type) { + varScopeIsPodStruct = isPodStruct(s); + s = nullptr; + break; + } + } + } + } if (func.type == Function::eConstructor && func.nestedIn && (func.nestedIn->numConstructors - func.nestedIn->numCopyOrMoveConstructors) > 1 && func.argCount() == 0 && func.functionScope && func.arg && func.arg->link()->next() == func.functionScope->bodyStart && func.functionScope->bodyStart->link() == func.functionScope->bodyStart->next()) { // don't warn about user defined default constructor when there are other constructors - if (printInconclusive) + if (printInconclusive && (!derived || !varScopeIsPodStruct)) uninitVarError(func.token, func.access == AccessControl::Private, func.type, var.scope()->className, var.name(), derived, true); } else if (missingCopy) missingMemberCopyError(func.token, func.type, var.scope()->className, var.name()); - else + else if (!derived || !varScopeIsPodStruct) uninitVarError(func.token, func.access == AccessControl::Private, func.type, var.scope()->className, var.name(), derived, false); } } diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index eeec24a3a..99803ab56 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -126,6 +126,7 @@ private: TEST_CASE(initvar_delegate); // ticket #4302 TEST_CASE(initvar_delegate2); TEST_CASE(initvar_derived_class); + TEST_CASE(initvar_derived_pod_struct); // #11101 TEST_CASE(initvar_private_constructor); // BUG 2354171 - private constructor TEST_CASE(initvar_copy_constructor); // ticket #1611 @@ -1416,6 +1417,24 @@ private: } + void initvar_derived_pod_struct() { + check("struct S {\n" + " union {\n" + " unsigned short all;\n" + " struct {\n" + " unsigned char flag1;\n" + " unsigned char flag2;\n" + " };\n" + " };\n" + "};\n" + "\n" + "class C : public S {\n" + "public:\n" + " C() { all = 0; tick = 0; }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + void initvar_private_constructor() { settings.standards.cpp = Standards::CPP11; check("class Fred\n"