Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Revise intrinsic-move-val test to not require knowledge of whether fi…
…lling drop is in use.
  • Loading branch information
pnkfelix committed Jul 28, 2015
1 parent e25427a commit ff14eaf
Showing 1 changed file with 74 additions and 11 deletions.
85 changes: 74 additions & 11 deletions src/test/run-pass/intrinsic-move-val.rs
Expand Up @@ -9,13 +9,8 @@
// except according to those terms.


#![allow(unknown_features)]
#![feature(box_syntax)]
#![feature(intrinsics)]
// needed to check for drop fill word.
#![feature(filling_drop)]

use std::mem::{self, transmute};

mod rusti {
extern "rust-intrinsic" {
Expand All @@ -26,12 +21,80 @@ mod rusti {

pub fn main() {
unsafe {
let x: Box<_> = box 1;
let mut y = rusti::init();
let mut z: *const usize = transmute(&x);
// sanity check
check_drops_state(0, None);

let mut x: Box<D> = box D(1);
assert_eq!(x.0, 1);

// A normal overwrite, to demonstrate `check_drops_state`.
x = box D(2);

// At this point, one destructor has run, because the
// overwrite of `x` drops its initial value.
check_drops_state(1, Some(1));

let mut y: Box<D> = rusti::init();

// An initial binding does not overwrite anything.
check_drops_state(1, Some(1));

// Since `y` has been initialized via the `init` intrinsic, it
// would be unsound to directly overwrite its value via normal
// assignment.
//
// The code currently generated by the compiler is overly
// accepting, however, in that it will check if `y` is itself
// null and thus avoid the unsound action of attempting to
// free null. In other words, if we were to do a normal
// assignment like `y = box D(4);` here, it probably would not
// crash today. But the plan is that it may well crash in the
// future, (I believe).

// `x` is moved here; the manner in which this is tracked by the
// compiler is hidden.
rusti::move_val_init(&mut y, x);
assert_eq!(*y, 1);
// `x` is nulled out, not directly visible
assert_eq!(*z, mem::POST_DROP_USIZE);

// In particular, it may be tracked via a drop-flag embedded
// in the value, or via a null pointer, or via
// mem::POST_DROP_USIZE, or (most preferably) via a
// stack-local drop flag.
//
// (This test used to build-in knowledge of how it was
// tracked, and check that the underlying stack slot had been
// set to `mem::POST_DROP_USIZE`.)

// But what we *can* observe is how many times the destructor
// for `D` is invoked, and what the last value we saw was
// during such a destructor call. We do so after the end of
// this scope.

assert_eq!(y.0, 2);
y.0 = 3;
assert_eq!(y.0, 3);

check_drops_state(1, Some(1));
}

check_drops_state(2, Some(3));
}

static mut NUM_DROPS: i32 = 0;
static mut LAST_DROPPED: Option<i32> = None;

fn check_drops_state(num_drops: i32, last_dropped: Option<i32>) {
unsafe {
assert_eq!(NUM_DROPS, num_drops);
assert_eq!(LAST_DROPPED, last_dropped);
}
}

struct D(i32);
impl Drop for D {
fn drop(&mut self) {
unsafe {
NUM_DROPS += 1;
LAST_DROPPED = Some(self.0);
}
}
}

0 comments on commit ff14eaf

Please sign in to comment.