631 lines · cpp
1// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -fcxx-exceptions -verify %s -pedantic2// RUN: %clang_cc1 -std=c++11 -triple %ms_abi_triple -DMSABI -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s -pedantic3 4#if defined(BE_THE_HEADER)5 6// Wdelete-non-virtual-dtor should warn about the delete from smart pointer7// classes in system headers (std::unique_ptr...) too.8 9#pragma clang system_header10namespace dnvd {11 12struct SystemB {13 virtual void foo();14};15 16template <typename T>17class simple_ptr {18public:19 simple_ptr(T* t): _ptr(t) {}20 ~simple_ptr() { delete _ptr; } // \21 // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} \22 // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}}23 T& operator*() const { return *_ptr; }24private:25 T* _ptr;26};27}28 29#else30 31#define BE_THE_HEADER32#include __FILE__33 34class A {35public:36 ~A();37};38 39class B {40public:41 ~B() { }42};43 44class C {45public:46 (~C)() { }47};48 49struct D {50 static void ~D(int, ...) const { } // \51 // expected-error{{static member function cannot have 'const' qualifier}} \52 // expected-error{{destructor cannot be declared 'static'}} \53 // expected-error{{destructor cannot have any parameters}} \54 // expected-error{{destructor cannot be variadic}} \55 // expected-error{{destructor cannot have a return type}} \56 // expected-error{{'const' qualifier is not allowed on a destructor}}57};58 59struct D2 {60 void ~D2() { } // \61 // expected-error{{destructor cannot have a return type}}62};63 64 65struct E;66 67typedef E E_typedef;68struct E {69 ~E_typedef(); // expected-error{{destructor cannot be declared using a typedef 'E_typedef' (aka 'E') of the class name}}70};71 72struct F {73 (~F)(); // expected-note {{previous declaration is here}}74 ~F(); // expected-error {{destructor cannot be redeclared}}75};76 77~; // expected-error {{expected a class name after '~' to name a destructor}}78~undef(); // expected-error {{undeclared identifier 'undef' in destructor name}}79~operator+(int, int); // expected-error {{expected a class name after '~' to name a destructor}}80~F(){} // expected-error {{destructor must be a non-static member function}}81 82struct G {83 ~G();84};85 86G::~G() { }87 88struct H {89 ~H(void) { }90};91 92struct X {};93 94struct Y {95 ~X(); // expected-error {{expected the class name after '~' to name the enclosing class}}96};97 98namespace PR6421 {99 class T; // expected-note{{forward declaration}}100 101 class QGenericArgument102 {103 template<typename U>104 void foo(T t) // expected-error{{variable has incomplete type}}105 { }106 107 void disconnect()108 {109 T* t;110 bob<QGenericArgument>(t); // expected-error{{undeclared identifier 'bob'}}111 }112 };113}114 115namespace PR6709 {116#ifdef MSABI117 // This bug, "Clang instantiates destructor for function argument" is intended118 // behaviour in the Microsoft ABI because the callee needs to destruct the arguments.119 // expected-error@+3 {{indirection requires pointer operand ('int' invalid)}}120 // expected-note@+3 {{in instantiation of member function 'PR6709::X<int>::~X' requested here}}121#endif122 template<class T> class X { T v; ~X() { ++*v; } };123 void a(X<int> x) {}124}125 126struct X0 { virtual ~X0() throw(); };127struct X1 : public X0 { };128 129// Make sure we instantiate operator deletes when building a virtual130// destructor.131namespace test6 {132 template <class T> class A {133 public:134 void *operator new(__SIZE_TYPE__);135 void operator delete(void *p) {136 T::deleteIt(p); // expected-error {{type 'int' cannot be used prior to '::'}}137 }138 139#ifdef MSABI140 // expected-note@+2 {{in instantiation of member function 'test6::A<int>::operator delete' requested here}}141#endif142 virtual ~A() {}143 };144 145#ifndef MSABI146 // expected-note@+2 {{in instantiation of member function 'test6::A<int>::operator delete' requested here}}147#endif148 class B : A<int> { B(); };149 B::B() {}150}151 152// Make sure classes are marked invalid when they have invalid153// members. This avoids a crash-on-invalid.154namespace test7 {155 struct A {156 ~A() const; // expected-error {{'const' qualifier is not allowed on a destructor}}157 };158 struct B : A {};159 160 void test() {161 B *b;162 b->~B();163 }164}165 166namespace nonvirtualdtor {167struct S1 { // expected-warning {{has virtual functions but non-virtual destructor}}168 virtual void m();169};170 171struct S2 {172 ~S2(); // expected-warning {{has virtual functions but non-virtual destructor}}173 virtual void m();174};175 176struct S3 : public S1 { // expected-warning {{has virtual functions but non-virtual destructor}}177 virtual void m();178};179 180struct S4 : public S2 { // expected-warning {{has virtual functions but non-virtual destructor}}181 virtual void m();182};183 184struct B {185 virtual ~B();186 virtual void m();187};188 189struct S5 : public B {190 virtual void m();191};192 193struct S6 {194 virtual void m();195private:196 ~S6();197};198 199struct S7 {200 virtual void m();201protected:202 ~S7();203};204 205struct S8 {} s8;206 207UnknownType S8::~S8() { // expected-error {{unknown type name 'UnknownType'}}208 s8.~S8();209}210 211template<class T> class TS : public B {212 virtual void m();213};214 215TS<int> baz;216 217template<class T> class TS2 { // expected-warning {{'nonvirtualdtor::TS2<int>' has virtual functions but non-virtual destructor}}218 virtual void m();219};220 221TS2<int> foo; // expected-note {{instantiation}}222}223 224namespace dnvd { // delete-non-virtual-dtor warning225struct NP {};226 227struct B { // expected-warning {{has virtual functions but non-virtual destructor}}228 virtual void foo();229};230 231struct D: B {}; // expected-warning {{has virtual functions but non-virtual destructor}}232 233struct F final : B {};234 235struct VB {236 virtual void foo();237 virtual ~VB();238};239 240struct VD: VB {};241 242struct VF final: VB {};243 244template <typename T>245class simple_ptr2 {246public:247 simple_ptr2(T* t): _ptr(t) {}248 ~simple_ptr2() { delete _ptr; } // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}}249 T& operator*() const { return *_ptr; }250private:251 T* _ptr;252};253 254void use(B&);255void use(SystemB&);256void use(VB&);257 258void nowarnstack() {259 B b; use(b);260 D d; use(d);261 F f; use(f);262 VB vb; use(vb);263 VD vd; use(vd);264 VF vf; use(vf);265}266 267void nowarnnonpoly() {268 {269 NP* np = new NP();270 delete np;271 }272 {273 NP* np = new NP[4];274 delete[] np;275 }276}277 278// FIXME: Why are these supposed to not warn?279void nowarnarray() {280 {281 B* b = new B[4];282 delete[] b;283 }284 {285 D* d = new D[4];286 delete[] d;287 }288 {289 VB* vb = new VB[4];290 delete[] vb;291 }292 {293 VD* vd = new VD[4];294 delete[] vd;295 }296}297 298template <typename T>299void nowarntemplate() {300 {301 T* t = new T();302 delete t;303 }304 {305 T* t = new T[4];306 delete[] t;307 }308}309 310void nowarn0() {311 {312 F* f = new F();313 delete f;314 }315 {316 VB* vb = new VB();317 delete vb;318 }319 {320 VB* vb = new VD();321 delete vb;322 }323 {324 VD* vd = new VD();325 delete vd;326 }327 {328 VF* vf = new VF();329 delete vf;330 }331}332 333void nowarn0_explicit_dtor(F* f, VB* vb, VD* vd, VF* vf) {334 f->~F();335 f->~F();336 vb->~VB();337 vd->~VD();338 vf->~VF();339}340 341void warn0() {342 {343 B* b = new B();344 delete b; // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}}345 }346 {347 B* b = new D();348 delete b; // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}}349 }350 {351 D* d = new D();352 delete d; // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}}353 }354}355 356// Taken from libc++, slightly simplified.357template <class>358struct __is_destructible_apply { typedef int type; };359struct __two {char __lx[2];};360template <typename _Tp>361struct __is_destructor_wellformed {362 template <typename _Tp1>363 static char __test(typename __is_destructible_apply<364 decltype(_Tp1().~_Tp1())>::type);365 template <typename _Tp1>366 static __two __test (...);367 368 static const bool value = sizeof(__test<_Tp>(12)) == sizeof(char);369};370 371void warn0_explicit_dtor(B* b, B& br, D* d) {372 b->~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}373 b->B::~B(); // No warning when the call isn't virtual.374 375 // No warning in unevaluated contexts.376 (void)__is_destructor_wellformed<B>::value;377 378 br.~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}379 br.B::~B();380 381 d->~D(); // expected-warning {{destructor called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}}382 d->D::~D();383}384 385void nowarn1() {386 {387 simple_ptr<F> f(new F());388 use(*f);389 }390 {391 simple_ptr<VB> vb(new VB());392 use(*vb);393 }394 {395 simple_ptr<VB> vb(new VD());396 use(*vb);397 }398 {399 simple_ptr<VD> vd(new VD());400 use(*vd);401 }402 {403 simple_ptr<VF> vf(new VF());404 use(*vf);405 }406 {407 simple_ptr<SystemB> sb(new SystemB());408 use(*sb);409 }410}411 412void warn1() {413 {414 simple_ptr<B> b(new B()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr<dnvd::B>::~simple_ptr' requested here}}415 use(*b);416 }417 {418 simple_ptr2<B> b(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr2<dnvd::B>::~simple_ptr2' requested here}}419 use(*b);420 }421 {422 simple_ptr<D> d(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr<dnvd::D>::~simple_ptr' requested here}}423 use(*d);424 }425}426}427 428namespace PR9238 {429 class B { public: ~B(); };430 class C : virtual B { public: ~C() { } };431}432 433namespace PR7900 {434 struct A { // expected-note 2{{type 'A' found by destructor name lookup}}435 };436 struct B : public A {437 };438 void foo() {439 B b;440 b.~B();441 b.~A(); // expected-error{{destructor type 'A' in object destruction expression does not match the type 'B' of the object being destroyed}}442 (&b)->~A(); // expected-error{{destructor type 'A' in object destruction expression does not match the type 'B' of the object being destroyed}}443 }444}445 446namespace PR16892 {447 auto p = &A::~A; // expected-error{{taking the address of a destructor}}448}449 450namespace PR20238 {451struct S {452 volatile ~S() { } // expected-error{{destructor cannot have a return type}}453};454}455 456namespace PR22668 {457struct S {458};459void f(S s) {460 (s.~S)();461}462void g(S s) {463 (s.~S); // expected-error{{reference to destructor must be called}}464}465}466 467class Invalid {468 ~Invalid();469 UnknownType xx; // expected-error{{unknown type name}}470};471 472// The constructor definition should not have errors473Invalid::~Invalid() {}474 475namespace PR30361 {476template <typename T>477struct C1 {478 ~C1() {}479 operator C1<T>* () { return nullptr; }480 void foo1();481};482 483template<typename T>484void C1<T>::foo1() {485 C1::operator C1<T>*();486 C1::~C1();487}488 489void foo1() {490 C1<int> x;491 x.foo1();492}493}494 495namespace DtorTypedef {496 struct A { ~A(); };497 using A = A;498 DtorTypedef::A::~A() {}499 500 // This is invalid, but compilers accept it.501 struct B { ~B(); };502 namespace N { using B = B; }503 N::B::~B() {} // expected-error {{destructor cannot be declared using a type alias}}504 505#pragma clang diagnostic push506#pragma clang diagnostic ignored "-Wdtor-typedef"507 struct C { ~C(); };508 namespace N { using C = C; }509 N::C::~C() {}510#pragma clang diagnostic pop511}512 513// Ignore ambiguity errors in destructor name lookup. This matches the observed514// behavior of ICC, and is compatible with the observed behavior of GCC (which515// appears to ignore lookups that result in ambiguity) and MSVC (which appears516// to perform the lookups in the opposite order from Clang).517namespace PR44978 {518 // All compilers accept this despite it being clearly ill-formed per the519 // current wording.520 namespace n {521 class Foo {}; // expected-note {{found}}522 }523 class Foo {}; // expected-note {{found}}524 using namespace n;525 static void func(n::Foo *p) { p->~Foo(); } // expected-warning {{ambiguous}}526 527 // GCC rejects this case, ICC accepts, despite the class member lookup being528 // ambiguous.529 struct Z;530 struct X { using T = Z; }; // expected-note {{found}}531 struct Y { using T = int; }; // expected-note {{found}}532 struct Z : X, Y {};533 void f(Z *p) { p->~T(); } // expected-warning {{ambiguous}}534 535 // GCC accepts this and ignores the ambiguous class member lookup.536 //537 // FIXME: We should warn on the ambiguity here too, but that requires us to538 // keep doing lookups after we've already found the type we want.539 using T = Z;540 void g(Z *p) { p->~T(); }541 542 // ICC accepts this and ignores the ambiguous unqualified lookup.543 struct Q {};544 namespace { using U = Q; } // expected-note {{candidate}} expected-note {{found}}545 using U = int; // expected-note {{candidate}} expected-note {{found}}546 void f(Q *p) { p->~U(); } // expected-warning {{ambiguous}}547 548 // We still diagnose if the unqualified lookup is dependent, though.549 template<typename T> void f(T *p) { p->~U(); } // expected-error {{ambiguous}}550}551 552namespace crash_on_invalid_base_dtor {553struct Test {554 virtual ~Test();555};556struct Baz : public Test {557 Baz() {}558 ~Baz() = defaul; // expected-error {{undeclared identifier 'defaul'}}559};560struct Foo : public Baz {561 Foo() {}562};563}564 565namespace GH89544 {566class Foo {567 ~Foo() = {}568 // expected-error@-1 {{initializer on function does not look like a pure-specifier}}569 // expected-error@-2 {{expected ';' at end of declaration list}}570};571 572static_assert(!__is_trivially_constructible(Foo), "");573static_assert(!__is_trivially_constructible(Foo, const Foo &), "");574static_assert(!__is_trivially_constructible(Foo, Foo &&), "");575} // namespace GH89544576 577namespace GH97230 {578struct X {579 ~X() = defaul; // expected-error {{use of undeclared identifier 'defaul'}}580};581struct Y : X {} y1{ };582}583 584namespace GH121706 {585struct A {586 *&~A(); // expected-error {{invalid destructor declaration}}587};588 589struct B {590 *&&~B(); // expected-error {{invalid destructor declaration}}591};592 593struct C {594 *const ~C(); // expected-error {{invalid destructor declaration}}595};596 597struct D {598 *const * ~D(); // expected-error {{invalid destructor declaration}}599};600 601struct E {602 *E::*~E(); // expected-error {{invalid destructor declaration}}603};604 605struct F {606 *F::*const ~F(); // expected-error {{invalid destructor declaration}}607};608 609struct G {610 ****~G(); // expected-error {{invalid destructor declaration}}611};612 613struct H {614 **~H(); // expected-error {{invalid destructor declaration}}615};616 617struct I {618 *~I(); // expected-error {{invalid destructor declaration}}619};620 621struct J {622 *&~J(); // expected-error {{invalid destructor declaration}}623};624 625struct K {626 **&&~K(); // expected-error {{invalid destructor declaration}}627};628}629 630#endif // BE_THE_HEADER631