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