diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 2eae9e589..b74935714 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1643,7 +1643,7 @@ void CheckClass::virtualDestructor() // * derived class has non-empty destructor (only c++03, in c++11 it's UB see paragraph 3 in [expr.delete]) // * base class is deleted // unless inconclusive in which case: - // * base class has virtual members but doesn't have virtual destructor + // * A class with any virtual functions should have a destructor that is either public and virtual or protected const bool printInconclusive = mSettings->inconclusive; std::list inconclusiveErrors; @@ -1654,11 +1654,14 @@ void CheckClass::virtualDestructor() if (scope->definedType->derivedFrom.empty()) { if (printInconclusive) { const Function *destructor = scope->getDestructor(); - if (destructor && !destructor->hasVirtualSpecifier()) { - for (const Function &func : scope->functionList) { - if (func.hasVirtualSpecifier()) { - inconclusiveErrors.push_back(destructor); - break; + if (destructor) { + if(!((destructor->hasVirtualSpecifier() && destructor->access == AccessControl::Public) || + (destructor->access == AccessControl::Protected))) { + for (const Function &func : scope->functionList) { + if (func.hasVirtualSpecifier()) { + inconclusiveErrors.push_back(destructor); + break; + } } } } diff --git a/test/testclass.cpp b/test/testclass.cpp index 769ca6456..75eece4de 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -2699,6 +2699,15 @@ private: " delete base;\n" "}\n", true); ASSERT_EQUALS("[test.cpp:3]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor.\n", errout.str()); + + // class Base destructor is not virtual but protected -> no error + checkVirtualDestructor("class Base {\n" + "public:\n" + " virtual void foo(){}\n" + "protected:\n" + " ~Base(){}\n" + "};\n", true); + ASSERT_EQUALS("", errout.str()); } void checkNoMemset(const char code[]) {