xref: /llvm-project/clang/test/AST/ByteCode/placement-new.cpp (revision ceaf6e912a846b88f19df682c6bdbe9516be04e9)
1 // RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -fexperimental-new-constant-interpreter -verify=expected,both %s -DBYTECODE
2 // RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -verify=ref,both %s
3 
4 namespace std {
5   using size_t = decltype(sizeof(0));
6   template<typename T> struct allocator {
7     constexpr T *allocate(size_t N) {
8       return (T*)operator new(sizeof(T) * N);
9     }
10     constexpr void deallocate(void *p) {
11       operator delete(p);
12     }
13   };
14   template<typename T, typename ...Args>
15   constexpr void construct_at(void *p, Args &&...args) {
16     new (p) T((Args&&)args...); // both-note {{in call to}} \
17                                 // both-note {{placement new would change type of storage from 'int' to 'float'}} \
18                                 // both-note {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}}
19 
20   }
21 }
22 
23 void *operator new(std::size_t, void *p) { return p; }
24 void* operator new[] (std::size_t, void* p) {return p;}
25 
26 
27 consteval auto ok1() {
28   bool b;
29   new (&b) bool(true);
30   return b;
31 }
32 static_assert(ok1());
33 
34 consteval auto ok2() {
35   int b;
36   new (&b) int(12);
37   return b;
38 }
39 static_assert(ok2() == 12);
40 
41 
42 consteval auto ok3() {
43   float b;
44   new (&b) float(12.0);
45   return b;
46 }
47 static_assert(ok3() == 12.0);
48 
49 
50 consteval auto ok4() {
51   _BitInt(11) b;
52   new (&b) _BitInt(11)(37);
53   return b;
54 }
55 static_assert(ok4() == 37);
56 
57 consteval int ok5() {
58   int i;
59   new (&i) int[1]{1};
60 
61   struct S {
62     int a; int b;
63   } s;
64   new (&s) S[1]{{12, 13}};
65 
66   return 25;
67   // return s.a + s.b; FIXME: Broken in the current interpreter.
68 }
69 static_assert(ok5() == 25);
70 
71 /// FIXME: Broken in both interpreters.
72 #if 0
73 consteval int ok5() {
74     int i;
75     new (&i) int[1]{1}; // expected-note {{assignment to dereferenced one-past-the-end pointer}}
76     return i;
77 }
78 static_assert(ok5() == 1); // expected-error {{not an integral constant expression}} \
79                            // expected-note {{in call to}}
80 #endif
81 
82 /// FIXME: Crashes the current interpreter.
83 #if 0
84 consteval int ok6() {
85     int i[2];
86     new (&i) int(100);
87     return i[0];
88 }
89 static_assert(ok6() == 100);
90 #endif
91 
92 consteval int ok6() {
93     int i[2];
94     new (i) int(100);
95     new (i + 1) int(200);
96     return i[0] + i[1];
97 }
98 static_assert(ok6() == 300);
99 
100 
101 consteval auto fail1() {
102   int b;
103   new (&b) float(1.0); // both-note {{placement new would change type of storage from 'int' to 'float'}}
104   return b;
105 }
106 static_assert(fail1() == 0); // both-error {{not an integral constant expression}} \
107                              // both-note {{in call to}}
108 
109 consteval int fail2() {
110     int i;
111     new (static_cast<void*>(&i)) float(0); // both-note {{placement new would change type of storage from 'int' to 'float'}}
112     return 0;
113 }
114 static_assert(fail2() == 0); // both-error {{not an integral constant expression}} \
115                              // both-note {{in call to}}
116 
117 consteval int indeterminate() {
118     int * indeterminate;
119     new (indeterminate) int(0); // both-note {{read of uninitialized object is not allowed in a constant expression}}
120     return 0;
121 }
122 static_assert(indeterminate() == 0); // both-error {{not an integral constant expression}} \
123                                      // both-note {{in call to}}
124 
125 consteval int array1() {
126     int i[2];
127     new (&i) int[]{1,2};
128     return i[0] + i[1];
129 }
130 static_assert(array1() == 3);
131 
132 consteval int array2() {
133     int i[2];
134     new (static_cast<void*>(&i)) int[]{1,2};
135     return i[0] + i[1];
136 }
137 static_assert(array2() == 3);
138 
139 consteval int array3() {
140     int i[1];
141     new (&i) int[2]; // both-note {{placement new would change type of storage from 'int[1]' to 'int[2]'}}
142     return 0;
143 }
144 static_assert(array3() == 0); // both-error {{not an integral constant expression}} \
145                               // both-note {{in call to}}
146 
147 consteval int array4() {
148     int i[2];
149     new (&i) int[]{12};
150     return i[0];
151 }
152 static_assert(array4() == 12);
153 
154 constexpr int *intptr() {
155   return new int;
156 }
157 constexpr bool yay() {
158   int *ptr = new (intptr()) int(42);
159   bool ret = *ptr == 42;
160   delete ptr;
161   return ret;
162 }
163 static_assert(yay());
164 
165 
166 constexpr bool blah() {
167   int *ptr = new (intptr()) int[3]{ 1, 2, 3 }; // both-note {{placement new would change type of storage from 'int' to 'int[3]'}}
168   bool ret = ptr[0] == 1 && ptr[1] == 2 && ptr[2] == 3;
169   delete [] ptr;
170   return ret;
171 }
172 static_assert(blah()); // both-error {{not an integral constant expression}} \
173                        // both-note {{in call to 'blah()'}}
174 
175 
176 constexpr int *get_indeterminate() {
177   int *evil;
178   return evil; // both-note {{read of uninitialized object is not allowed in a constant expression}}
179 }
180 
181 constexpr bool bleh() {
182   int *ptr = new (get_indeterminate()) int;  // both-note {{in call to 'get_indeterminate()'}}
183   return true;
184 }
185 static_assert(bleh()); // both-error {{not an integral constant expression}} \
186                        // both-note {{in call to 'bleh()'}}
187 
188 namespace records {
189   class S {
190   public:
191     float f;
192   };
193 
194   constexpr bool record1() {
195     S s(13);
196     new (&s) S(42);
197     return s.f == 42;
198   }
199   static_assert(record1());
200 
201   S GlobalS;
202   constexpr bool record2() {
203     new (&GlobalS) S(42); // both-note {{a constant expression cannot modify an object that is visible outside that expression}}
204     return GlobalS.f == 42;
205   }
206   static_assert(record2()); // both-error {{not an integral constant expression}} \
207                             // both-note {{in call to}}
208 
209 
210   constexpr bool record3() {
211     S ss[3];
212 
213     new (&ss) S[]{{1}, {2}, {3}};
214 
215     return ss[0].f == 1 && ss[1].f == 2 && ss[2].f == 3;
216   }
217   static_assert(record3());
218 
219   struct F {
220     float f;
221   };
222   struct R {
223     F f;
224     int a;
225   };
226   constexpr bool record4()  {
227     R r;
228     new (&r.f) F{42.0};
229     new (&r.a) int(12);
230 
231     return r.f.f == 42.0 && r.a == 12;
232   }
233   static_assert(record4());
234 
235   /// Destructor is NOT called.
236   struct A {
237     bool b;
238     constexpr ~A() { if (b) throw; }
239   };
240 
241   constexpr int foo() {
242     A a;
243     new (&a) A(true);
244     new (&a) A(false);
245     return 0;
246   }
247   static_assert(foo() == 0);
248 }
249 
250 namespace ConstructAt {
251   struct S {
252     int a = 10;
253     float b = 1.0;
254   };
255 
256   constexpr bool ok1() {
257     S s;
258 
259     std::construct_at<S>(&s);
260     return s.a == 10 && s.b == 1.0;
261   }
262   static_assert(ok1());
263 
264   struct S2 {
265     constexpr S2() {
266       (void)(1/0); // both-note {{division by zero}} \
267                    // both-warning {{division by zero is undefined}}
268     }
269   };
270 
271   constexpr bool ctorFail() { //
272     S2 *s = std::allocator<S2>().allocate(1);
273     std::construct_at<S2>(s); // both-note {{in call to}}
274 
275     return true;
276   }
277   static_assert(ctorFail()); // both-error {{not an integral constant expression}} \
278                              // both-note {{in call to 'ctorFail()'}}
279 
280 
281   constexpr bool bad_construct_at_type() {
282     int a;
283     std::construct_at<float>(&a, 1.0f); // both-note {{in call to}}
284     return true;
285   }
286   static_assert(bad_construct_at_type()); // both-error {{not an integral constant expression}} \
287                                           // both-note {{in call}}
288 
289   constexpr bool bad_construct_at_subobject() {
290     struct X { int a, b; };
291     union A {
292       int a;
293       X x;
294     };
295     A a = {1};
296     std::construct_at<int>(&a.x.a, 1); // both-note {{in call}}
297     return true;
298   }
299   static_assert(bad_construct_at_subobject()); // both-error{{not an integral constant expression}} \
300                                                // both-note {{in call}}
301 }
302 
303 namespace UsedToCrash {
304   struct S {
305       int* i;
306       constexpr S() : i(new int(42)) {} // #no-deallocation
307       constexpr ~S() {delete i;}
308   };
309   consteval void alloc() {
310       S* s = new S();
311       s->~S();
312       new (s) S();
313       delete s;
314   }
315   int alloc1 = (alloc(), 0);
316 }
317 
318 constexpr bool change_union_member() {
319   union U {
320     int a;
321     int b;
322   };
323   U u = {.a = 1};
324   std::construct_at<int>(&u.b, 2);
325   return u.b == 2;
326 }
327 static_assert(change_union_member());
328 
329 namespace PR48606 {
330   struct A { mutable int n = 0; };
331 
332   constexpr bool f() {
333     A a;
334     A *p = &a;
335     p->~A();
336     std::construct_at<A>(p);
337     return true;
338   }
339   static_assert(f());
340 }
341 
342 #ifdef BYTECODE
343 constexpr int N = [] // expected-error {{must be initialized by a constant expression}} \
344                      // expected-note {{assignment to dereferenced one-past-the-end pointer is not allowed in a constant expression}} \
345                      // expected-note {{in call to}}
346 {
347     struct S {
348         int a[1];
349     };
350     S s;
351     ::new (s.a) int[1][2][3][4]();
352     return s.a[0];
353 }();
354 #endif
355