]> git.lizzy.rs Git - rust.git/blob - src/test/ui/issues/issue-23338-ensure-param-drop-order.rs
Auto merge of #78066 - bugadani:wat, r=jonas-schievink
[rust.git] / src / test / ui / issues / issue-23338-ensure-param-drop-order.rs
1 // run-pass
2 #![allow(non_upper_case_globals)]
3
4 // ignore-pretty issue #37201
5
6 // This test is ensuring that parameters are indeed dropped after
7 // temporaries in a fn body.
8
9 use std::cell::RefCell;
10
11 use self::d::D;
12
13 pub fn main() {
14     let log = RefCell::new(vec![]);
15     d::println("created empty log");
16     test(&log);
17
18     assert_eq!(&log.borrow()[..],
19                [
20                    //                                    created empty log
21                    //    +-- Make D(da_0, 0)
22                    //    | +-- Make D(de_1, 1)
23                    //    | |                             calling foo
24                    //    | |                             entered foo
25                    //    | | +-- Make D(de_2, 2)
26                    //    | | | +-- Make D(da_1, 3)
27                    //    | | | | +-- Make D(de_3, 4)
28                    //    | | | | | +-- Make D(de_4, 5)
29                    3, // | | | +-- Drop D(da_1, 3)
30                    //    | | |   | |
31                    4, // | | |   +-- Drop D(de_3, 4)
32                    //    | | |     |
33                    //    | | |     |                     eval tail of foo
34                    //    | | | +-- Make D(de_5, 6)
35                    //    | | | | +-- Make D(de_6, 7)
36                    5, // | | | | | +-- Drop D(de_4, 5)
37                    //    | | | | |
38                    2, // | | +-- Drop D(de_2, 2)
39                    //    | |   | |
40                    6, // | |   +-- Drop D(de_5, 6)
41                    //    | |     |
42                    1, // | +-- Drop D(de_1, 1)
43                    //    |       |
44                    0, // +-- Drop D(da_0, 0)
45                    //            |
46                    //            |                       result D(de_6, 7)
47                    7 //          +-- Drop D(de_6, 7)
48
49                        ]);
50 }
51
52 fn test<'a>(log: d::Log<'a>) {
53     let da = D::new("da", 0, log);
54     let de = D::new("de", 1, log);
55     d::println("calling foo");
56     let result = foo(da, de);
57     d::println(&format!("result {}", result));
58 }
59
60 fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> {
61     d::println("entered foo");
62     let de2 = de1.incr();      // creates D(de_2, 2)
63     let de4 = {
64         let _da1 = da0.incr(); // creates D(da_1, 3)
65         de2.incr().incr()      // creates D(de_3, 4) and D(de_4, 5)
66     };
67     d::println("eval tail of foo");
68     de4.incr().incr()          // creates D(de_5, 6) and D(de_6, 7)
69 }
70
71 // This module provides simultaneous printouts of the dynamic extents
72 // of all of the D values, in addition to logging the order that each
73 // is dropped.
74
75 const PREF_INDENT: u32 = 16;
76
77 pub mod d {
78     #![allow(unused_parens)]
79     use std::fmt;
80     use std::mem;
81     use std::cell::RefCell;
82
83     static mut counter: u32 = 0;
84     static mut trails: u64 = 0;
85
86     pub type Log<'a> = &'a RefCell<Vec<u32>>;
87
88     pub fn current_width() -> u32 {
89         unsafe { max_width() - trails.leading_zeros() }
90     }
91
92     pub fn max_width() -> u32 {
93         unsafe {
94             (mem::size_of_val(&trails)*8) as u32
95         }
96     }
97
98     pub fn indent_println(my_trails: u32, s: &str) {
99         let mut indent: String = String::new();
100         for i in 0..my_trails {
101             unsafe {
102                 if trails & (1 << i) != 0 {
103                     indent = indent + "| ";
104                 } else {
105                     indent = indent + "  ";
106                 }
107             }
108         }
109         println!("{}{}", indent, s);
110     }
111
112     pub fn println(s: &str) {
113         indent_println(super::PREF_INDENT, s);
114     }
115
116     fn first_avail() -> u32 {
117         unsafe {
118             for i in 0..64 {
119                 if trails & (1 << i) == 0 {
120                     return i;
121                 }
122             }
123         }
124         panic!("exhausted trails");
125     }
126
127     pub struct D<'a> {
128         name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a>
129     }
130
131     impl<'a> fmt::Display for D<'a> {
132         fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
133             write!(w, "D({}_{}, {})", self.name, self.i, self.uid)
134         }
135     }
136
137     impl<'a> D<'a> {
138         pub fn new(name: &'static str, i: u32, log: Log<'a>) -> D<'a> {
139             unsafe {
140                 let trail = first_avail();
141                 let ctr = counter;
142                 counter += 1;
143                 trails |= (1 << trail);
144                 let ret = D {
145                     name: name, i: i, log: log, uid: ctr, trail: trail
146                 };
147                 indent_println(trail, &format!("+-- Make {}", ret));
148                 ret
149             }
150         }
151         pub fn incr(&self) -> D<'a> {
152             D::new(self.name, self.i + 1, self.log)
153         }
154     }
155
156     impl<'a> Drop for D<'a> {
157         fn drop(&mut self) {
158             unsafe { trails &= !(1 << self.trail); };
159             self.log.borrow_mut().push(self.uid);
160             indent_println(self.trail, &format!("+-- Drop {}", self));
161             indent_println(::PREF_INDENT, "");
162         }
163     }
164 }