// RUN: %clang_cc1 -verify=expected,both -std=c++26 %s -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -verify=ref,both -std=c++26 %s namespace std { struct type_info; struct destroying_delete_t { explicit destroying_delete_t() = default; } inline constexpr destroying_delete{}; struct nothrow_t { explicit nothrow_t() = default; } inline constexpr nothrow{}; using size_t = decltype(sizeof(0)); enum class align_val_t : size_t {}; using size_t = decltype(sizeof(0)); template struct allocator { constexpr T *allocate(size_t N) { return (T*)__builtin_operator_new(sizeof(T) * N); } constexpr void deallocate(void *p) { __builtin_operator_delete(p); } }; template constexpr void construct_at(void *p, Args &&...args) { new (p) T((Args&&)args...); } }; constexpr void *operator new(std::size_t, void *p) { return p; } namespace std { template constexpr T *construct_at(T *p) { return new (p) T; } template constexpr void destroy_at(T *p) { p->~T(); } // #destroy } constexpr bool foo() { using T = bool; bool b = true; b.~T(); new (&b) bool(false); return b; } static_assert(!foo()); struct S {}; constexpr bool foo2() { S s; s.~S(); new (&s) S{}; return true; } static_assert(foo2()); constexpr void destroy_pointer() { using T = int*; T p; p.~T(); std::construct_at(&p); } static_assert((destroy_pointer(), true)); namespace DestroyArrayElem { constexpr int test1() { int a[4] = {}; std::destroy_at(&a); // both-error@#destroy {{object expression of non-scalar type 'int[4]' cannot be used in a pseudo-destructor expression}} \ // both-note {{in instantiation of function template specialization 'std::destroy_at' requested here}} \ // both-note {{subexpression not valid}} return 0; } static_assert(test1() == 0); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int test2() { int a[4] = {}; // both-note {{declared here}} std::destroy_at(&a[1]); int r = a[1]; // both-note {{read of object outside its lifetime}} std::construct_at(&a[1]); return 0; } static_assert(test2() == 0); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int test3() { int a[4]; /// Array with no init map. // both-note@-1 {{declared here}} std::construct_at(&a[3]); return a[3]; // both-note {{read of uninitialized object}} } static_assert(test3() == 0); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int test4(bool b) { int a[4]; // both-note {{declared here}} a[0] = 12; std::construct_at(&a[3]); return b ? a[0] : a[3]; // both-note {{read of uninitialized object}} } static_assert(test4(true) == 12); static_assert(test4(false) == 0); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int test5() { int *a = std::allocator{}.allocate(3); // both-note {{heap allocation performed here}} a[0] = 1; // both-note {{assignment to object outside its lifetime}} int b = a[1]; std::allocator{}.deallocate(a); return b; } static_assert(test5() == 1); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int test6() { int *a = std::allocator{}.allocate(3); std::construct_at(&a[0]); a[0] = 1; std::construct_at(&a[1]); a[1] = 2; std::construct_at(&a[2]); a[2] = 3; int b = a[1]; std::allocator{}.deallocate(a); return b; } static_assert(test6() == 2); constexpr int test7() { int *a = std::allocator{}.allocate(3); int *b = a + 3; new (a + 0) int(); new (a + 1) int(); new (a + 2) int(); b = b - 1; new (b) int(0); bool r = a[0] == 0; std::allocator{}.deallocate(a); return r; } static_assert(test7()); constexpr int test8() { int *a = std::allocator{}.allocate(3); int *b = a + 3; new (a + 0) int(); new (a + 1) int(); new (a + 2) int(); new (a) int(); std::destroy_at(b - 1); bool r = *a == 0; std::allocator{}.deallocate(a); return r; } static_assert(test8()); }