rust/tests/ui/drop/issue-23338-ensure-param-drop-order.rs

170 lines
4.7 KiB
Rust

//@ 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, "");
}
}
}