diff options
Diffstat (limited to 'test/SemaCXX/cxx2a-destroying-delete.cpp')
-rw-r--r-- | test/SemaCXX/cxx2a-destroying-delete.cpp | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/test/SemaCXX/cxx2a-destroying-delete.cpp b/test/SemaCXX/cxx2a-destroying-delete.cpp new file mode 100644 index 000000000000..6115774e3836 --- /dev/null +++ b/test/SemaCXX/cxx2a-destroying-delete.cpp @@ -0,0 +1,122 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +namespace std { + using size_t = decltype(sizeof(0)); + enum class align_val_t : size_t; + + struct destroying_delete_t { + struct __construct { explicit __construct() = default; }; + explicit destroying_delete_t(__construct) {} + }; + + inline constexpr destroying_delete_t destroying_delete(destroying_delete_t::__construct()); +} + +void operator delete(void*, std::destroying_delete_t); // ok, just a placement delete + +struct A; +void operator delete(A*, std::destroying_delete_t); // expected-error {{first parameter of 'operator delete' must have type 'void *'}} + +struct A { + void operator delete(A*, std::destroying_delete_t); + void operator delete(A*, std::destroying_delete_t, std::size_t); + void operator delete(A*, std::destroying_delete_t, std::align_val_t); + void operator delete(A*, std::destroying_delete_t, std::size_t, std::align_val_t); + void operator delete(A*, std::destroying_delete_t, int); // expected-error {{destroying operator delete can have only an optional size and optional alignment parameter}} + // FIXME: It's probably a language defect that we permit usual operator delete to be variadic. + void operator delete(A*, std::destroying_delete_t, std::size_t, ...); + + void operator delete(struct X*, std::destroying_delete_t, std::size_t, ...); // expected-error {{first parameter of 'operator delete' must have type 'A *'}} + + void operator delete(void*, std::size_t); +}; + +void delete_A(A *a) { delete a; } + +namespace convert_param { + struct A { + void operator delete( + A*, + std::destroying_delete_t); + }; + struct B : private A { using A::operator delete; }; // expected-note 2{{declared private here}} + struct C : B {}; + void delete_C(C *c) { delete c; } // expected-error {{cannot cast 'convert_param::C' to its private base class 'convert_param::A'}} + + // expected-error@-7 {{cannot cast 'convert_param::D' to its private base class 'convert_param::A'}} + struct D : B { virtual ~D() {} }; // expected-note {{while checking implicit 'delete this' for virtual destructor}} +} + +namespace delete_selection { + struct B { + void operator delete(void*) = delete; + void operator delete(B *, std::destroying_delete_t) = delete; // expected-note {{deleted}} + }; + void delete_B(B *b) { delete b; } // expected-error {{deleted}} + + struct C { + C(); + void *operator new(std::size_t); + void operator delete(void*) = delete; + void operator delete(C *, std::destroying_delete_t) = delete; + }; + // FIXME: This should be ill-formed, but we incorrectly decide that overload + // resolution failed (because it selected a deleted function) and thus no + // 'operator delete' should be called. + C *new_C() { return new C; } + + struct D { + void operator delete(D *, std::destroying_delete_t) = delete; // expected-note {{deleted}} + void operator delete(D *, std::destroying_delete_t, std::align_val_t) = delete; + }; + void delete_D(D *d) { delete d; } // expected-error {{deleted}} + + struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) E { + void operator delete(E *, std::destroying_delete_t) = delete; + void operator delete(E *, std::destroying_delete_t, std::align_val_t) = delete; // expected-note {{deleted}} + }; + void delete_E(E *e) { delete e; } // expected-error {{deleted}} + + struct F { + void operator delete(F *, std::destroying_delete_t) = delete; // expected-note {{deleted}} + void operator delete(F *, std::destroying_delete_t, std::size_t) = delete; + }; + void delete_F(F *f) { delete f; } // expected-error {{deleted}} + + struct G { + void operator delete(G *, std::destroying_delete_t, std::align_val_t) = delete; + void operator delete(G *, std::destroying_delete_t, std::size_t) = delete; // expected-note {{deleted}} + }; + void delete_G(G *g) { delete g; } // expected-error {{deleted}} + + struct H { + void operator delete(H *, std::destroying_delete_t, std::align_val_t) = delete; // expected-note {{deleted}} + void operator delete(H *, std::destroying_delete_t, std::size_t, std::align_val_t) = delete; + }; + void delete_H(H *h) { delete h; } // expected-error {{deleted}} + + struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) I { + void operator delete(I *, std::destroying_delete_t, std::size_t) = delete; + void operator delete(I *, std::destroying_delete_t, std::size_t, std::align_val_t) = delete; // expected-note {{deleted}} + }; + void delete_I(I *i) { delete i; } // expected-error {{deleted}} +} + +namespace first_param_conversion { + struct A { + void operator delete(A *, std::destroying_delete_t); + }; + void f(const volatile A *a) { + delete a; // ok + } + + struct B { + void operator delete(B *, std::destroying_delete_t); + }; + struct C : B {}; + struct D : B {}; + struct E : C, D {}; + void g(E *e) { + delete e; // expected-error {{ambiguous conversion from derived class 'first_param_conversion::E' to base class 'first_param_conversion::B':}} + } +} |