brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.6 KiB · bc47d87 Raw
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