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