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