]>
Commit | Line | Data |
---|---|---|
041b39d2 XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
abe05a73 XL |
11 | // ignore-wasm32-bare compiled with panic=abort by default |
12 | ||
041b39d2 XL |
13 | #![allow(dead_code, unreachable_code)] |
14 | ||
15 | use std::cell::RefCell; | |
16 | use std::rc::Rc; | |
17 | use std::panic::{self, AssertUnwindSafe, UnwindSafe}; | |
18 | ||
19 | // This struct is used to record the order in which elements are dropped | |
20 | struct PushOnDrop { | |
21 | vec: Rc<RefCell<Vec<u32>>>, | |
22 | val: u32 | |
23 | } | |
24 | ||
25 | impl PushOnDrop { | |
26 | fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop { | |
27 | PushOnDrop { vec, val } | |
28 | } | |
29 | } | |
30 | ||
31 | impl Drop for PushOnDrop { | |
32 | fn drop(&mut self) { | |
33 | self.vec.borrow_mut().push(self.val) | |
34 | } | |
35 | } | |
36 | ||
37 | impl UnwindSafe for PushOnDrop { } | |
38 | ||
39 | // Structs | |
40 | struct TestStruct { | |
41 | x: PushOnDrop, | |
42 | y: PushOnDrop, | |
43 | z: PushOnDrop | |
44 | } | |
45 | ||
46 | // Tuple structs | |
47 | struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop); | |
48 | ||
49 | // Enum variants | |
50 | enum TestEnum { | |
51 | Tuple(PushOnDrop, PushOnDrop, PushOnDrop), | |
52 | Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop } | |
53 | } | |
54 | ||
55 | fn test_drop_tuple() { | |
56 | // Tuple fields are dropped in the same order they are declared | |
57 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
58 | let test_tuple = (PushOnDrop::new(1, dropped_fields.clone()), | |
59 | PushOnDrop::new(2, dropped_fields.clone())); | |
60 | drop(test_tuple); | |
61 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
62 | ||
63 | // Panic during construction means that fields are treated as local variables | |
64 | // Therefore they are dropped in reverse order of initialization | |
65 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
66 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
67 | panic::catch_unwind(|| { | |
68 | (PushOnDrop::new(2, cloned.clone()), | |
69 | PushOnDrop::new(1, cloned.clone()), | |
70 | panic!("this panic is catched :D")); | |
71 | }).err().unwrap(); | |
72 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
73 | } | |
74 | ||
75 | fn test_drop_struct() { | |
76 | // Struct fields are dropped in the same order they are declared | |
77 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
78 | let test_struct = TestStruct { | |
79 | x: PushOnDrop::new(1, dropped_fields.clone()), | |
80 | y: PushOnDrop::new(2, dropped_fields.clone()), | |
81 | z: PushOnDrop::new(3, dropped_fields.clone()), | |
82 | }; | |
83 | drop(test_struct); | |
84 | assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); | |
85 | ||
86 | // The same holds for tuple structs | |
87 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
88 | let test_tuple_struct = TestTupleStruct(PushOnDrop::new(1, dropped_fields.clone()), | |
89 | PushOnDrop::new(2, dropped_fields.clone()), | |
90 | PushOnDrop::new(3, dropped_fields.clone())); | |
91 | drop(test_tuple_struct); | |
92 | assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); | |
93 | ||
94 | // Panic during struct construction means that fields are treated as local variables | |
95 | // Therefore they are dropped in reverse order of initialization | |
96 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
97 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
98 | panic::catch_unwind(|| { | |
99 | TestStruct { | |
100 | x: PushOnDrop::new(2, cloned.clone()), | |
101 | y: PushOnDrop::new(1, cloned.clone()), | |
102 | z: panic!("this panic is catched :D") | |
103 | }; | |
104 | }).err().unwrap(); | |
105 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
106 | ||
107 | // Test with different initialization order | |
108 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
109 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
110 | panic::catch_unwind(|| { | |
111 | TestStruct { | |
112 | y: PushOnDrop::new(2, cloned.clone()), | |
113 | x: PushOnDrop::new(1, cloned.clone()), | |
114 | z: panic!("this panic is catched :D") | |
115 | }; | |
116 | }).err().unwrap(); | |
117 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
118 | ||
119 | // The same holds for tuple structs | |
120 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
121 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
122 | panic::catch_unwind(|| { | |
123 | TestTupleStruct(PushOnDrop::new(2, cloned.clone()), | |
124 | PushOnDrop::new(1, cloned.clone()), | |
125 | panic!("this panic is catched :D")); | |
126 | }).err().unwrap(); | |
127 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
128 | } | |
129 | ||
130 | fn test_drop_enum() { | |
131 | // Enum variants are dropped in the same order they are declared | |
132 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
133 | let test_struct_enum = TestEnum::Struct { | |
134 | x: PushOnDrop::new(1, dropped_fields.clone()), | |
135 | y: PushOnDrop::new(2, dropped_fields.clone()), | |
136 | z: PushOnDrop::new(3, dropped_fields.clone()) | |
137 | }; | |
138 | drop(test_struct_enum); | |
139 | assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); | |
140 | ||
141 | // The same holds for tuple enum variants | |
142 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
143 | let test_tuple_enum = TestEnum::Tuple(PushOnDrop::new(1, dropped_fields.clone()), | |
144 | PushOnDrop::new(2, dropped_fields.clone()), | |
145 | PushOnDrop::new(3, dropped_fields.clone())); | |
146 | drop(test_tuple_enum); | |
147 | assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); | |
148 | ||
149 | // Panic during enum construction means that fields are treated as local variables | |
150 | // Therefore they are dropped in reverse order of initialization | |
151 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
152 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
153 | panic::catch_unwind(|| { | |
154 | TestEnum::Struct { | |
155 | x: PushOnDrop::new(2, cloned.clone()), | |
156 | y: PushOnDrop::new(1, cloned.clone()), | |
157 | z: panic!("this panic is catched :D") | |
158 | }; | |
159 | }).err().unwrap(); | |
160 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
161 | ||
162 | // Test with different initialization order | |
163 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
164 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
165 | panic::catch_unwind(|| { | |
166 | TestEnum::Struct { | |
167 | y: PushOnDrop::new(2, cloned.clone()), | |
168 | x: PushOnDrop::new(1, cloned.clone()), | |
169 | z: panic!("this panic is catched :D") | |
170 | }; | |
171 | }).err().unwrap(); | |
172 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
173 | ||
174 | // The same holds for tuple enum variants | |
175 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
176 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
177 | panic::catch_unwind(|| { | |
178 | TestEnum::Tuple(PushOnDrop::new(2, cloned.clone()), | |
179 | PushOnDrop::new(1, cloned.clone()), | |
180 | panic!("this panic is catched :D")); | |
181 | }).err().unwrap(); | |
182 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
183 | } | |
184 | ||
185 | fn test_drop_list() { | |
186 | // Elements in a Vec are dropped in the same order they are pushed | |
187 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
188 | let xs = vec![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 | // The same holds for arrays | |
195 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
196 | let xs = [PushOnDrop::new(1, dropped_fields.clone()), | |
197 | PushOnDrop::new(2, dropped_fields.clone()), | |
198 | PushOnDrop::new(3, dropped_fields.clone())]; | |
199 | drop(xs); | |
200 | assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]); | |
201 | ||
202 | // Panic during vec construction means that fields are treated as local variables | |
203 | // Therefore they are dropped in reverse order of initialization | |
204 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
205 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
206 | panic::catch_unwind(|| { | |
207 | vec![ | |
208 | PushOnDrop::new(2, cloned.clone()), | |
209 | PushOnDrop::new(1, cloned.clone()), | |
210 | panic!("this panic is catched :D") | |
211 | ]; | |
212 | }).err().unwrap(); | |
213 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
214 | ||
215 | // The same holds for arrays | |
216 | let dropped_fields = Rc::new(RefCell::new(Vec::new())); | |
217 | let cloned = AssertUnwindSafe(dropped_fields.clone()); | |
218 | panic::catch_unwind(|| { | |
219 | [ | |
220 | PushOnDrop::new(2, cloned.clone()), | |
221 | PushOnDrop::new(1, cloned.clone()), | |
222 | panic!("this panic is catched :D") | |
223 | ]; | |
224 | }).err().unwrap(); | |
225 | assert_eq!(*dropped_fields.borrow(), &[1, 2]); | |
226 | } | |
227 | ||
228 | fn main() { | |
229 | test_drop_tuple(); | |
230 | test_drop_struct(); | |
231 | test_drop_enum(); | |
232 | test_drop_list(); | |
233 | } |