314 lines · cpp
1// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s -DNEW=__builtin_operator_new -DDELETE=__builtin_operator_delete2// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s "-DNEW=operator new" "-DDELETE=operator delete"3// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s "-DNEW=::operator new" "-DDELETE=::operator delete"4// RUN: %clang_cc1 -std=c++2c -verify=expected,cxx26 %s "-DNEW=::operator new" "-DDELETE=::operator delete"5 6// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s -DNEW=__builtin_operator_new -DDELETE=__builtin_operator_delete -fexperimental-new-constant-interpreter7// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s "-DNEW=operator new" "-DDELETE=operator delete" -fexperimental-new-constant-interpreter8// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx20 %s "-DNEW=::operator new" "-DDELETE=::operator delete" -fexperimental-new-constant-interpreter9// RUN: %clang_cc1 -std=c++2c -verify=expected,cxx26 %s "-DNEW=::operator new" "-DDELETE=::operator delete" -fexperimental-new-constant-interpreter10 11constexpr bool alloc_from_user_code() {12 void *p = NEW(sizeof(int)); // expected-note {{cannot allocate untyped memory in a constant expression; use 'std::allocator<T>::allocate'}}13 DELETE(p);14 return true;15}16static_assert(alloc_from_user_code()); // expected-error {{constant expression}} expected-note {{in call}}17 18namespace std {19 using size_t = decltype(sizeof(0));20 template<typename T> struct allocator {21 constexpr T *allocate(size_t N) {22 return (T*)NEW(sizeof(T) * N);23 }24 constexpr void deallocate(void *p) {25 DELETE(p); // #dealloc expected-note 2{{'std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}}26 }27 };28}29 30constexpr bool alloc_via_std_allocator() {31 std::allocator<int> alloc;32 int *p = alloc.allocate(1);33 alloc.deallocate(p);34 return true;35}36static_assert(alloc_via_std_allocator());37 38template<> struct std::allocator<void()> {39 constexpr void *allocate() { return NEW(8); } // expected-note {{cannot allocate memory of function type 'void ()'}}40};41constexpr void *fn = std::allocator<void()>().allocate(); // expected-error {{constant expression}} expected-note {{in call}}42 43struct Incomplete;44template<> struct std::allocator<Incomplete> {45 constexpr void *allocate() { return NEW(8); } // expected-note {{cannot allocate memory of incomplete type 'Incomplete'}}46};47constexpr void *incomplete = std::allocator<Incomplete>().allocate(); // expected-error {{constant expression}} expected-note {{in call}}48 49struct WrongSize { char x[5]; };50static_assert(sizeof(WrongSize) == 5);51template<> struct std::allocator<WrongSize> {52 constexpr void *allocate() { return NEW(7); } // expected-note {{allocated size 7 is not a multiple of size 5 of element type 'WrongSize'}}53};54constexpr void *wrong_size = std::allocator<WrongSize>().allocate(); // expected-error {{constant expression}} expected-note {{in call}}55 56constexpr bool mismatched(int alloc_kind, int dealloc_kind) {57 int *p;58 switch (alloc_kind) {59 case 0:60 p = new int; // expected-note {{heap allocation}}61 break;62 case 1:63 p = new int[1]; // expected-note {{heap allocation}}64 break;65 case 2:66 p = std::allocator<int>().allocate(1); // expected-note 2{{heap allocation}}67 break;68 }69 switch (dealloc_kind) {70 case 0:71 delete p; // expected-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}}72 break;73 case 1:74 delete[] p; // expected-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}}75 break;76 case 2:77 std::allocator<int>().deallocate(p); // expected-note 2{{in call}}78 break;79 }80 return true;81}82static_assert(mismatched(0, 2)); // expected-error {{constant expression}} expected-note {{in call}}83static_assert(mismatched(1, 2)); // expected-error {{constant expression}} expected-note {{in call}}84static_assert(mismatched(2, 0)); // expected-error {{constant expression}} expected-note {{in call}}85static_assert(mismatched(2, 1)); // expected-error {{constant expression}} expected-note {{in call}}86static_assert(mismatched(2, 2));87 88constexpr int *escape = std::allocator<int>().allocate(3); // expected-error {{constant expression}} expected-note {{pointer to subobject of heap-allocated}} \89 // expected-note {{heap allocation performed here}}90constexpr int leak = (std::allocator<int>().allocate(3), 0); // expected-error {{constant expression}} \91 // expected-note {{not deallocated}}92constexpr int no_lifetime_start = (*std::allocator<int>().allocate(1) = 1); // expected-error {{constant expression}} expected-note {{assignment to object outside its lifetime}}93constexpr int no_deallocate_nullptr = (std::allocator<int>().deallocate(nullptr), 1); // expected-error {{constant expression}} expected-note {{in call}}94// expected-note@#dealloc {{'std::allocator<...>::deallocate' used to delete a null pointer}}95constexpr int no_deallocate_nonalloc = (std::allocator<int>().deallocate((int*)&no_deallocate_nonalloc), 1); // expected-error {{constant expression}} expected-note {{in call}}96// expected-note@#dealloc {{delete of pointer '&no_deallocate_nonalloc' that does not point to a heap-allocated object}}97// expected-note@-2 {{declared here}}98 99void *operator new(std::size_t, void *p) { return p; }100void* operator new[] (std::size_t, void* p) {return p;}101constexpr bool no_placement_new_in_user_code() { // cxx20-error {{constexpr function never produces a constant expression}}102 int a;103 new (&a) int(42); // cxx20-note {{this placement new expression is not supported in constant expressions before C++2c}}104 return a == 42;105}106 107namespace std {108 constexpr bool placement_new_in_stdlib() {109 int a;110 new (&a) int(42);111 return a == 42;112 }113}114static_assert(std::placement_new_in_stdlib());115 116namespace std {117 template<typename T, typename ...Args>118 constexpr void construct_at(void *p, Args &&...args) {119 new (p) T((Args&&)args...); // #new120 }121}122 123constexpr bool call_std_construct_at() {124 int *p = std::allocator<int>().allocate(3);125 std::construct_at<int>(p, 1);126 std::construct_at<int>(p + 1, 2);127 std::construct_at<int>(p + 2, 3);128 bool good = p[0] + p[1] + p[2] == 6;129 std::allocator<int>().deallocate(p);130 return good;131}132static_assert(call_std_construct_at());133 134constexpr bool bad_construct_at_type() {135 int a;136 // expected-note@#new {{placement new would change type of storage from 'int' to 'float'}}137 std::construct_at<float>(&a, 1.0f); // expected-note {{in call}}138 return true;139}140static_assert(bad_construct_at_type()); // expected-error{{}} expected-note {{in call}}141 142constexpr bool bad_construct_at_subobject() {143 struct X { int a, b; };144 union A {145 int a;146 X x;147 };148 A a = {1};149 // expected-note@#new {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}}150 std::construct_at<int>(&a.x.a, 1); // expected-note {{in call}}151 return true;152}153static_assert(bad_construct_at_subobject()); // expected-error{{}} expected-note {{in call}}154 155constexpr bool change_union_member() {156 union U {157 int a;158 int b;159 };160 U u = {.a = 1};161 std::construct_at<int>(&u.b, 2);162 return u.b == 2;163}164static_assert(change_union_member());165 166int external;167// expected-note@#new {{visible outside}}168static_assert((std::construct_at<int>(&external, 1), true)); // expected-error{{}} expected-note {{in call}}169 170constexpr int &&temporary = 0; // expected-note {{created here}}171// expected-note@#new {{construction of temporary is not allowed in a constant expression outside the expression that created the temporary}}172static_assert((std::construct_at<int>(&temporary, 1), true)); // expected-error{{}} expected-note {{in call}}173 174constexpr bool construct_after_lifetime() {175 int *p = new int;176 delete p;177 // expected-note@#new {{construction of heap allocated object that has been deleted}}178 std::construct_at<int>(p); // expected-note {{in call}}179 return true;180}181static_assert(construct_after_lifetime()); // expected-error {{}} expected-note {{in call}}182 183constexpr bool construct_after_lifetime_2() {184 struct A { struct B {} b; };185 A a;186 a.~A();187 std::construct_at<A::B>(&a.b); // expected-note {{in call}}188 // expected-note@#new {{construction of subobject of object outside its lifetime is not allowed in a constant expression}}189 return true;190}191static_assert(construct_after_lifetime_2()); // expected-error {{}} expected-note {{in call}}192 193namespace PR48606 {194 struct A { mutable int n = 0; };195 196 constexpr bool f() {197 A a;198 A *p = &a;199 p->~A();200 std::construct_at<A>(p);201 return true;202 }203 static_assert(f());204 205 constexpr bool g() {206 A *p = new A;207 p->~A();208 std::construct_at<A>(p);209 delete p;210 return true;211 }212 static_assert(g());213 214 constexpr bool h() {215 std::allocator<A> alloc;216 A *p = alloc.allocate(1);217 std::construct_at<A>(p);218 p->~A();219 std::construct_at<A>(p);220 p->~A();221 alloc.deallocate(p);222 return true;223 }224 static_assert(h());225}226 227namespace GH62462 {228 229class string {230public:231 char *mem;232 constexpr string() {233 this->mem = new char(1);234 }235 constexpr ~string() {236 delete this->mem;237 }238 constexpr unsigned size() const { return 4; }239};240 241 242template <unsigned N>243void test() {};244 245void f() {246 test<string().size()>();247}248 249}250 251namespace GH134820 {252struct S {253 char* c = new char;254 constexpr ~S() {255 delete c;256 }257 int i = 0;258};259 260int f() {261 if constexpr((S{}, true)) { // expected-warning{{left operand of comma operator has no effect}}262 return 1;263 }264 if constexpr(S s; (S{}, true)) { // expected-warning{{left operand of comma operator has no effect}}265 return 1;266 }267 if constexpr(S s; (s, true)) { // expected-warning{{left operand of comma operator has no effect}}268 return 1;269 }270 if constexpr(constexpr int _ = S{}.i; true) {271 return 1;272 }273 return 0;274}275 276template <typename T>277int f2() {278 if constexpr((T{}, true)) { // expected-warning{{left operand of comma operator has no effect}}279 return 1;280 }281 if constexpr(T s; (T{}, true)) { // expected-warning{{left operand of comma operator has no effect}}282 return 1;283 }284 if constexpr(T s; (s, true)) { // expected-warning{{left operand of comma operator has no effect}}285 return 1;286 }287 if constexpr(constexpr int _ = T{}.i; true) {288 return 1;289 }290 return 0;291}292 293void test() {294 f2<S>(); // expected-note {{in instantiation}}295}296 297}298namespace GH120197{299struct NonTrivialDtor {300 NonTrivialDtor() = default;301 NonTrivialDtor(const NonTrivialDtor&) = default;302 NonTrivialDtor(NonTrivialDtor&&) = default;303 NonTrivialDtor& operator=(const NonTrivialDtor&) = default;304 NonTrivialDtor& operator=(NonTrivialDtor&&) = default;305 constexpr ~NonTrivialDtor() noexcept {}306};307 308static_assert(((void)NonTrivialDtor{}, true)); // passes309 310void f() {311 if constexpr ((void)NonTrivialDtor{}, true) {}312}313}314