зеркало из https://github.com/microsoft/clang.git
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
This commit is contained in:
Родитель
63fe6814f3
Коммит
6f0074ae2f
|
@ -35,6 +35,8 @@ def : DiagGroup<"ctor-dtor-privacy">;
|
||||||
def : DiagGroup<"declaration-after-statement">;
|
def : DiagGroup<"declaration-after-statement">;
|
||||||
def GNUDesignator : DiagGroup<"gnu-designator">;
|
def GNUDesignator : DiagGroup<"gnu-designator">;
|
||||||
|
|
||||||
|
def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
|
||||||
|
|
||||||
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
|
||||||
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">;
|
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">;
|
||||||
def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >,
|
def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >,
|
||||||
|
@ -235,6 +237,7 @@ def Extra : DiagGroup<"extra", [
|
||||||
def Most : DiagGroup<"most", [
|
def Most : DiagGroup<"most", [
|
||||||
CharSubscript,
|
CharSubscript,
|
||||||
Comment,
|
Comment,
|
||||||
|
DeleteNonVirtualDtor,
|
||||||
Format,
|
Format,
|
||||||
Implicit,
|
Implicit,
|
||||||
MismatchedTags,
|
MismatchedTags,
|
||||||
|
|
|
@ -3069,6 +3069,9 @@ def err_objc_exceptions_disabled : Error<
|
||||||
def warn_non_virtual_dtor : Warning<
|
def warn_non_virtual_dtor : Warning<
|
||||||
"%0 has virtual functions but non-virtual destructor">,
|
"%0 has virtual functions but non-virtual destructor">,
|
||||||
InGroup<NonVirtualDtor>, DefaultIgnore;
|
InGroup<NonVirtualDtor>, DefaultIgnore;
|
||||||
|
def warn_delete_non_virtual_dtor : Warning<
|
||||||
|
"delete called on %0 that has virtual functions but non-virtual destructor">,
|
||||||
|
InGroup<DeleteNonVirtualDtor>, DefaultIgnore;
|
||||||
def warn_overloaded_virtual : Warning<
|
def warn_overloaded_virtual : Warning<
|
||||||
"%q0 hides overloaded virtual %select{function|functions}1">,
|
"%q0 hides overloaded virtual %select{function|functions}1">,
|
||||||
InGroup<OverloadedVirtual>, DefaultIgnore;
|
InGroup<OverloadedVirtual>, DefaultIgnore;
|
||||||
|
|
|
@ -1800,6 +1800,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
|
||||||
const_cast<CXXDestructorDecl*>(Dtor));
|
const_cast<CXXDestructorDecl*>(Dtor));
|
||||||
DiagnoseUseOfDecl(Dtor, StartLoc);
|
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<FinalAttr>()) {
|
||||||
|
CXXDestructorDecl *dtor = RD->getDestructor();
|
||||||
|
if (!dtor || !dtor->isVirtual())
|
||||||
|
Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OperatorDelete) {
|
if (!OperatorDelete) {
|
||||||
|
|
|
@ -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 {
|
class A {
|
||||||
public:
|
public:
|
||||||
~A();
|
~A();
|
||||||
|
@ -173,6 +173,179 @@ template<class T> class TS2 { // expected-warning {{'nonvirtualdtor::TS2<int>' h
|
||||||
TS2<int> foo; // expected-note {{instantiation}}
|
TS2<int> 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 <typename T>
|
||||||
|
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 <typename T>
|
||||||
|
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 <typename T>
|
||||||
|
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> f(new F());
|
||||||
|
use(*f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
simple_ptr<VB> vb(new VB());
|
||||||
|
use(*vb);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
simple_ptr<VB> vb(new VD());
|
||||||
|
use(*vb);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
simple_ptr<VD> vd(new VD());
|
||||||
|
use(*vd);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
simple_ptr<VF> vf(new VF());
|
||||||
|
use(*vf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void warn1() {
|
||||||
|
{
|
||||||
|
simple_ptr<B> b(new B()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr<dnvd::B>::~simple_ptr' requested here}}
|
||||||
|
use(*b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
simple_ptr2<B> b(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr2<dnvd::B>::~simple_ptr2' requested here}}
|
||||||
|
use(*b);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
simple_ptr<D> d(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr<dnvd::D>::~simple_ptr' requested here}}
|
||||||
|
use(*d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace PR9238 {
|
namespace PR9238 {
|
||||||
class B { public: ~B(); };
|
class B { public: ~B(); };
|
||||||
class C : virtual B { public: ~C() { } };
|
class C : virtual B { public: ~C() { } };
|
||||||
|
|
Загрузка…
Ссылка в новой задаче