]> git.lizzy.rs Git - rust.git/blob - src/test/ui/drop/dynamic-drop.rs
Auto merge of #77692 - PankajChaudhary5:issue-76630, r=davidtwco
[rust.git] / src / test / ui / drop / dynamic-drop.rs
1 // run-pass
2 // ignore-wasm32-bare compiled with panic=abort by default
3
4 #![feature(generators, generator_trait)]
5 #![feature(bindings_after_at)]
6 #![allow(unused_assignments)]
7 #![allow(unused_variables)]
8
9 use std::cell::{Cell, RefCell};
10 use std::mem::ManuallyDrop;
11 use std::ops::Generator;
12 use std::panic;
13 use std::pin::Pin;
14
15 struct InjectedFailure;
16
17 struct Allocator {
18     data: RefCell<Vec<bool>>,
19     name: &'static str,
20     failing_op: usize,
21     cur_ops: Cell<usize>,
22 }
23
24 impl panic::UnwindSafe for Allocator {}
25 impl panic::RefUnwindSafe for Allocator {}
26
27 impl Drop for Allocator {
28     fn drop(&mut self) {
29         let data = self.data.borrow();
30         if data.iter().any(|d| *d) {
31             panic!("missing free in {:?}: {:?}", self.name, data);
32         }
33     }
34 }
35
36 impl Allocator {
37     fn new(failing_op: usize, name: &'static str) -> Self {
38         Allocator {
39             failing_op: failing_op,
40             cur_ops: Cell::new(0),
41             data: RefCell::new(vec![]),
42             name,
43         }
44     }
45     fn alloc(&self) -> Ptr<'_> {
46         self.cur_ops.set(self.cur_ops.get() + 1);
47
48         if self.cur_ops.get() == self.failing_op {
49             panic!(InjectedFailure);
50         }
51
52         let mut data = self.data.borrow_mut();
53         let addr = data.len();
54         data.push(true);
55         Ptr(addr, self)
56     }
57 }
58
59 struct Ptr<'a>(usize, &'a Allocator);
60 impl<'a> Drop for Ptr<'a> {
61     fn drop(&mut self) {
62         match self.1.data.borrow_mut()[self.0] {
63             false => panic!("double free in {:?} at index {:?}", self.1.name, self.0),
64             ref mut d => *d = false,
65         }
66
67         self.1.cur_ops.set(self.1.cur_ops.get() + 1);
68
69         if self.1.cur_ops.get() == self.1.failing_op {
70             panic!(InjectedFailure);
71         }
72     }
73 }
74
75 fn dynamic_init(a: &Allocator, c: bool) {
76     let _x;
77     if c {
78         _x = Some(a.alloc());
79     }
80 }
81
82 fn dynamic_drop(a: &Allocator, c: bool) {
83     let x = a.alloc();
84     if c {
85         Some(x)
86     } else {
87         None
88     };
89 }
90
91 struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
92 fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
93     for i in 0..2 {
94         let x;
95         let y;
96         if (c0 && i == 0) || (c1 && i == 1) {
97             x = (a.alloc(), a.alloc(), a.alloc());
98             y = TwoPtrs(a.alloc(), a.alloc());
99             if c {
100                 drop(x.1);
101                 drop(y.0);
102             }
103         }
104     }
105 }
106
107 fn field_assignment(a: &Allocator, c0: bool) {
108     let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc());
109
110     x.1 = a.alloc();
111     x.1 = a.alloc();
112
113     let f = (x.0).0;
114     if c0 {
115         (x.0).0 = f;
116     }
117 }
118
119 fn assignment2(a: &Allocator, c0: bool, c1: bool) {
120     let mut _v = a.alloc();
121     let mut _w = a.alloc();
122     if c0 {
123         drop(_v);
124     }
125     _v = _w;
126     if c1 {
127         _w = a.alloc();
128     }
129 }
130
131 fn assignment1(a: &Allocator, c0: bool) {
132     let mut _v = a.alloc();
133     let mut _w = a.alloc();
134     if c0 {
135         drop(_v);
136     }
137     _v = _w;
138 }
139
140 union Boxy<T> {
141     a: ManuallyDrop<T>,
142     b: ManuallyDrop<T>,
143 }
144
145 fn union1(a: &Allocator) {
146     unsafe {
147         let mut u = Boxy { a: ManuallyDrop::new(a.alloc()) };
148         *u.b = a.alloc(); // drops first alloc
149         drop(ManuallyDrop::into_inner(u.a));
150     }
151 }
152
153 fn array_simple(a: &Allocator) {
154     let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
155 }
156
157 fn vec_simple(a: &Allocator) {
158     let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
159 }
160
161 fn generator(a: &Allocator, run_count: usize) {
162     assert!(run_count < 4);
163
164     let mut gen = || {
165         (a.alloc(), yield a.alloc(), a.alloc(), yield a.alloc());
166     };
167     for _ in 0..run_count {
168         Pin::new(&mut gen).resume(());
169     }
170 }
171
172 fn mixed_drop_and_nondrop(a: &Allocator) {
173     // check that destructor panics handle drop
174     // and non-drop blocks in the same scope correctly.
175     //
176     // Surprisingly enough, this used to not work.
177     let (x, y, z);
178     x = a.alloc();
179     y = 5;
180     z = a.alloc();
181 }
182
183 #[allow(unreachable_code)]
184 fn vec_unreachable(a: &Allocator) {
185     let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
186 }
187
188 fn slice_pattern_first(a: &Allocator) {
189     let [_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
190 }
191
192 fn slice_pattern_middle(a: &Allocator) {
193     let [_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
194 }
195
196 fn slice_pattern_two(a: &Allocator) {
197     let [_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
198 }
199
200 fn slice_pattern_last(a: &Allocator) {
201     let [.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
202 }
203
204 fn slice_pattern_one_of(a: &Allocator, i: usize) {
205     let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
206     let _x = match i {
207         0 => {
208             let [a, ..] = array;
209             a
210         }
211         1 => {
212             let [_, a, ..] = array;
213             a
214         }
215         2 => {
216             let [_, _, a, _] = array;
217             a
218         }
219         3 => {
220             let [_, _, _, a] = array;
221             a
222         }
223         _ => panic!("unmatched"),
224     };
225 }
226
227 fn subslice_pattern_from_end(a: &Allocator, arg: bool) {
228     let a = [a.alloc(), a.alloc(), a.alloc()];
229     if arg {
230         let [.., _x, _] = a;
231     } else {
232         let [_, _y @ ..] = a;
233     }
234 }
235
236 fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) {
237     let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()];
238     if arg2 {
239         drop(a);
240         return;
241     }
242
243     if arg {
244         let [.., _x, _] = a;
245     } else {
246         let [_, _y @ ..] = a;
247     }
248 }
249
250 fn slice_pattern_reassign(a: &Allocator) {
251     let mut ar = [a.alloc(), a.alloc()];
252     let [_, _x] = ar;
253     ar = [a.alloc(), a.alloc()];
254     let [.., _y] = ar;
255 }
256
257 fn subslice_pattern_reassign(a: &Allocator) {
258     let mut ar = [a.alloc(), a.alloc(), a.alloc()];
259     let [_, _, _x] = ar;
260     ar = [a.alloc(), a.alloc(), a.alloc()];
261     let [_, _y @ ..] = ar;
262 }
263
264 fn index_field_mixed_ends(a: &Allocator) {
265     let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
266     let [(_x, _), ..] = ar;
267     let [(_, _y), _] = ar;
268     let [_, (_, _w)] = ar;
269     let [.., (_z, _)] = ar;
270 }
271
272 fn subslice_mixed_min_lengths(a: &Allocator, c: i32) {
273     let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
274     match c {
275         0 => {
276             let [_x, ..] = ar;
277         }
278         1 => {
279             let [_x, _, ..] = ar;
280         }
281         2 => {
282             let [_x, _] = ar;
283         }
284         3 => {
285             let [(_x, _), _, ..] = ar;
286         }
287         4 => {
288             let [.., (_x, _)] = ar;
289         }
290         5 => {
291             let [.., (_x, _), _] = ar;
292         }
293         6 => {
294             let [_y @ ..] = ar;
295         }
296         _ => {
297             let [_y @ .., _] = ar;
298         }
299     }
300 }
301
302 fn bindings_after_at_dynamic_init_move(a: &Allocator, c: bool) {
303     let foo = if c { Some(a.alloc()) } else { None };
304     let _x;
305
306     if let bar @ Some(_) = foo {
307         _x = bar;
308     }
309 }
310
311 fn bindings_after_at_dynamic_init_ref(a: &Allocator, c: bool) {
312     let foo = if c { Some(a.alloc()) } else { None };
313     let _x;
314
315     if let bar @ Some(_baz) = &foo {
316         _x = bar;
317     }
318 }
319
320 fn bindings_after_at_dynamic_drop_move(a: &Allocator, c: bool) {
321     let foo = if c { Some(a.alloc()) } else { None };
322
323     if let bar @ Some(_) = foo {
324         bar
325     } else {
326         None
327     };
328 }
329
330 fn bindings_after_at_dynamic_drop_ref(a: &Allocator, c: bool) {
331     let foo = if c { Some(a.alloc()) } else { None };
332
333     if let bar @ Some(_baz) = &foo {
334         bar
335     } else {
336         &None
337     };
338 }
339
340 fn move_ref_pattern(a: &Allocator) {
341     let mut tup = (a.alloc(), a.alloc(), a.alloc(), a.alloc());
342     let (ref _a, ref mut _b, _c, mut _d) = tup;
343 }
344
345 fn panic_after_return(a: &Allocator) -> Ptr<'_> {
346     a.alloc();
347     let p = a.alloc();
348     {
349         a.alloc();
350         let p = a.alloc();
351         a.alloc()
352     }
353 }
354
355 fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> {
356     a.alloc();
357     let p = a.alloc();
358     {
359         a.alloc();
360         let q = a.alloc();
361         return a.alloc();
362     }
363 }
364
365 fn panic_after_init(a: &Allocator) {
366     a.alloc();
367     let p = a.alloc();
368     let q = {
369         a.alloc();
370         let r = a.alloc();
371         a.alloc()
372     };
373 }
374
375 fn panic_after_init_temp(a: &Allocator) {
376     a.alloc();
377     let p = a.alloc();
378     {
379         a.alloc();
380         let r = a.alloc();
381         a.alloc()
382     };
383 }
384
385 fn panic_after_init_by_loop(a: &Allocator) {
386     a.alloc();
387     let p = a.alloc();
388     let q = loop {
389         a.alloc();
390         let r = a.alloc();
391         break a.alloc();
392     };
393 }
394
395 fn panic_after_init_by_match(a: &Allocator, b: bool) {
396     a.alloc();
397     let p = a.alloc();
398     let _ = loop {
399         let q = match b {
400             true => {
401                 a.alloc();
402                 let r = a.alloc();
403                 a.alloc()
404             }
405             false => {
406                 a.alloc();
407                 let r = a.alloc();
408                 break a.alloc();
409             }
410         };
411         return;
412     };
413 }
414
415 fn panic_after_init_by_match_with_guard(a: &Allocator, b: bool) {
416     a.alloc();
417     let p = a.alloc();
418     let q = match a.alloc() {
419         _ if b => {
420             a.alloc();
421             let r = a.alloc();
422             a.alloc()
423         }
424         _ => {
425             a.alloc();
426             let r = a.alloc();
427             a.alloc()
428         }
429     };
430 }
431
432 fn panic_after_init_by_match_with_bindings_and_guard(a: &Allocator, b: bool) {
433     a.alloc();
434     let p = a.alloc();
435     let q = match a.alloc() {
436         _x if b => {
437             a.alloc();
438             let r = a.alloc();
439             a.alloc()
440         }
441         _x => {
442             a.alloc();
443             let r = a.alloc();
444             a.alloc()
445         }
446     };
447 }
448
449 fn panic_after_init_by_match_with_ref_bindings_and_guard(a: &Allocator, b: bool) {
450     a.alloc();
451     let p = a.alloc();
452     let q = match a.alloc() {
453         ref _x if b => {
454             a.alloc();
455             let r = a.alloc();
456             a.alloc()
457         }
458         ref _x => {
459             a.alloc();
460             let r = a.alloc();
461             a.alloc()
462         }
463     };
464 }
465
466 fn panic_after_init_by_break_if(a: &Allocator, b: bool) {
467     a.alloc();
468     let p = a.alloc();
469     let q = loop {
470         let r = a.alloc();
471         break if b {
472             let s = a.alloc();
473             a.alloc()
474         } else {
475             a.alloc()
476         };
477     };
478 }
479
480 fn run_test<F>(mut f: F, name: &'static str)
481 where
482     F: FnMut(&Allocator),
483 {
484     let first_alloc = Allocator::new(usize::MAX, name);
485     f(&first_alloc);
486
487     for failing_op in 1..first_alloc.cur_ops.get() + 1 {
488         let alloc = Allocator::new(failing_op, name);
489         let alloc = &alloc;
490         let f = panic::AssertUnwindSafe(&mut f);
491         let result = panic::catch_unwind(move || {
492             f.0(alloc);
493         });
494         match result {
495             Ok(..) => panic!(
496                 "test executed {} ops but now {}",
497                 first_alloc.cur_ops.get(),
498                 alloc.cur_ops.get()
499             ),
500             Err(e) => {
501                 if e.downcast_ref::<InjectedFailure>().is_none() {
502                     panic::resume_unwind(e);
503                 }
504             }
505         }
506     }
507 }
508
509 fn run_test_nopanic<F>(mut f: F, name: &'static str)
510 where
511     F: FnMut(&Allocator),
512 {
513     let first_alloc = Allocator::new(usize::MAX, name);
514     f(&first_alloc);
515 }
516
517 macro_rules! run_test {
518     ($e:expr) => {
519         run_test($e, stringify!($e));
520     };
521 }
522
523 fn main() {
524     run_test!(|a| dynamic_init(a, false));
525     run_test!(|a| dynamic_init(a, true));
526     run_test!(|a| dynamic_drop(a, false));
527     run_test!(|a| dynamic_drop(a, true));
528
529     run_test!(|a| assignment2(a, false, false));
530     run_test!(|a| assignment2(a, false, true));
531     run_test!(|a| assignment2(a, true, false));
532     run_test!(|a| assignment2(a, true, true));
533
534     run_test!(|a| assignment1(a, false));
535     run_test!(|a| assignment1(a, true));
536
537     run_test!(|a| array_simple(a));
538     run_test!(|a| vec_simple(a));
539     run_test!(|a| vec_unreachable(a));
540
541     run_test!(|a| struct_dynamic_drop(a, false, false, false));
542     run_test!(|a| struct_dynamic_drop(a, false, false, true));
543     run_test!(|a| struct_dynamic_drop(a, false, true, false));
544     run_test!(|a| struct_dynamic_drop(a, false, true, true));
545     run_test!(|a| struct_dynamic_drop(a, true, false, false));
546     run_test!(|a| struct_dynamic_drop(a, true, false, true));
547     run_test!(|a| struct_dynamic_drop(a, true, true, false));
548     run_test!(|a| struct_dynamic_drop(a, true, true, true));
549
550     run_test!(|a| field_assignment(a, false));
551     run_test!(|a| field_assignment(a, true));
552
553     run_test!(|a| generator(a, 0));
554     run_test!(|a| generator(a, 1));
555     run_test!(|a| generator(a, 2));
556     run_test!(|a| generator(a, 3));
557
558     run_test!(|a| mixed_drop_and_nondrop(a));
559
560     run_test!(|a| slice_pattern_first(a));
561     run_test!(|a| slice_pattern_middle(a));
562     run_test!(|a| slice_pattern_two(a));
563     run_test!(|a| slice_pattern_last(a));
564     run_test!(|a| slice_pattern_one_of(a, 0));
565     run_test!(|a| slice_pattern_one_of(a, 1));
566     run_test!(|a| slice_pattern_one_of(a, 2));
567     run_test!(|a| slice_pattern_one_of(a, 3));
568
569     run_test!(|a| subslice_pattern_from_end(a, true));
570     run_test!(|a| subslice_pattern_from_end(a, false));
571     run_test!(|a| subslice_pattern_from_end_with_drop(a, true, true));
572     run_test!(|a| subslice_pattern_from_end_with_drop(a, true, false));
573     run_test!(|a| subslice_pattern_from_end_with_drop(a, false, true));
574     run_test!(|a| subslice_pattern_from_end_with_drop(a, false, false));
575     run_test!(|a| slice_pattern_reassign(a));
576     run_test!(|a| subslice_pattern_reassign(a));
577
578     run_test!(|a| index_field_mixed_ends(a));
579     run_test!(|a| subslice_mixed_min_lengths(a, 0));
580     run_test!(|a| subslice_mixed_min_lengths(a, 1));
581     run_test!(|a| subslice_mixed_min_lengths(a, 2));
582     run_test!(|a| subslice_mixed_min_lengths(a, 3));
583     run_test!(|a| subslice_mixed_min_lengths(a, 4));
584     run_test!(|a| subslice_mixed_min_lengths(a, 5));
585     run_test!(|a| subslice_mixed_min_lengths(a, 6));
586     run_test!(|a| subslice_mixed_min_lengths(a, 7));
587
588     run_test!(|a| move_ref_pattern(a));
589
590     run_test!(|a| {
591         panic_after_return(a);
592     });
593     run_test!(|a| {
594         panic_after_return_expr(a);
595     });
596     run_test!(|a| panic_after_init(a));
597     run_test!(|a| panic_after_init_temp(a));
598     run_test!(|a| panic_after_init_by_loop(a));
599     run_test!(|a| panic_after_init_by_match(a, false));
600     run_test!(|a| panic_after_init_by_match(a, true));
601     run_test!(|a| panic_after_init_by_match_with_guard(a, false));
602     run_test!(|a| panic_after_init_by_match_with_guard(a, true));
603     run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, false));
604     run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, true));
605     run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, false));
606     run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, true));
607     run_test!(|a| panic_after_init_by_break_if(a, false));
608     run_test!(|a| panic_after_init_by_break_if(a, true));
609
610     run_test!(|a| bindings_after_at_dynamic_init_move(a, true));
611     run_test!(|a| bindings_after_at_dynamic_init_move(a, false));
612     run_test!(|a| bindings_after_at_dynamic_init_ref(a, true));
613     run_test!(|a| bindings_after_at_dynamic_init_ref(a, false));
614     run_test!(|a| bindings_after_at_dynamic_drop_move(a, true));
615     run_test!(|a| bindings_after_at_dynamic_drop_move(a, false));
616     run_test!(|a| bindings_after_at_dynamic_drop_ref(a, true));
617     run_test!(|a| bindings_after_at_dynamic_drop_ref(a, false));
618
619     run_test_nopanic(|a| union1(a), "|a| union1(a)");
620 }