2 // ignore-wasm32-bare compiled with panic=abort by default
4 #![allow(dead_code, unreachable_code)]
6 use std::cell::RefCell;
8 use std::panic::{self, AssertUnwindSafe, UnwindSafe};
10 // This struct is used to record the order in which elements are dropped
12 vec: Rc<RefCell<Vec<u32>>>,
17 fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop {
18 PushOnDrop { vec, val }
22 impl Drop for PushOnDrop {
24 self.vec.borrow_mut().push(self.val)
28 impl UnwindSafe for PushOnDrop { }
38 struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop);
42 Tuple(PushOnDrop, PushOnDrop, PushOnDrop),
43 Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop }
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()));
52 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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"));
63 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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()),
75 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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]);
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(|| {
91 x: PushOnDrop::new(2, cloned.clone()),
92 y: PushOnDrop::new(1, cloned.clone()),
93 z: panic!("this panic is caught :D")
96 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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(|| {
103 y: PushOnDrop::new(2, cloned.clone()),
104 x: PushOnDrop::new(1, cloned.clone()),
105 z: panic!("this panic is caught :D")
108 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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"));
118 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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())
129 drop(test_struct_enum);
130 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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]);
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(|| {
146 x: PushOnDrop::new(2, cloned.clone()),
147 y: PushOnDrop::new(1, cloned.clone()),
148 z: panic!("this panic is caught :D")
151 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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(|| {
158 y: PushOnDrop::new(2, cloned.clone()),
159 x: PushOnDrop::new(1, cloned.clone()),
160 z: panic!("this panic is caught :D")
163 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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"));
173 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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())];
183 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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())];
191 assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
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(|| {
199 PushOnDrop::new(2, cloned.clone()),
200 PushOnDrop::new(1, cloned.clone()),
201 panic!("this panic is caught :D")
204 assert_eq!(*dropped_fields.borrow(), &[1, 2]);
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(|| {
211 PushOnDrop::new(2, cloned.clone()),
212 PushOnDrop::new(1, cloned.clone()),
213 panic!("this panic is caught :D")
216 assert_eq!(*dropped_fields.borrow(), &[1, 2]);