]> git.lizzy.rs Git - rust.git/blob - src/test/ui/rfcs/rfc1857-drop-order.rs
Rollup merge of #98640 - cuviper:stable-rust-analyzer, r=Mark-Simulacrum
[rust.git] / src / test / ui / rfcs / rfc1857-drop-order.rs
1 // run-pass
2 // needs-unwind
3 // ignore-wasm32-bare compiled with panic=abort by default
4
5 #![allow(dead_code, unreachable_code)]
6
7 use std::cell::RefCell;
8 use std::rc::Rc;
9 use std::panic::{self, AssertUnwindSafe, UnwindSafe};
10
11 // This struct is used to record the order in which elements are dropped
12 struct PushOnDrop {
13     vec: Rc<RefCell<Vec<u32>>>,
14     val: u32
15 }
16
17 impl PushOnDrop {
18     fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop {
19         PushOnDrop { vec, val }
20     }
21 }
22
23 impl Drop for PushOnDrop {
24     fn drop(&mut self) {
25         self.vec.borrow_mut().push(self.val)
26     }
27 }
28
29 impl UnwindSafe for PushOnDrop { }
30
31 // Structs
32 struct TestStruct {
33     x: PushOnDrop,
34     y: PushOnDrop,
35     z: PushOnDrop
36 }
37
38 // Tuple structs
39 struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop);
40
41 // Enum variants
42 enum TestEnum {
43     Tuple(PushOnDrop, PushOnDrop, PushOnDrop),
44     Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop }
45 }
46
47 fn test_drop_tuple() {
48     // Tuple fields are dropped in the same order they are declared
49     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
50     let test_tuple = (PushOnDrop::new(1, dropped_fields.clone()),
51                       PushOnDrop::new(2, dropped_fields.clone()));
52     drop(test_tuple);
53     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
54
55     // Panic during construction means that fields are treated as local variables
56     // Therefore they are dropped in reverse order of initialization
57     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
58     let cloned = AssertUnwindSafe(dropped_fields.clone());
59     panic::catch_unwind(|| {
60         (PushOnDrop::new(2, cloned.clone()),
61          PushOnDrop::new(1, cloned.clone()),
62          panic!("this panic is caught :D"));
63     }).err().unwrap();
64     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
65 }
66
67 fn test_drop_struct() {
68     // Struct fields are dropped in the same order they are declared
69     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
70     let test_struct = TestStruct {
71         x: PushOnDrop::new(1, dropped_fields.clone()),
72         y: PushOnDrop::new(2, dropped_fields.clone()),
73         z: PushOnDrop::new(3, dropped_fields.clone()),
74     };
75     drop(test_struct);
76     assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
77
78     // The same holds for tuple structs
79     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
80     let test_tuple_struct = TestTupleStruct(PushOnDrop::new(1, dropped_fields.clone()),
81                                             PushOnDrop::new(2, dropped_fields.clone()),
82                                             PushOnDrop::new(3, dropped_fields.clone()));
83     drop(test_tuple_struct);
84     assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
85
86     // Panic during struct construction means that fields are treated as local variables
87     // Therefore they are dropped in reverse order of initialization
88     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
89     let cloned = AssertUnwindSafe(dropped_fields.clone());
90     panic::catch_unwind(|| {
91         TestStruct {
92             x: PushOnDrop::new(2, cloned.clone()),
93             y: PushOnDrop::new(1, cloned.clone()),
94             z: panic!("this panic is caught :D")
95         };
96     }).err().unwrap();
97     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
98
99     // Test with different initialization order
100     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
101     let cloned = AssertUnwindSafe(dropped_fields.clone());
102     panic::catch_unwind(|| {
103         TestStruct {
104             y: PushOnDrop::new(2, cloned.clone()),
105             x: PushOnDrop::new(1, cloned.clone()),
106             z: panic!("this panic is caught :D")
107         };
108     }).err().unwrap();
109     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
110
111     // The same holds for tuple structs
112     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
113     let cloned = AssertUnwindSafe(dropped_fields.clone());
114     panic::catch_unwind(|| {
115         TestTupleStruct(PushOnDrop::new(2, cloned.clone()),
116                         PushOnDrop::new(1, cloned.clone()),
117                         panic!("this panic is caught :D"));
118     }).err().unwrap();
119     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
120 }
121
122 fn test_drop_enum() {
123     // Enum variants are dropped in the same order they are declared
124     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
125     let test_struct_enum = TestEnum::Struct {
126         x: PushOnDrop::new(1, dropped_fields.clone()),
127         y: PushOnDrop::new(2, dropped_fields.clone()),
128         z: PushOnDrop::new(3, dropped_fields.clone())
129     };
130     drop(test_struct_enum);
131     assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
132
133     // The same holds for tuple enum variants
134     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
135     let test_tuple_enum = TestEnum::Tuple(PushOnDrop::new(1, dropped_fields.clone()),
136                                           PushOnDrop::new(2, dropped_fields.clone()),
137                                           PushOnDrop::new(3, dropped_fields.clone()));
138     drop(test_tuple_enum);
139     assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
140
141     // Panic during enum construction means that fields are treated as local variables
142     // Therefore they are dropped in reverse order of initialization
143     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
144     let cloned = AssertUnwindSafe(dropped_fields.clone());
145     panic::catch_unwind(|| {
146         TestEnum::Struct {
147             x: PushOnDrop::new(2, cloned.clone()),
148             y: PushOnDrop::new(1, cloned.clone()),
149             z: panic!("this panic is caught :D")
150         };
151     }).err().unwrap();
152     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
153
154     // Test with different initialization order
155     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
156     let cloned = AssertUnwindSafe(dropped_fields.clone());
157     panic::catch_unwind(|| {
158         TestEnum::Struct {
159             y: PushOnDrop::new(2, cloned.clone()),
160             x: PushOnDrop::new(1, cloned.clone()),
161             z: panic!("this panic is caught :D")
162         };
163     }).err().unwrap();
164     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
165
166     // The same holds for tuple enum variants
167     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
168     let cloned = AssertUnwindSafe(dropped_fields.clone());
169     panic::catch_unwind(|| {
170         TestEnum::Tuple(PushOnDrop::new(2, cloned.clone()),
171                         PushOnDrop::new(1, cloned.clone()),
172                         panic!("this panic is caught :D"));
173     }).err().unwrap();
174     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
175 }
176
177 fn test_drop_list() {
178     // Elements in a Vec are dropped in the same order they are pushed
179     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
180     let xs = vec![PushOnDrop::new(1, dropped_fields.clone()),
181                   PushOnDrop::new(2, dropped_fields.clone()),
182                   PushOnDrop::new(3, dropped_fields.clone())];
183     drop(xs);
184     assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
185
186     // The same holds for arrays
187     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
188     let xs = [PushOnDrop::new(1, dropped_fields.clone()),
189               PushOnDrop::new(2, dropped_fields.clone()),
190               PushOnDrop::new(3, dropped_fields.clone())];
191     drop(xs);
192     assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
193
194     // Panic during vec construction means that fields are treated as local variables
195     // Therefore they are dropped in reverse order of initialization
196     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
197     let cloned = AssertUnwindSafe(dropped_fields.clone());
198     panic::catch_unwind(|| {
199         vec![
200             PushOnDrop::new(2, cloned.clone()),
201             PushOnDrop::new(1, cloned.clone()),
202             panic!("this panic is caught :D")
203         ];
204     }).err().unwrap();
205     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
206
207     // The same holds for arrays
208     let dropped_fields = Rc::new(RefCell::new(Vec::new()));
209     let cloned = AssertUnwindSafe(dropped_fields.clone());
210     panic::catch_unwind(|| {
211         [
212             PushOnDrop::new(2, cloned.clone()),
213             PushOnDrop::new(1, cloned.clone()),
214             panic!("this panic is caught :D")
215         ];
216     }).err().unwrap();
217     assert_eq!(*dropped_fields.borrow(), &[1, 2]);
218 }
219
220 fn main() {
221     test_drop_tuple();
222     test_drop_struct();
223     test_drop_enum();
224     test_drop_list();
225 }