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:
parent
b823064cce
commit
7f64faae99
|
@ -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,16 +1665,19 @@ void CheckClass::virtualDestructor()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the destructor
|
// Check if destructor is empty and non-empty ..
|
||||||
const Function *destructor = scope->getDestructor();
|
if (mSettings->standards.cpp <= Standards::CPP03) {
|
||||||
|
// Find the destructor
|
||||||
|
const Function *destructor = scope->getDestructor();
|
||||||
|
|
||||||
// Check for destructor with implementation
|
// Check for destructor with implementation
|
||||||
if (!destructor || !destructor->hasBody())
|
if (!destructor || !destructor->hasBody())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 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();
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue