Skip to content

Commit d5acb55

Browse files
committed
regression test.
1 parent 8f98795 commit d5acb55

File tree

1 file changed

+265
-0
lines changed

1 file changed

+265
-0
lines changed
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
// Copyright 2015 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+
// Issue 23611: this test is ensuring that, for an instance `X` of the
12+
// enum `E`, if you swap in a different variant during the execution
13+
// of the `<E as Drop>::drop`, then the appropriate substructure will
14+
// be torn down after the `<E as Drop>::drop` method returns.
15+
16+
use std::cell::RefCell;
17+
use std::mem;
18+
19+
use self::d::D;
20+
21+
pub fn main() {
22+
let log = RefCell::new(vec![]);
23+
d::println(&format!("created empty log"));
24+
test(&log);
25+
26+
// println!("log: {:?}", &log.borrow()[..]);
27+
assert_eq!(
28+
&log.borrow()[..],
29+
[
30+
// created empty log
31+
// +-- Make D(test_1, 10000000)
32+
// | +-- Make D(g_b_5, 50000001)
33+
// | | in g_B(b2b0) from E::drop, b=b4b0
34+
// | +-- Drop D(g_b_5, 50000001)
35+
50000001,
36+
// |
37+
// | +-- Make D(drop_6, 60000002)
38+
// | | +-- Make D(g_b_5, 50000003)
39+
// | | | in g_B(b2b0) from E::drop, b=b4b1
40+
// | | +-- Drop D(g_b_5, 50000003)
41+
50000003,
42+
// | |
43+
// | | +-- Make D(GaspB::drop_3, 30000004)
44+
// | | | +-- Make D(g_b_5, 50000005)
45+
// | | | | in g_B(b4b2) from GaspB::drop
46+
// | | | +-- Drop D(g_b_5, 50000005)
47+
50000005,
48+
// | | |
49+
// | | +-- Drop D(GaspB::drop_3, 30000004)
50+
30000004,
51+
// | |
52+
// +-- Drop D(test_1, 10000000)
53+
10000000,
54+
// |
55+
// +-- Make D(GaspA::drop_2, 20000006)
56+
// | | +-- Make D(f_a_4, 40000007)
57+
// | | | in f_A(a3a0) from GaspA::drop
58+
// | | +-- Drop D(f_a_4, 40000007)
59+
40000007,
60+
// | |
61+
// +-- Drop D(GaspA::drop_2, 20000006)
62+
20000006,
63+
// |
64+
// +-- Drop D(drop_6, 60000002)
65+
60000002
66+
//
67+
]);
68+
69+
// For reference purposes, the old (incorrect) behavior would produce the following
70+
// output, which you can compare to the above:
71+
//
72+
// created empty log
73+
// +-- Make D(test_1, 10000000)
74+
// | +-- Make D(g_b_5, 50000001)
75+
// | | in g_B(b2b0) from E::drop, b=b4b0
76+
// | +-- Drop D(g_b_5, 50000001)
77+
// |
78+
// | +-- Make D(drop_6, 60000002)
79+
// | | +-- Make D(g_b_5, 50000003)
80+
// | | | in g_B(b2b0) from E::drop, b=b4b1
81+
// | | +-- Drop D(g_b_5, 50000003)
82+
// | |
83+
// | | +-- Make D(GaspB::drop_3, 30000004)
84+
// | | | +-- Make D(g_b_5, 50000005)
85+
// | | | | in g_B(b4b2) from GaspB::drop
86+
// | | | +-- Drop D(g_b_5, 50000005)
87+
// | | |
88+
// | | +-- Drop D(GaspB::drop_3, 30000004)
89+
// | |
90+
// +-- Drop D(test_1, 10000000)
91+
// |
92+
// +-- Make D(GaspB::drop_3, 30000006)
93+
// | | +-- Make D(f_a_4, 40000007)
94+
// | | | in f_A(a3a0) from GaspB::drop
95+
// | | +-- Drop D(f_a_4, 40000007)
96+
// | |
97+
// +-- Drop D(GaspB::drop_3, 30000006)
98+
// |
99+
// +-- Drop D(drop_6, 60000002)
100+
101+
// Note that this calls f_A from GaspB::drop (and thus creates a D
102+
// with a uid incorporating the origin of GaspB's drop that
103+
// surrounds the f_A invocation), but the code as written only
104+
// ever hands f_A off to instances of GaspA, and thus one should
105+
// be able to prove the invariant that f_A is *only* invoked from
106+
// from an instance of GaspA (either via the GaspA drop
107+
// implementation or the E drop implementaton). Yet the old (bad)
108+
// behavior allowed a call to f_A to leak in while we are tearing
109+
// down a value of type GaspB.
110+
}
111+
112+
fn test<'a>(log: d::Log<'a>) {
113+
let _e = E::B(GaspB(g_b, 0xB4B0, log, D::new("test", 1, log)), true);
114+
}
115+
116+
struct GaspA<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
117+
struct GaspB<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
118+
119+
impl<'a> Drop for GaspA<'a> {
120+
fn drop(&mut self) {
121+
let _d = d::D::new("GaspA::drop", 2, self.2);
122+
(self.0)(self.1, "GaspA::drop", self.2);
123+
}
124+
}
125+
126+
impl<'a> Drop for GaspB<'a> {
127+
fn drop(&mut self) {
128+
let _d = d::D::new("GaspB::drop", 3, self.2);
129+
(self.0)(self.1, "GaspB::drop", self.2);
130+
}
131+
}
132+
133+
enum E<'a> {
134+
A(GaspA<'a>, bool), B(GaspB<'a>, bool),
135+
}
136+
137+
fn f_a(x: u32, ctxt: &str, log: d::Log) {
138+
let _d = d::D::new("f_a", 4, log);
139+
d::println(&format!("in f_A({:x}) from {}", x, ctxt));
140+
}
141+
fn g_b(y: u32, ctxt: &str, log: d::Log) {
142+
let _d = d::D::new("g_b", 5, log);
143+
d::println(&format!("in g_B({:x}) from {}", y, ctxt));
144+
}
145+
146+
impl<'a> Drop for E<'a> {
147+
fn drop(&mut self) {
148+
let (do_drop, log) = match *self {
149+
E::A(GaspA(ref f, ref mut val_a, log, ref _d_a), ref mut do_drop) => {
150+
f(0xA1A0, &format!("E::drop, a={:x}", val_a), log);
151+
*val_a += 1;
152+
// swap in do_drop := false to avoid infinite dtor regress
153+
(mem::replace(do_drop, false), log)
154+
}
155+
E::B(GaspB(ref g, ref mut val_b, log, ref _d_b), ref mut do_drop) => {
156+
g(0xB2B0, &format!("E::drop, b={:x}", val_b), log);
157+
*val_b += 1;
158+
// swap in do_drop := false to avoid infinite dtor regress
159+
(mem::replace(do_drop, false), log)
160+
}
161+
};
162+
163+
if do_drop {
164+
mem::replace(self, E::A(GaspA(f_a, 0xA3A0, log, D::new("drop", 6, log)), true));
165+
}
166+
}
167+
}
168+
169+
// This module provides simultaneous printouts of the dynamic extents
170+
// of all of the D values, in addition to logging the order that each
171+
// is dropped.
172+
//
173+
// This code is similar to a support code module embedded within
174+
// test/run-pass/issue-123338-ensure-param-drop-order.rs; however,
175+
// that (slightly simpler) code only identifies objects in the log via
176+
// (creation) time-stamps; this incorporates both timestamping and the
177+
// point of origin within the source code into the unique ID (uid).
178+
179+
const PREF_INDENT: u32 = 20;
180+
181+
pub mod d {
182+
#![allow(unused_parens)]
183+
use std::fmt;
184+
use std::mem;
185+
use std::cell::RefCell;
186+
187+
static mut counter: u16 = 0;
188+
static mut trails: u64 = 0;
189+
190+
pub type Log<'a> = &'a RefCell<Vec<u32>>;
191+
192+
pub fn current_width() -> u32 {
193+
unsafe { max_width() - trails.leading_zeros() }
194+
}
195+
196+
pub fn max_width() -> u32 {
197+
unsafe {
198+
(mem::size_of_val(&trails)*8) as u32
199+
}
200+
}
201+
202+
pub fn indent_println(my_trails: u32, s: &str) {
203+
let mut indent: String = String::new();
204+
for i in 0..my_trails {
205+
unsafe {
206+
if trails & (1 << i) != 0 {
207+
indent = indent + "| ";
208+
} else {
209+
indent = indent + " ";
210+
}
211+
}
212+
}
213+
println!("{}{}", indent, s);
214+
}
215+
216+
pub fn println(s: &str) {
217+
indent_println(super::PREF_INDENT, s);
218+
}
219+
220+
fn first_avail() -> u32 {
221+
unsafe {
222+
for i in 0..64 {
223+
if trails & (1 << i) == 0 {
224+
return i;
225+
}
226+
}
227+
}
228+
panic!("exhausted trails");
229+
}
230+
231+
pub struct D<'a> {
232+
name: &'static str, i: u8, uid: u32, trail: u32, log: Log<'a>
233+
}
234+
235+
impl<'a> fmt::Display for D<'a> {
236+
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
237+
write!(w, "D({}_{}, {})", self.name, self.i, self.uid)
238+
}
239+
}
240+
241+
impl<'a> D<'a> {
242+
pub fn new(name: &'static str, i: u8, log: Log<'a>) -> D<'a> {
243+
unsafe {
244+
let trail = first_avail();
245+
let ctr = ((i as u32) * 10_000_000) + (counter as u32);
246+
counter += 1;
247+
trails |= (1 << trail);
248+
let ret = D {
249+
name: name, i: i, log: log, uid: ctr, trail: trail
250+
};
251+
indent_println(trail, &format!("+-- Make {}", ret));
252+
ret
253+
}
254+
}
255+
}
256+
257+
impl<'a> Drop for D<'a> {
258+
fn drop(&mut self) {
259+
unsafe { trails &= !(1 << self.trail); };
260+
self.log.borrow_mut().push(self.uid);
261+
indent_println(self.trail, &format!("+-- Drop {}", self));
262+
indent_println(::PREF_INDENT, "");
263+
}
264+
}
265+
}

0 commit comments

Comments
 (0)