1 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s 2 // RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s 3 // RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s 4 // RUN: %clang_cc1 -verify=ref,both %s 5 // RUN: %clang_cc1 -std=c++20 -verify=ref,both %s 6 // RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -verify=ref,both %s 7 8 #if __cplusplus >= 202002L 9 10 constexpr int *Global = new int(12); // both-error {{must be initialized by a constant expression}} \ 11 // both-note {{pointer to heap-allocated object}} \ 12 // both-note {{heap allocation performed here}} 13 14 static_assert(*(new int(12)) == 12); // both-error {{not an integral constant expression}} \ 15 // both-note {{allocation performed here was not deallocated}} 16 17 18 constexpr int a() { 19 new int(12); // both-note {{allocation performed here was not deallocated}} 20 return 1; 21 } 22 static_assert(a() == 1, ""); // both-error {{not an integral constant expression}} 23 24 constexpr int b() { 25 int *i = new int(12); 26 int m = *i; 27 delete(i); 28 return m; 29 } 30 static_assert(b() == 12, ""); 31 32 33 struct S { 34 int a; 35 int b; 36 37 static constexpr S *create(int a, int b) { 38 return new S(a, b); 39 } 40 }; 41 42 constexpr int c() { 43 S *s = new S(12, 13); 44 45 int i = s->a; 46 delete s; 47 48 return i; 49 } 50 static_assert(c() == 12, ""); 51 52 /// Dynamic allocation in function ::create(), freed in function d(). 53 constexpr int d() { 54 S* s = S::create(12, 14); 55 56 int sum = s->a + s->b; 57 delete s; 58 return sum; 59 } 60 static_assert(d() == 26); 61 62 63 /// Test we emit the right diagnostic for several allocations done on 64 /// the same site. 65 constexpr int loop() { 66 for (int i = 0; i < 10; ++i) { 67 int *a = new int[10]; // both-note {{not deallocated (along with 9 other memory leaks)}} 68 } 69 70 return 1; 71 } 72 static_assert(loop() == 1, ""); // both-error {{not an integral constant expression}} 73 74 /// No initializer. 75 constexpr int noInit() { 76 int *i = new int; 77 delete i; 78 return 0; 79 } 80 static_assert(noInit() == 0, ""); 81 82 /// Try to delete a pointer that hasn't been heap allocated. 83 constexpr int notHeapAllocated() { // both-error {{never produces a constant expression}} 84 int A = 0; // both-note 2{{declared here}} 85 delete &A; // ref-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}} \ 86 // expected-note 2{{delete of pointer '&A' that does not point to a heap-allocated object}} 87 88 return 1; 89 } 90 static_assert(notHeapAllocated() == 1, ""); // both-error {{not an integral constant expression}} \ 91 // both-note {{in call to 'notHeapAllocated()'}} 92 93 consteval int deleteNull() { 94 int *A = nullptr; 95 delete A; 96 return 1; 97 } 98 static_assert(deleteNull() == 1, ""); 99 100 consteval int doubleDelete() { // both-error {{never produces a constant expression}} 101 int *A = new int; 102 delete A; 103 delete A; // both-note 2{{delete of pointer that has already been deleted}} 104 return 1; 105 } 106 static_assert(doubleDelete() == 1); // both-error {{not an integral constant expression}} \ 107 // both-note {{in call to 'doubleDelete()'}} 108 109 constexpr int AutoArray() { 110 auto array = new int[]{0, 1, 2, 3}; 111 int ret = array[3]; 112 delete [] array; 113 return ret; 114 } 115 116 static_assert(AutoArray() == 3); 117 118 #if 0 119 consteval int largeArray1(bool b) { 120 if (b) { 121 int *a = new int[1ull<<32]; // both-note {{cannot allocate array; evaluated array bound 4294967296 is too large}} 122 delete[] a; 123 } 124 return 1; 125 } 126 static_assert(largeArray1(false) == 1, ""); 127 static_assert(largeArray1(true) == 1, ""); // both-error {{not an integral constant expression}} \ 128 // both-note {{in call to 'largeArray1(true)'}} 129 130 consteval int largeArray2(bool b) { 131 if (b) { 132 S *a = new S[1ull<<32]; // both-note {{cannot allocate array; evaluated array bound 4294967296 is too large}} 133 delete[] a; 134 } 135 return 1; 136 } 137 static_assert(largeArray2(false) == 1, ""); 138 static_assert(largeArray2(true) == 1, ""); // both-error {{not an integral constant expression}} \ 139 // both-note {{in call to 'largeArray2(true)'}} 140 #endif 141 namespace Arrays { 142 constexpr int d() { 143 int *Arr = new int[12]; 144 145 Arr[0] = 1; 146 Arr[1] = 5; 147 148 int sum = Arr[0] + Arr[1]; 149 delete[] Arr; 150 return sum; 151 } 152 static_assert(d() == 6); 153 154 155 constexpr int mismatch1() { // both-error {{never produces a constant expression}} 156 int *i = new int(12); // both-note {{allocated with 'new' here}} \ 157 // both-note 2{{heap allocation performed here}} 158 delete[] i; // both-warning {{'delete[]' applied to a pointer that was allocated with 'new'}} \ 159 // both-note 2{{array delete used to delete pointer to non-array object of type 'int'}} 160 return 6; 161 } 162 static_assert(mismatch1() == 6); // both-error {{not an integral constant expression}} \ 163 // both-note {{in call to 'mismatch1()'}} 164 165 constexpr int mismatch2() { // both-error {{never produces a constant expression}} 166 int *i = new int[12]; // both-note {{allocated with 'new[]' here}} \ 167 // both-note 2{{heap allocation performed here}} 168 delete i; // both-warning {{'delete' applied to a pointer that was allocated with 'new[]'}} \ 169 // both-note 2{{non-array delete used to delete pointer to array object of type 'int[12]'}} 170 return 6; 171 } 172 static_assert(mismatch2() == 6); // both-error {{not an integral constant expression}} \ 173 // both-note {{in call to 'mismatch2()'}} 174 /// Array of composite elements. 175 constexpr int foo() { 176 S *ss = new S[12]; 177 178 ss[0].a = 12; 179 180 int m = ss[0].a; 181 182 delete[] ss; 183 return m; 184 } 185 static_assert(foo() == 12); 186 187 188 189 constexpr int ArrayInit() { 190 auto array = new int[4]{0, 1, 2, 3}; 191 int ret = array[0]; 192 delete [] array; 193 return ret; 194 } 195 static_assert(ArrayInit() == 0, ""); 196 197 struct S { 198 float F; 199 }; 200 constexpr float ArrayInit2() { 201 auto array = new S[4]{}; 202 float ret = array[0].F; 203 delete [] array; 204 return ret; 205 } 206 static_assert(ArrayInit2() == 0.0f, ""); 207 } 208 209 namespace std { 210 struct type_info; 211 struct destroying_delete_t { 212 explicit destroying_delete_t() = default; 213 } inline constexpr destroying_delete{}; 214 struct nothrow_t { 215 explicit nothrow_t() = default; 216 } inline constexpr nothrow{}; 217 using size_t = decltype(sizeof(0)); 218 enum class align_val_t : size_t {}; 219 }; 220 221 [[nodiscard]] void *operator new(std::size_t, const std::nothrow_t&) noexcept; 222 [[nodiscard]] void *operator new(std::size_t, std::align_val_t, const std::nothrow_t&) noexcept; 223 [[nodiscard]] void *operator new[](std::size_t, const std::nothrow_t&) noexcept; 224 [[nodiscard]] void *operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) noexcept; 225 [[nodiscard]] void *operator new[](std::size_t, std::align_val_t); 226 void operator delete(void*, const std::nothrow_t&) noexcept; 227 void operator delete(void*, std::align_val_t, const std::nothrow_t&) noexcept; 228 void operator delete[](void*, const std::nothrow_t&) noexcept; 229 void operator delete[](void*, std::align_val_t, const std::nothrow_t&) noexcept; 230 231 struct placement_new_arg {}; 232 void *operator new(std::size_t, placement_new_arg); 233 void operator delete(void*, placement_new_arg); 234 235 236 constexpr void *operator new(std::size_t, void *p) { return p; } 237 namespace std { 238 template<typename T> constexpr T *construct(T *p) { return new (p) T; } 239 template<typename T> constexpr void destroy(T *p) { p->~T(); } 240 } 241 242 243 244 namespace PlacementNew { 245 constexpr int foo() { // both-error {{never produces a constant expression}} 246 char c[sizeof(int)]; 247 new (c) int{12}; // both-note {{this placement new expression is not supported in constant expressions before C++2c}} 248 return 0; 249 } 250 } 251 252 namespace NowThrowNew { 253 constexpr bool erroneous_array_bound_nothrow(long long n) { 254 int *p = new (std::nothrow) int[n]; 255 bool result = p != nullptr; 256 delete[] p; 257 return result; 258 } 259 static_assert(erroneous_array_bound_nothrow(3)); 260 static_assert(erroneous_array_bound_nothrow(0)); 261 static_assert(erroneous_array_bound_nothrow(-1) == 0); 262 static_assert(!erroneous_array_bound_nothrow(1LL << 62)); 263 264 struct S { int a; }; 265 constexpr bool erroneous_array_bound_nothrow2(long long n) { 266 S *p = new (std::nothrow) S[n]; 267 bool result = p != nullptr; 268 delete[] p; 269 return result; 270 } 271 /// This needs support for CXXConstrucExprs with non-constant array sizes. 272 static_assert(erroneous_array_bound_nothrow2(3)); // expected-error {{not an integral constant expression}} 273 static_assert(erroneous_array_bound_nothrow2(0));// expected-error {{not an integral constant expression}} 274 static_assert(erroneous_array_bound_nothrow2(-1) == 0);// expected-error {{not an integral constant expression}} 275 static_assert(!erroneous_array_bound_nothrow2(1LL << 62));// expected-error {{not an integral constant expression}} 276 277 constexpr bool erroneous_array_bound(long long n) { 278 delete[] new int[n]; // both-note {{array bound -1 is negative}} both-note {{array bound 4611686018427387904 is too large}} 279 return true; 280 } 281 static_assert(erroneous_array_bound(3)); 282 static_assert(erroneous_array_bound(0)); 283 static_assert(erroneous_array_bound(-1)); // both-error {{constant expression}} both-note {{in call}} 284 static_assert(erroneous_array_bound(1LL << 62)); // both-error {{constant expression}} both-note {{in call}} 285 286 constexpr bool evaluate_nothrow_arg() { 287 bool ok = false; 288 delete new ((ok = true, std::nothrow)) int; 289 return ok; 290 } 291 static_assert(evaluate_nothrow_arg()); 292 } 293 294 namespace placement_new_delete { 295 struct ClassSpecificNew { 296 void *operator new(std::size_t); 297 }; 298 struct ClassSpecificDelete { 299 void operator delete(void*); 300 }; 301 struct DestroyingDelete { 302 void operator delete(DestroyingDelete*, std::destroying_delete_t); 303 }; 304 struct alignas(64) Overaligned {}; 305 306 constexpr bool ok() { 307 delete new Overaligned; 308 delete ::new ClassSpecificNew; 309 ::delete new ClassSpecificDelete; 310 ::delete new DestroyingDelete; 311 return true; 312 } 313 static_assert(ok()); 314 315 constexpr bool bad(int which) { 316 switch (which) { 317 case 0: 318 delete new (placement_new_arg{}) int; // both-note {{this placement new expression is not supported in constant expressions}} 319 break; 320 321 case 1: 322 delete new ClassSpecificNew; // both-note {{call to class-specific 'operator new'}} 323 break; 324 325 case 2: 326 delete new ClassSpecificDelete; // both-note {{call to class-specific 'operator delete'}} 327 break; 328 329 case 3: 330 delete new DestroyingDelete; // both-note {{call to class-specific 'operator delete'}} 331 break; 332 333 case 4: 334 // FIXME: This technically follows the standard's rules, but it seems 335 // unreasonable to expect implementations to support this. 336 delete new (std::align_val_t{64}) Overaligned; // both-note {{this placement new expression is not supported in constant expressions}} 337 break; 338 } 339 340 return true; 341 } 342 static_assert(bad(0)); // both-error {{constant expression}} \ 343 // both-note {{in call}} 344 static_assert(bad(1)); // both-error {{constant expression}} both-note {{in call}} 345 static_assert(bad(2)); // both-error {{constant expression}} both-note {{in call}} 346 static_assert(bad(3)); // both-error {{constant expression}} both-note {{in call}} 347 static_assert(bad(4)); // both-error {{constant expression}} \ 348 // both-note {{in call}} 349 } 350 351 352 353 354 namespace delete_random_things { 355 static_assert((delete new int, true)); 356 static_assert((delete (int*)0, true)); 357 int n; // both-note {{declared here}} 358 static_assert((delete &n, true)); // both-error {{}} \ 359 // both-note {{delete of pointer '&n' that does not point to a heap-allocated object}} 360 struct A { int n; }; 361 static_assert((delete &(new A)->n, true)); // both-error {{}} \ 362 // both-note {{delete of pointer to subobject }} 363 static_assert((delete (new int + 1), true)); // both-error {{}} \ 364 // ref-note {{delete of pointer '&{*new int#0} + 1' that does not point to complete object}} \ 365 // expected-note {{delete of pointer '&{*new int#1} + 1' that does not point to complete object}} 366 static_assert((delete[] (new int[3] + 1), true)); // both-error {{}} \ 367 // both-note {{delete of pointer to subobject}} 368 static_assert((delete &(int&)(int&&)0, true)); // both-error {{}} \ 369 // both-note {{delete of pointer '&0' that does not point to a heap-allocated object}} \ 370 // both-note {{temporary created here}} 371 } 372 373 namespace value_dependent_delete { 374 template<typename T> void f(T *p) { 375 int arr[(delete p, 0)]; 376 } 377 } 378 379 namespace memory_leaks { 380 static_assert(*new bool(true)); // both-error {{}} both-note {{allocation performed here was not deallocated}} 381 382 constexpr bool *f() { return new bool(true); } // both-note {{allocation performed here was not deallocated}} 383 static_assert(*f()); // both-error {{}} 384 385 struct UP { 386 bool *p; 387 constexpr ~UP() { delete p; } 388 constexpr bool &operator*() { return *p; } 389 }; 390 constexpr UP g() { return {new bool(true)}; } 391 static_assert(*g()); // ok 392 393 constexpr bool h(UP p) { return *p; } 394 static_assert(h({new bool(true)})); // ok 395 } 396 397 /// From test/SemaCXX/cxx2a-consteval.cpp 398 399 namespace std { 400 template <typename T> struct remove_reference { using type = T; }; 401 template <typename T> struct remove_reference<T &> { using type = T; }; 402 template <typename T> struct remove_reference<T &&> { using type = T; }; 403 template <typename T> 404 constexpr typename std::remove_reference<T>::type&& move(T &&t) noexcept { 405 return static_cast<typename std::remove_reference<T>::type &&>(t); 406 } 407 } 408 409 namespace cxx2a { 410 struct A { 411 int* p = new int(42); // both-note 3{{heap allocation performed here}} 412 consteval int ret_i() const { return p ? *p : 0; } 413 consteval A ret_a() const { return A{}; } 414 constexpr ~A() { delete p; } 415 }; 416 417 consteval int by_value_a(A a) { return a.ret_i(); } 418 419 consteval int const_a_ref(const A &a) { 420 return a.ret_i(); 421 } 422 423 consteval int rvalue_ref(const A &&a) { 424 return a.ret_i(); 425 } 426 427 consteval const A &to_lvalue_ref(const A &&a) { 428 return a; 429 } 430 431 void test() { 432 constexpr A a{ nullptr }; 433 { int k = A().ret_i(); } 434 435 { A k = A().ret_a(); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \ 436 // both-note {{heap-allocated object is not a constant expression}} 437 { A k = to_lvalue_ref(A()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \ 438 // both-note {{reference to temporary is not a constant expression}} \ 439 // both-note {{temporary created here}} 440 { A k = to_lvalue_ref(A().ret_a()); } // both-error {{'cxx2a::to_lvalue_ref' is not a constant expression}} \ 441 // both-note {{reference to temporary is not a constant expression}} \ 442 // both-note {{temporary created here}} 443 { int k = A().ret_a().ret_i(); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \ 444 // both-note {{heap-allocated object is not a constant expression}} 445 { int k = by_value_a(A()); } 446 { int k = const_a_ref(A()); } 447 { int k = const_a_ref(a); } 448 { int k = rvalue_ref(A()); } 449 { int k = rvalue_ref(std::move(a)); } 450 { int k = const_a_ref(A().ret_a()); } 451 { int k = const_a_ref(to_lvalue_ref(A().ret_a())); } 452 { int k = const_a_ref(to_lvalue_ref(std::move(a))); } 453 { int k = by_value_a(A().ret_a()); } 454 { int k = by_value_a(to_lvalue_ref(static_cast<const A&&>(a))); } 455 { int k = (A().ret_a(), A().ret_i()); } // both-error {{'cxx2a::A::ret_a' is not a constant expression}} \ 456 // both-note {{is not a constant expression}} \ 457 // both-warning {{left operand of comma operator has no effect}} 458 { int k = (const_a_ref(A().ret_a()), A().ret_i()); } // both-warning {{left operand of comma operator has no effect}} 459 } 460 } 461 462 constexpr int *const &p = new int; // both-error {{must be initialized by a constant expression}} \ 463 // both-note {{pointer to heap-allocated object}} \ 464 // both-note {{allocation performed here}} 465 466 constexpr const int *A[] = {nullptr, nullptr, new int{12}}; // both-error {{must be initialized by a constant expression}} \ 467 // both-note {{pointer to heap-allocated object}} \ 468 // both-note {{allocation performed here}} 469 470 struct Sp { 471 const int *p; 472 }; 473 constexpr Sp ss[] = {Sp{new int{154}}}; // both-error {{must be initialized by a constant expression}} \ 474 // both-note {{pointer to heap-allocated object}} \ 475 // both-note {{allocation performed here}} 476 477 namespace DeleteRunsDtors { 478 struct InnerFoo { 479 int *mem; 480 constexpr ~InnerFoo() { 481 delete mem; 482 } 483 }; 484 485 struct Foo { 486 int *a; 487 InnerFoo IF; 488 489 constexpr Foo() { 490 a = new int(13); 491 IF.mem = new int(100); 492 } 493 constexpr ~Foo() { delete a; } 494 }; 495 496 constexpr int abc() { 497 Foo *F = new Foo(); 498 int n = *F->a; 499 delete F; 500 501 return n; 502 } 503 static_assert(abc() == 13); 504 505 constexpr int abc2() { 506 Foo *f = new Foo[3]; 507 508 delete[] f; 509 510 return 1; 511 } 512 static_assert(abc2() == 1); 513 } 514 515 /// FIXME: There is a slight difference in diagnostics here. 516 namespace FaultyDtorCalledByDelete { 517 struct InnerFoo { 518 int *mem; 519 constexpr ~InnerFoo() { 520 if (mem) { 521 (void)(1/0); // both-warning {{division by zero is undefined}} \ 522 // both-note {{division by zero}} 523 } 524 delete mem; 525 } 526 }; 527 528 struct Foo { 529 int *a; 530 InnerFoo IF; 531 532 constexpr Foo() { 533 a = new int(13); 534 IF.mem = new int(100); 535 } 536 constexpr ~Foo() { delete a; } // expected-note {{in call to}} 537 }; 538 539 constexpr int abc() { 540 Foo *F = new Foo(); 541 int n = *F->a; 542 delete F; // both-note {{in call to}} \ 543 // ref-note {{in call to}} 544 545 return n; 546 } 547 static_assert(abc() == 13); // both-error {{not an integral constant expression}} \ 548 // both-note {{in call to 'abc()'}} 549 } 550 551 namespace DeleteThis { 552 constexpr bool super_secret_double_delete() { 553 struct A { 554 constexpr ~A() { delete this; } // both-note {{destruction of object that is already being destroyed}} \ 555 // ref-note {{in call to}} 556 }; 557 delete new A; // both-note {{in call to}} 558 return true; 559 } 560 static_assert(super_secret_double_delete()); // both-error {{not an integral constant expression}} \ 561 // both-note {{in call to 'super_secret_double_delete()'}} 562 } 563 564 namespace CastedDelete { 565 struct S { 566 constexpr S(int *p) : p(p) {} 567 constexpr virtual ~S() { *p = 1; } 568 int *p; 569 }; 570 struct T: S { 571 // implicit destructor defined eagerly because it is constexpr and virtual 572 using S::S; 573 }; 574 575 constexpr int vdtor_1() { 576 int a; 577 delete (S*)new T(&a); 578 return a; 579 } 580 static_assert(vdtor_1() == 1); 581 582 constexpr int foo() { // both-error {{never produces a constant expression}} 583 struct S {}; 584 struct T : S {}; 585 S *p = new T(); 586 delete p; // both-note 2{{delete of object with dynamic type 'T' through pointer to base class type 'S' with non-virtual destructor}} 587 return 1; 588 } 589 static_assert(foo() == 1); // both-error {{not an integral constant expression}} \ 590 // both-note {{in call to}} 591 } 592 593 constexpr void use_after_free_2() { // both-error {{never produces a constant expression}} 594 struct X { constexpr void f() {} }; 595 X *p = new X; 596 delete p; 597 p->f(); // both-note {{member call on heap allocated object that has been deleted}} 598 } 599 600 /// std::allocator definition 601 namespace std { 602 using size_t = decltype(sizeof(0)); 603 template<typename T> struct allocator { 604 constexpr T *allocate(size_t N) { 605 return (T*)__builtin_operator_new(sizeof(T) * N); // #alloc 606 } 607 constexpr void deallocate(void *p) { 608 __builtin_operator_delete(p); // both-note 2{{std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}} \ 609 // both-note {{used to delete a null pointer}} 610 } 611 }; 612 template<typename T, typename ...Args> 613 constexpr void construct_at(void *p, Args &&...args) { // #construct 614 new (p) T((Args&&)args...); 615 } 616 } 617 618 /// Specialization for float, using operator new/delete. 619 namespace std { 620 using size_t = decltype(sizeof(0)); 621 template<> struct allocator<float> { 622 constexpr float *allocate(size_t N) { 623 return (float*)operator new (sizeof(float) * N); 624 } 625 constexpr void deallocate(void *p) { 626 operator delete(p); 627 } 628 }; 629 } 630 631 namespace OperatorNewDelete { 632 633 constexpr bool mismatched(int alloc_kind, int dealloc_kind) { 634 int *p; 635 switch (alloc_kind) { 636 case 0: 637 p = new int; // both-note {{heap allocation performed here}} 638 break; 639 case 1: 640 p = new int[1]; // both-note {{heap allocation performed here}} 641 break; 642 case 2: 643 p = std::allocator<int>().allocate(1); // both-note 2{{heap allocation performed here}} 644 break; 645 } 646 switch (dealloc_kind) { 647 case 0: 648 delete p; // both-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}} 649 break; 650 case 1: 651 delete[] p; // both-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}} 652 break; 653 case 2: 654 std::allocator<int>().deallocate(p); // both-note 2{{in call}} 655 break; 656 } 657 return true; 658 } 659 static_assert(mismatched(0, 2)); // both-error {{constant expression}} \ 660 // both-note {{in call to}} 661 static_assert(mismatched(1, 2)); // both-error {{constant expression}} \ 662 // both-note {{in call to}} 663 static_assert(mismatched(2, 0)); // both-error {{constant expression}} \ 664 // both-note {{in call}} 665 static_assert(mismatched(2, 1)); // both-error {{constant expression}} \ 666 // both-note {{in call}} 667 static_assert(mismatched(2, 2)); 668 669 constexpr bool zeroAlloc() { 670 int *F = std::allocator<int>().allocate(0); 671 std::allocator<int>().deallocate(F); 672 return true; 673 } 674 static_assert(zeroAlloc()); 675 676 /// FIXME: This is broken in the current interpreter. 677 constexpr int arrayAlloc() { 678 int *F = std::allocator<int>().allocate(2); 679 F[0] = 10; // ref-note {{assignment to object outside its lifetime is not allowed in a constant expression}} 680 F[1] = 13; 681 int Res = F[1] + F[0]; 682 std::allocator<int>().deallocate(F); 683 return Res; 684 } 685 static_assert(arrayAlloc() == 23); // ref-error {{not an integral constant expression}} \ 686 // ref-note {{in call to}} 687 688 struct S { 689 int i; 690 constexpr S(int i) : i(i) {} 691 constexpr ~S() { } 692 }; 693 694 /// FIXME: This is broken in the current interpreter. 695 constexpr bool structAlloc() { 696 S *s = std::allocator<S>().allocate(1); 697 698 s->i = 12; // ref-note {{assignment to object outside its lifetime is not allowed in a constant expression}} 699 700 bool Res = (s->i == 12); 701 std::allocator<S>().deallocate(s); 702 703 return Res; 704 } 705 static_assert(structAlloc()); // ref-error {{not an integral constant expression}} \ 706 // ref-note {{in call to}} 707 708 constexpr bool structAllocArray() { 709 S *s = std::allocator<S>().allocate(9); 710 711 s[2].i = 12; // ref-note {{assignment to object outside its lifetime is not allowed in a constant expression}} 712 bool Res = (s[2].i == 12); 713 std::allocator<S>().deallocate(s); 714 715 return Res; 716 } 717 static_assert(structAllocArray()); // ref-error {{not an integral constant expression}} \ 718 // ref-note {{in call to}} 719 720 constexpr bool alloc_from_user_code() { 721 void *p = __builtin_operator_new(sizeof(int)); // both-note {{cannot allocate untyped memory in a constant expression; use 'std::allocator<T>::allocate'}} 722 __builtin_operator_delete(p); 723 return true; 724 } 725 static_assert(alloc_from_user_code()); // both-error {{constant expression}} \ 726 // both-note {{in call to}} 727 728 729 constexpr int no_deallocate_nullptr = (std::allocator<int>().deallocate(nullptr), 1); // both-error {{constant expression}} \ 730 // both-note {{in call}} 731 732 static_assert((std::allocator<float>().deallocate(std::allocator<float>().allocate(10)), 1) == 1); 733 } 734 735 namespace Limits { 736 template<typename T> 737 constexpr T dynarray(int elems, int i) { 738 T *p; 739 if constexpr (sizeof(T) == 1) 740 p = new T[elems]{"fox"}; 741 else 742 p = new T[elems]{1, 2, 3}; 743 T n = p[i]; 744 delete [] p; 745 return n; 746 } 747 static_assert(dynarray<char>(5, 0) == 'f'); 748 749 750 #if __LP64__ 751 template <typename T> 752 struct S { 753 constexpr S(unsigned long long N) 754 : data(nullptr){ 755 data = alloc.allocate(N); // both-note {{in call to 'this->alloc.allocate(18446744073709551615)}} 756 } 757 constexpr T operator[](std::size_t i) const { 758 return data[i]; 759 } 760 761 constexpr ~S() { 762 alloc.deallocate(data); 763 } 764 std::allocator<T> alloc; 765 T* data; 766 }; 767 768 constexpr std::size_t s = S<std::size_t>(~0UL)[42]; // both-error {{constexpr variable 's' must be initialized by a constant expression}} \ 769 // both-note@#alloc {{cannot allocate array; evaluated array bound 2305843009213693951 is too large}} \ 770 // both-note {{in call to}} 771 #endif 772 } 773 774 /// Just test that we reject placement-new expressions before C++2c. 775 /// Tests for successful expressions are in placement-new.cpp 776 namespace Placement { 777 consteval auto ok1() { // both-error {{never produces a constant expression}} 778 bool b; 779 new (&b) bool(true); // both-note 2{{this placement new expression is not supported in constant expressions before C++2c}} 780 return b; 781 } 782 static_assert(ok1()); // both-error {{not an integral constant expression}} \ 783 // both-note {{in call to}} 784 785 /// placement-new should be supported before C++26 in std functions. 786 constexpr int ok2() { 787 int *I = new int; 788 std::construct_at<int>(I); 789 int r = *I; 790 delete I; 791 return r; 792 } 793 static_assert(ok2()== 0); 794 } 795 796 constexpr bool virt_delete(bool global) { 797 struct A { 798 virtual constexpr ~A() {} 799 }; 800 struct B : A { 801 void operator delete(void *); 802 constexpr ~B() {} 803 }; 804 805 A *p = new B; 806 if (global) 807 ::delete p; 808 else 809 delete p; // both-note {{call to class-specific 'operator delete'}} 810 return true; 811 } 812 static_assert(virt_delete(true)); 813 static_assert(virt_delete(false)); // both-error {{not an integral constant expression}} \ 814 // both-note {{in call to}} 815 816 817 namespace ToplevelScopeInTemplateArg { 818 class string { 819 public: 820 char *mem; 821 constexpr string() { 822 this->mem = new char(1); 823 } 824 constexpr ~string() { 825 delete this->mem; 826 } 827 constexpr unsigned size() const { return 4; } 828 }; 829 830 831 template <unsigned N> 832 void test() {}; 833 834 void f() { 835 test<string().size()>(); 836 static_assert(string().size() == 4); 837 } 838 } 839 840 template <typename T> 841 struct SS { 842 constexpr SS(unsigned long long N) 843 : data(nullptr){ 844 data = alloc.allocate(N); // #call 845 for(std::size_t i = 0; i < N; i ++) 846 std::construct_at<T>(data + i, i); // #construct_call 847 } 848 constexpr T operator[](std::size_t i) const { 849 return data[i]; 850 } 851 852 constexpr ~SS() { 853 alloc.deallocate(data); 854 } 855 std::allocator<T> alloc; 856 T* data; 857 }; 858 constexpr unsigned short ssmall = SS<unsigned short>(100)[42]; 859 860 #else 861 /// Make sure we reject this prior to C++20 862 constexpr int a() { // both-error {{never produces a constant expression}} 863 delete new int(12); // both-note 2{{dynamic memory allocation is not permitted in constant expressions until C++20}} 864 return 1; 865 } 866 static_assert(a() == 1, ""); // both-error {{not an integral constant expression}} \ 867 // both-note {{in call to 'a()'}} 868 869 870 static_assert(true ? *new int : 4, ""); // both-error {{expression is not an integral constant expression}} \ 871 // both-note {{read of uninitialized object is not allowed in a constant expression}} 872 873 #endif 874