1*61e7adefSGabor Horvath // RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.DeleteWithNonVirtualDtor -std=c++11 -verify -analyzer-output=text %s
2*61e7adefSGabor Horvath 
3*61e7adefSGabor Horvath struct Virtual {
~VirtualVirtual4*61e7adefSGabor Horvath   virtual ~Virtual() {}
5*61e7adefSGabor Horvath };
6*61e7adefSGabor Horvath 
7*61e7adefSGabor Horvath struct VDerived : public Virtual {};
8*61e7adefSGabor Horvath 
9*61e7adefSGabor Horvath struct NonVirtual {
~NonVirtualNonVirtual10*61e7adefSGabor Horvath   ~NonVirtual() {}
11*61e7adefSGabor Horvath };
12*61e7adefSGabor Horvath 
13*61e7adefSGabor Horvath struct NVDerived : public NonVirtual {};
14*61e7adefSGabor Horvath struct NVDoubleDerived : public NVDerived {};
15*61e7adefSGabor Horvath 
16*61e7adefSGabor Horvath struct Base {
17*61e7adefSGabor Horvath   virtual void destroy() = 0;
18*61e7adefSGabor Horvath };
19*61e7adefSGabor Horvath 
20*61e7adefSGabor Horvath class PrivateDtor final : public Base {
21*61e7adefSGabor Horvath public:
destroy()22*61e7adefSGabor Horvath   void destroy() { delete this; }
23*61e7adefSGabor Horvath private:
~PrivateDtor()24*61e7adefSGabor Horvath   ~PrivateDtor() {}
25*61e7adefSGabor Horvath };
26*61e7adefSGabor Horvath 
27*61e7adefSGabor Horvath struct ImplicitNV {
28*61e7adefSGabor Horvath   virtual void f();
29*61e7adefSGabor Horvath };
30*61e7adefSGabor Horvath 
31*61e7adefSGabor Horvath struct ImplicitNVDerived : public ImplicitNV {};
32*61e7adefSGabor Horvath 
33*61e7adefSGabor Horvath NVDerived *get();
34*61e7adefSGabor Horvath 
create()35*61e7adefSGabor Horvath NonVirtual *create() {
36*61e7adefSGabor Horvath   NonVirtual *x = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
37*61e7adefSGabor Horvath   return x;
38*61e7adefSGabor Horvath }
39*61e7adefSGabor Horvath 
sink(NonVirtual * x)40*61e7adefSGabor Horvath void sink(NonVirtual *x) {
41*61e7adefSGabor Horvath   delete x; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
42*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
43*61e7adefSGabor Horvath }
44*61e7adefSGabor Horvath 
sinkCast(NonVirtual * y)45*61e7adefSGabor Horvath void sinkCast(NonVirtual *y) {
46*61e7adefSGabor Horvath   delete reinterpret_cast<NVDerived*>(y);
47*61e7adefSGabor Horvath }
48*61e7adefSGabor Horvath 
sinkParamCast(NVDerived * z)49*61e7adefSGabor Horvath void sinkParamCast(NVDerived *z) {
50*61e7adefSGabor Horvath   delete z;
51*61e7adefSGabor Horvath }
52*61e7adefSGabor Horvath 
singleDerived()53*61e7adefSGabor Horvath void singleDerived() {
54*61e7adefSGabor Horvath   NonVirtual *sd;
55*61e7adefSGabor Horvath   sd = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
56*61e7adefSGabor Horvath   delete sd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
57*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
58*61e7adefSGabor Horvath }
59*61e7adefSGabor Horvath 
singleDerivedArr()60*61e7adefSGabor Horvath void singleDerivedArr() {
61*61e7adefSGabor Horvath   NonVirtual *sda = new NVDerived[5]; // expected-note{{Conversion from derived to base happened here}}
62*61e7adefSGabor Horvath   delete[] sda; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
63*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
64*61e7adefSGabor Horvath }
65*61e7adefSGabor Horvath 
doubleDerived()66*61e7adefSGabor Horvath void doubleDerived() {
67*61e7adefSGabor Horvath   NonVirtual *dd = new NVDoubleDerived(); // expected-note{{Conversion from derived to base happened here}}
68*61e7adefSGabor Horvath   delete (dd); // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
69*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
70*61e7adefSGabor Horvath }
71*61e7adefSGabor Horvath 
assignThroughFunction()72*61e7adefSGabor Horvath void assignThroughFunction() {
73*61e7adefSGabor Horvath   NonVirtual *atf = get(); // expected-note{{Conversion from derived to base happened here}}
74*61e7adefSGabor Horvath   delete atf; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
75*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
76*61e7adefSGabor Horvath }
77*61e7adefSGabor Horvath 
assignThroughFunction2()78*61e7adefSGabor Horvath void assignThroughFunction2() {
79*61e7adefSGabor Horvath   NonVirtual *atf2;
80*61e7adefSGabor Horvath   atf2 = get(); // expected-note{{Conversion from derived to base happened here}}
81*61e7adefSGabor Horvath   delete atf2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
82*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
83*61e7adefSGabor Horvath }
84*61e7adefSGabor Horvath 
createThroughFunction()85*61e7adefSGabor Horvath void createThroughFunction() {
86*61e7adefSGabor Horvath   NonVirtual *ctf = create(); // expected-note{{Calling 'create'}}
87*61e7adefSGabor Horvath   // expected-note@-1{{Returning from 'create'}}
88*61e7adefSGabor Horvath   delete ctf; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}}
89*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
90*61e7adefSGabor Horvath }
91*61e7adefSGabor Horvath 
deleteThroughFunction()92*61e7adefSGabor Horvath void deleteThroughFunction() {
93*61e7adefSGabor Horvath   NonVirtual *dtf = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
94*61e7adefSGabor Horvath   sink(dtf); // expected-note{{Calling 'sink'}}
95*61e7adefSGabor Horvath }
96*61e7adefSGabor Horvath 
singleCastCStyle()97*61e7adefSGabor Horvath void singleCastCStyle() {
98*61e7adefSGabor Horvath   NVDerived *sccs = new NVDerived();
99*61e7adefSGabor Horvath   NonVirtual *sccs2 = (NonVirtual*)sccs; // expected-note{{Conversion from derived to base happened here}}
100*61e7adefSGabor Horvath   delete sccs2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
101*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
102*61e7adefSGabor Horvath }
103*61e7adefSGabor Horvath 
doubleCastCStyle()104*61e7adefSGabor Horvath void doubleCastCStyle() {
105*61e7adefSGabor Horvath   NonVirtual *dccs = new NVDerived();
106*61e7adefSGabor Horvath   NVDerived *dccs2 = (NVDerived*)dccs;
107*61e7adefSGabor Horvath   dccs = (NonVirtual*)dccs2; // expected-note{{Conversion from derived to base happened here}}
108*61e7adefSGabor Horvath   delete dccs; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
109*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
110*61e7adefSGabor Horvath }
111*61e7adefSGabor Horvath 
singleCast()112*61e7adefSGabor Horvath void singleCast() {
113*61e7adefSGabor Horvath   NVDerived *sc = new NVDerived();
114*61e7adefSGabor Horvath   NonVirtual *sc2 = reinterpret_cast<NonVirtual*>(sc); // expected-note{{Conversion from derived to base happened here}}
115*61e7adefSGabor Horvath   delete sc2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
116*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
117*61e7adefSGabor Horvath }
118*61e7adefSGabor Horvath 
doubleCast()119*61e7adefSGabor Horvath void doubleCast() {
120*61e7adefSGabor Horvath   NonVirtual *dd = new NVDerived();
121*61e7adefSGabor Horvath   NVDerived *dd2 = reinterpret_cast<NVDerived*>(dd);
122*61e7adefSGabor Horvath   dd = reinterpret_cast<NonVirtual*>(dd2); // expected-note {{Conversion from derived to base happened here}}
123*61e7adefSGabor Horvath   delete dd; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}}
124*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
125*61e7adefSGabor Horvath }
126*61e7adefSGabor Horvath 
implicitNV()127*61e7adefSGabor Horvath void implicitNV() {
128*61e7adefSGabor Horvath   ImplicitNV *invd = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}}
129*61e7adefSGabor Horvath   delete invd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
130*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
131*61e7adefSGabor Horvath }
132*61e7adefSGabor Horvath 
doubleDecl()133*61e7adefSGabor Horvath void doubleDecl() {
134*61e7adefSGabor Horvath   ImplicitNV *dd1, *dd2;
135*61e7adefSGabor Horvath   dd1 = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}}
136*61e7adefSGabor Horvath   delete dd1; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
137*61e7adefSGabor Horvath   // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
138*61e7adefSGabor Horvath }
139*61e7adefSGabor Horvath 
virtualBase()140*61e7adefSGabor Horvath void virtualBase() {
141*61e7adefSGabor Horvath   Virtual *vb = new VDerived();
142*61e7adefSGabor Horvath   delete vb; // no-warning
143*61e7adefSGabor Horvath }
144*61e7adefSGabor Horvath 
notDerived()145*61e7adefSGabor Horvath void notDerived() {
146*61e7adefSGabor Horvath   NonVirtual *nd = new NonVirtual();
147*61e7adefSGabor Horvath   delete nd; // no-warning
148*61e7adefSGabor Horvath }
149*61e7adefSGabor Horvath 
notDerivedArr()150*61e7adefSGabor Horvath void notDerivedArr() {
151*61e7adefSGabor Horvath   NonVirtual *nda = new NonVirtual[3];
152*61e7adefSGabor Horvath   delete[] nda; // no-warning
153*61e7adefSGabor Horvath }
154*61e7adefSGabor Horvath 
cast()155*61e7adefSGabor Horvath void cast() {
156*61e7adefSGabor Horvath   NonVirtual *c = new NVDerived();
157*61e7adefSGabor Horvath   delete reinterpret_cast<NVDerived*>(c); // no-warning
158*61e7adefSGabor Horvath }
159*61e7adefSGabor Horvath 
deleteThroughFunction2()160*61e7adefSGabor Horvath void deleteThroughFunction2() {
161*61e7adefSGabor Horvath   NonVirtual *dtf2 = new NVDerived();
162*61e7adefSGabor Horvath   sinkCast(dtf2); // no-warning
163*61e7adefSGabor Horvath }
164*61e7adefSGabor Horvath 
deleteThroughFunction3()165*61e7adefSGabor Horvath void deleteThroughFunction3() {
166*61e7adefSGabor Horvath   NVDerived *dtf3;
167*61e7adefSGabor Horvath   dtf3 = new NVDerived();
168*61e7adefSGabor Horvath   sinkParamCast(dtf3); // no-warning
169*61e7adefSGabor Horvath }
170*61e7adefSGabor Horvath 
stackVar()171*61e7adefSGabor Horvath void stackVar() {
172*61e7adefSGabor Horvath   NonVirtual sv2;
173*61e7adefSGabor Horvath   delete &sv2; // no-warning
174*61e7adefSGabor Horvath }
175*61e7adefSGabor Horvath 
176*61e7adefSGabor Horvath // Deleting a polymorphic object with a non-virtual dtor
177*61e7adefSGabor Horvath // is not a problem if it is referenced by its precise type.
178*61e7adefSGabor Horvath 
preciseType()179*61e7adefSGabor Horvath void preciseType() {
180*61e7adefSGabor Horvath   NVDerived *pt = new NVDerived();
181*61e7adefSGabor Horvath   delete pt; // no-warning
182*61e7adefSGabor Horvath }
183*61e7adefSGabor Horvath 
privateDtor()184*61e7adefSGabor Horvath void privateDtor() {
185*61e7adefSGabor Horvath   Base *pd = new PrivateDtor();
186*61e7adefSGabor Horvath   pd->destroy(); // no-warning
187*61e7adefSGabor Horvath }
188