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