cxx2a-destroying-delete.cpp
5.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// RUN: %clang_cc1 -std=c++2a -fexceptions -verify %s
// 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; // expected-note 0-1 {{deleted here}}
};
// TODO: We only diagnose the use of a deleted operator delete when exceptions
// are enabled. Otherwise we don't bother doing the lookup.
#ifdef __EXCEPTIONS
// expected-error@+2 {{attempt to use a deleted function}}
#endif
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':}}
}
}
namespace templated {
template<typename T> using id_alias = T;
template<typename T> struct id_struct { using type = T; };
template<typename T> struct A {
void operator delete(A *, std::destroying_delete_t);
};
template<typename T> struct B {
void operator delete(B<T> *, std::destroying_delete_t);
};
template<typename T> struct C {
void operator delete(id_alias<C> *, std::destroying_delete_t);
};
template<typename T> struct D {
void operator delete(typename id_struct<D>::type *, std::destroying_delete_t); // expected-error {{use 'D<T> *'}}
};
}