Virtual Destructors: Base class must have virtual destructor no matter if derived class has a destructor or not. There is UB according to paragraph 3 in [expr.delete].

This commit is contained in:
Daniel Marjamäki 2019-09-27 09:55:39 +02:00
parent b823064cce
commit 7f64faae99
2 changed files with 18 additions and 15 deletions

View File

@ -1639,7 +1639,7 @@ void CheckClass::virtualDestructor()
{ {
// This error should only be given if: // This error should only be given if:
// * base class doesn't have virtual destructor // * base class doesn't have virtual destructor
// * derived class has non-empty destructor // * 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 // * base class is deleted
// unless inconclusive in which case: // unless inconclusive in which case:
// * base class has virtual members but doesn't have virtual destructor // * base class has virtual members but doesn't have virtual destructor
@ -1665,6 +1665,8 @@ void CheckClass::virtualDestructor()
continue; continue;
} }
// Check if destructor is empty and non-empty ..
if (mSettings->standards.cpp <= Standards::CPP03) {
// Find the destructor // Find the destructor
const Function *destructor = scope->getDestructor(); const Function *destructor = scope->getDestructor();
@ -1675,6 +1677,7 @@ void CheckClass::virtualDestructor()
// Empty destructor // Empty destructor
if (destructor->token->linkAt(3) == destructor->token->tokAt(4)) if (destructor->token->linkAt(3) == destructor->token->tokAt(4))
continue; continue;
}
const Token *derived = scope->classDef; const Token *derived = scope->classDef;
const Token *derivedClass = derived->next(); const Token *derivedClass = derived->next();

View File

@ -2497,35 +2497,35 @@ private:
} }
void virtualDestructor4() { void virtualDestructor4() {
// Derived class doesn't have a destructor => no error // Derived class doesn't have a destructor => undefined behaviour according to paragraph 3 in [expr.delete]
checkVirtualDestructor("class Base { public: ~Base(); };\n" checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : public Base { };" "class Derived : public Base { };"
"Base *base = new Derived;\n" "Base *base = new Derived;\n"
"delete base;"); "delete base;");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor.\n", errout.str());
checkVirtualDestructor("class Base { public: ~Base(); };\n" checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : private Fred, public Base { };" "class Derived : private Fred, public Base { };"
"Base *base = new Derived;\n" "Base *base = new Derived;\n"
"delete base;"); "delete base;");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor.\n", errout.str());
} }
void virtualDestructor5() { void virtualDestructor5() {
// Derived class has empty destructor => no error // Derived class has empty destructor => undefined behaviour according to paragraph 3 in [expr.delete]
checkVirtualDestructor("class Base { public: ~Base(); };\n" checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : public Base { public: ~Derived() {} };" "class Derived : public Base { public: ~Derived() {} };"
"Base *base = new Derived;\n" "Base *base = new Derived;\n"
"delete base;"); "delete base;");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor.\n", errout.str());
checkVirtualDestructor("class Base { public: ~Base(); };\n" checkVirtualDestructor("class Base { public: ~Base(); };\n"
"class Derived : public Base { public: ~Derived(); }; Derived::~Derived() {}" "class Derived : public Base { public: ~Derived(); }; Derived::~Derived() {}"
"Base *base = new Derived;\n" "Base *base = new Derived;\n"
"delete base;"); "delete base;");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:1]: (error) Class 'Base' which is inherited by class 'Derived' does not have a virtual destructor.\n", errout.str());
} }
void virtualDestructor6() { void virtualDestructor6() {