2 #![allow(non_upper_case_globals)]
4 // Issue 23611: this test is ensuring that, for an instance `X` of the
5 // enum `E`, if you swap in a different variant during the execution
6 // of the `<E as Drop>::drop`, then the appropriate substructure will
7 // be torn down after the `<E as Drop>::drop` method returns.
9 use std::cell::RefCell;
15 let log = RefCell::new(vec![]);
16 d::println("created empty log");
19 // println!("log: {:?}", &log.borrow()[..]);
24 // +-- Make D(test_1, 10000000)
25 // | +-- Make D(g_b_5, 50000001)
26 // | | in g_B(b2b0) from E::drop, b=b4b0
27 // | +-- Drop D(g_b_5, 50000001)
30 // | +-- Make D(drop_6, 60000002)
31 // | | +-- Make D(g_b_5, 50000003)
32 // | | | in g_B(b2b0) from E::drop, b=b4b1
33 // | | +-- Drop D(g_b_5, 50000003)
36 // | | +-- Make D(GaspB::drop_3, 30000004)
37 // | | | +-- Make D(g_b_5, 50000005)
38 // | | | | in g_B(b4b2) from GaspB::drop
39 // | | | +-- Drop D(g_b_5, 50000005)
42 // | | +-- Drop D(GaspB::drop_3, 30000004)
45 // +-- Drop D(test_1, 10000000)
48 // +-- Make D(GaspA::drop_2, 20000006)
49 // | | +-- Make D(f_a_4, 40000007)
50 // | | | in f_A(a3a0) from GaspA::drop
51 // | | +-- Drop D(f_a_4, 40000007)
54 // +-- Drop D(GaspA::drop_2, 20000006)
57 // +-- Drop D(drop_6, 60000002)
62 // For reference purposes, the old (incorrect) behavior would produce the following
63 // output, which you can compare to the above:
66 // +-- Make D(test_1, 10000000)
67 // | +-- Make D(g_b_5, 50000001)
68 // | | in g_B(b2b0) from E::drop, b=b4b0
69 // | +-- Drop D(g_b_5, 50000001)
71 // | +-- Make D(drop_6, 60000002)
72 // | | +-- Make D(g_b_5, 50000003)
73 // | | | in g_B(b2b0) from E::drop, b=b4b1
74 // | | +-- Drop D(g_b_5, 50000003)
76 // | | +-- Make D(GaspB::drop_3, 30000004)
77 // | | | +-- Make D(g_b_5, 50000005)
78 // | | | | in g_B(b4b2) from GaspB::drop
79 // | | | +-- Drop D(g_b_5, 50000005)
81 // | | +-- Drop D(GaspB::drop_3, 30000004)
83 // +-- Drop D(test_1, 10000000)
85 // +-- Make D(GaspB::drop_3, 30000006)
86 // | | +-- Make D(f_a_4, 40000007)
87 // | | | in f_A(a3a0) from GaspB::drop
88 // | | +-- Drop D(f_a_4, 40000007)
90 // +-- Drop D(GaspB::drop_3, 30000006)
92 // +-- Drop D(drop_6, 60000002)
94 // Note that this calls f_A from GaspB::drop (and thus creates a D
95 // with a uid incorporating the origin of GaspB's drop that
96 // surrounds the f_A invocation), but the code as written only
97 // ever hands f_A off to instances of GaspA, and thus one should
98 // be able to prove the invariant that f_A is *only* invoked from
99 // from an instance of GaspA (either via the GaspA drop
100 // implementation or the E drop implementaton). Yet the old (bad)
101 // behavior allowed a call to f_A to leak in while we are tearing
102 // down a value of type GaspB.
105 fn test<'a>(log: d::Log<'a>) {
106 let _e = E::B(GaspB(g_b, 0xB4B0, log, D::new("test", 1, log)), true);
109 struct GaspA<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
110 struct GaspB<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
112 impl<'a> Drop for GaspA<'a> {
114 let _d = d::D::new("GaspA::drop", 2, self.2);
115 (self.0)(self.1, "GaspA::drop", self.2);
119 impl<'a> Drop for GaspB<'a> {
121 let _d = d::D::new("GaspB::drop", 3, self.2);
122 (self.0)(self.1, "GaspB::drop", self.2);
127 A(GaspA<'a>, bool), B(GaspB<'a>, bool),
130 fn f_a(x: u32, ctxt: &str, log: d::Log) {
131 let _d = d::D::new("f_a", 4, log);
132 d::println(&format!("in f_A({:x}) from {}", x, ctxt));
134 fn g_b(y: u32, ctxt: &str, log: d::Log) {
135 let _d = d::D::new("g_b", 5, log);
136 d::println(&format!("in g_B({:x}) from {}", y, ctxt));
139 impl<'a> Drop for E<'a> {
141 let (do_drop, log) = match *self {
142 E::A(GaspA(ref f, ref mut val_a, log, ref _d_a), ref mut do_drop) => {
143 f(0xA1A0, &format!("E::drop, a={:x}", val_a), log);
145 // swap in do_drop := false to avoid infinite dtor regress
146 (mem::replace(do_drop, false), log)
148 E::B(GaspB(ref g, ref mut val_b, log, ref _d_b), ref mut do_drop) => {
149 g(0xB2B0, &format!("E::drop, b={:x}", val_b), log);
151 // swap in do_drop := false to avoid infinite dtor regress
152 (mem::replace(do_drop, false), log)
156 #[allow(unused_must_use)]
158 mem::replace(self, E::A(GaspA(f_a, 0xA3A0, log, D::new("drop", 6, log)), true));
163 // This module provides simultaneous printouts of the dynamic extents
164 // of all of the D values, in addition to logging the order that each
167 // This code is similar to a support code module embedded within
168 // test/run-pass/issue-123338-ensure-param-drop-order.rs; however,
169 // that (slightly simpler) code only identifies objects in the log via
170 // (creation) time-stamps; this incorporates both timestamping and the
171 // point of origin within the source code into the unique ID (uid).
173 const PREF_INDENT: u32 = 20;
176 #![allow(unused_parens)]
179 use std::cell::RefCell;
181 static mut counter: u16 = 0;
182 static mut trails: u64 = 0;
184 pub type Log<'a> = &'a RefCell<Vec<u32>>;
186 pub fn current_width() -> u32 {
187 unsafe { max_width() - trails.leading_zeros() }
190 pub fn max_width() -> u32 {
192 (mem::size_of_val(&trails)*8) as u32
196 pub fn indent_println(my_trails: u32, s: &str) {
197 let mut indent: String = String::new();
198 for i in 0..my_trails {
200 if trails & (1 << i) != 0 {
201 indent = indent + "| ";
203 indent = indent + " ";
207 println!("{}{}", indent, s);
210 pub fn println(s: &str) {
211 indent_println(super::PREF_INDENT, s);
214 fn first_avail() -> u32 {
217 if trails & (1 << i) == 0 {
222 panic!("exhausted trails");
226 name: &'static str, i: u8, uid: u32, trail: u32, log: Log<'a>
229 impl<'a> fmt::Display for D<'a> {
230 fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
231 write!(w, "D({}_{}, {})", self.name, self.i, self.uid)
236 pub fn new(name: &'static str, i: u8, log: Log<'a>) -> D<'a> {
238 let trail = first_avail();
239 let ctr = ((i as u32) * 10_000_000) + (counter as u32);
241 trails |= (1 << trail);
243 name: name, i: i, log: log, uid: ctr, trail: trail
245 indent_println(trail, &format!("+-- Make {}", ret));
251 impl<'a> Drop for D<'a> {
253 unsafe { trails &= !(1 << self.trail); };
254 self.log.borrow_mut().push(self.uid);
255 indent_println(self.trail, &format!("+-- Drop {}", self));
256 indent_println(::PREF_INDENT, "");