]> git.proxmox.com Git - rustc.git/blame - src/test/run-pass/rfc1857-drop-order.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / test / run-pass / rfc1857-drop-order.rs
CommitLineData
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
15use std::cell::RefCell;
16use std::rc::Rc;
17use std::panic::{self, AssertUnwindSafe, UnwindSafe};
18
19// This struct is used to record the order in which elements are dropped
20struct PushOnDrop {
21 vec: Rc<RefCell<Vec<u32>>>,
22 val: u32
23}
24
25impl PushOnDrop {
26 fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop {
27 PushOnDrop { vec, val }
28 }
29}
30
31impl Drop for PushOnDrop {
32 fn drop(&mut self) {
33 self.vec.borrow_mut().push(self.val)
34 }
35}
36
37impl UnwindSafe for PushOnDrop { }
38
39// Structs
40struct TestStruct {
41 x: PushOnDrop,
42 y: PushOnDrop,
43 z: PushOnDrop
44}
45
46// Tuple structs
47struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop);
48
49// Enum variants
50enum TestEnum {
51 Tuple(PushOnDrop, PushOnDrop, PushOnDrop),
52 Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop }
53}
54
55fn 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
75fn 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
130fn 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
185fn 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
228fn main() {
229 test_drop_tuple();
230 test_drop_struct();
231 test_drop_enum();
232 test_drop_list();
233}