3 // ignore-wasm32-bare compiled with panic=abort by default
5 #![allow(dead_code, unreachable_code)]
7 use std::cell::RefCell;
9 use std::panic::{self, AssertUnwindSafe, UnwindSafe};
11 // This struct is used to record the order in which elements are dropped
13 vec: Rc<RefCell<Vec<u32>>>,
18 fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop {
19 PushOnDrop { vec, val }
23 impl Drop for PushOnDrop {
25 self.vec.borrow_mut().push(self.val)
29 impl UnwindSafe for PushOnDrop { }
39 struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop);
43 Tuple(PushOnDrop, PushOnDrop, PushOnDrop),
44 Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop }
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()));
53 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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"));
64 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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()),
76 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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]);
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(|| {
92 x: PushOnDrop::new(2, cloned.clone()),
93 y: PushOnDrop::new(1, cloned.clone()),
94 z: panic!("this panic is caught :D")
97 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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(|| {
104 y: PushOnDrop::new(2, cloned.clone()),
105 x: PushOnDrop::new(1, cloned.clone()),
106 z: panic!("this panic is caught :D")
109 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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"));
119 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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())
130 drop(test_struct_enum);
131 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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]);
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(|| {
147 x: PushOnDrop::new(2, cloned.clone()),
148 y: PushOnDrop::new(1, cloned.clone()),
149 z: panic!("this panic is caught :D")
152 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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(|| {
159 y: PushOnDrop::new(2, cloned.clone()),
160 x: PushOnDrop::new(1, cloned.clone()),
161 z: panic!("this panic is caught :D")
164 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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"));
174 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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())];
184 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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())];
192 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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(|| {
200 PushOnDrop::new(2, cloned.clone()),
201 PushOnDrop::new(1, cloned.clone()),
202 panic!("this panic is caught :D")
205 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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(|| {
212 PushOnDrop::new(2, cloned.clone()),
213 PushOnDrop::new(1, cloned.clone()),
214 panic!("this panic is caught :D")
217 assert_eq!(*dropped_fields.borrow(), &[1, 2]);