xref: /llvm-project/clang/test/AST/ByteCode/new-delete.cpp (revision e6030d389571b3f1b0f0c5a35b7fa45937ed0f6c)
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