From: Argyrios Kyrtzidis Date: Tue, 24 May 2011 19:53:26 +0000 (+0000) Subject: Add new warning that warns when invoking 'delete' on a polymorphic, non-final, class... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6f0074ae2f466bae9f415da268d61a2dc1fabe26;p=clang Add new warning that warns when invoking 'delete' on a polymorphic, non-final, class without a virtual destructor. Patch by Matthieu Monrocq! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131989 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 72afc3d616..09488da89e 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -35,6 +35,8 @@ def : DiagGroup<"ctor-dtor-privacy">; def : DiagGroup<"declaration-after-statement">; def GNUDesignator : DiagGroup<"gnu-designator">; +def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; + def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">; def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >, @@ -235,6 +237,7 @@ def Extra : DiagGroup<"extra", [ def Most : DiagGroup<"most", [ CharSubscript, Comment, + DeleteNonVirtualDtor, Format, Implicit, MismatchedTags, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8653358265..7d6c660ae4 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3069,6 +3069,9 @@ def err_objc_exceptions_disabled : Error< def warn_non_virtual_dtor : Warning< "%0 has virtual functions but non-virtual destructor">, InGroup, DefaultIgnore; +def warn_delete_non_virtual_dtor : Warning< + "delete called on %0 that has virtual functions but non-virtual destructor">, + InGroup, DefaultIgnore; def warn_overloaded_virtual : Warning< "%q0 hides overloaded virtual %select{function|functions}1">, InGroup, DefaultIgnore; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c82a9f9d00..3631fcff53 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1800,6 +1800,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, const_cast(Dtor)); DiagnoseUseOfDecl(Dtor, StartLoc); } + + // C++ [expr.delete]p3: + // In the first alternative (delete object), if the static type of the + // object to be deleted is different from its dynamic type, the static + // type shall be a base class of the dynamic type of the object to be + // deleted and the static type shall have a virtual destructor or the + // behavior is undefined. + // + // Note: a final class cannot be derived from, no issue there + if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr()) { + CXXDestructorDecl *dtor = RD->getDestructor(); + if (!dtor || !dtor->isVirtual()) + Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; + } } if (!OperatorDelete) { diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp index 01f21de6de..ec0539b819 100644 --- a/test/SemaCXX/destructor.cpp +++ b/test/SemaCXX/destructor.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wnon-virtual-dtor -verify %s +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s class A { public: ~A(); @@ -173,6 +173,179 @@ template class TS2 { // expected-warning {{'nonvirtualdtor::TS2' h TS2 foo; // expected-note {{instantiation}} } +namespace dnvd { // delete-non-virtual-dtor warning +struct NP {}; + +struct B { // expected-warning {{has virtual functions but non-virtual destructor}} + virtual void foo(); +}; + +struct D: B {}; // expected-warning {{has virtual functions but non-virtual destructor}} + +struct F final: B {}; // expected-warning {{has virtual functions but non-virtual destructor}} + +struct VB { + virtual void foo(); + virtual ~VB(); +}; + +struct VD: VB {}; + +struct VF final: VB {}; + +template +class simple_ptr { +public: + simple_ptr(T* t): _ptr(t) {} + ~simple_ptr() { delete _ptr; } // \ + // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}} \ + // expected-warning {{delete called on 'dnvd::D' that has virtual functions but non-virtual destructor}} + T& operator*() const { return *_ptr; } +private: + T* _ptr; +}; + +template +class simple_ptr2 { +public: + simple_ptr2(T* t): _ptr(t) {} + ~simple_ptr2() { delete _ptr; } // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}} + T& operator*() const { return *_ptr; } +private: + T* _ptr; +}; + +void use(B&); +void use(VB&); + +void nowarnstack() { + B b; use(b); + D d; use(d); + F f; use(f); + VB vb; use(vb); + VD vd; use(vd); + VF vf; use(vf); +} + +void nowarnnonpoly() { + { + NP* np = new NP(); + delete np; + } + { + NP* np = new NP[4]; + delete[] np; + } +} + +void nowarnarray() { + { + B* b = new B[4]; + delete[] b; + } + { + D* d = new D[4]; + delete[] d; + } + { + VB* vb = new VB[4]; + delete[] vb; + } + { + VD* vd = new VD[4]; + delete[] vd; + } +} + +template +void nowarntemplate() { + { + T* t = new T(); + delete t; + } + { + T* t = new T[4]; + delete[] t; + } +} + +void nowarn0() { + { + F* f = new F(); + delete f; + } + { + VB* vb = new VB(); + delete vb; + } + { + VB* vb = new VD(); + delete vb; + } + { + VD* vd = new VD(); + delete vd; + } + { + VF* vf = new VF(); + delete vf; + } +} + +void warn0() { + { + B* b = new B(); + delete b; // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}} + } + { + B* b = new D(); + delete b; // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}} + } + { + D* d = new D(); + delete d; // expected-warning {{delete called on 'dnvd::D' that has virtual functions but non-virtual destructor}} + } +} + +void nowarn1() { + { + simple_ptr f(new F()); + use(*f); + } + { + simple_ptr vb(new VB()); + use(*vb); + } + { + simple_ptr vb(new VD()); + use(*vb); + } + { + simple_ptr vd(new VD()); + use(*vd); + } + { + simple_ptr vf(new VF()); + use(*vf); + } +} + +void warn1() { + { + simple_ptr b(new B()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr::~simple_ptr' requested here}} + use(*b); + } + { + simple_ptr2 b(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr2::~simple_ptr2' requested here}} + use(*b); + } + { + simple_ptr d(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr::~simple_ptr' requested here}} + use(*d); + } +} +} + namespace PR9238 { class B { public: ~B(); }; class C : virtual B { public: ~C() { } };