From ff14eaf0542b94dce2b4afce1b5443795c11884a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 8 Jun 2015 12:30:58 +0200 Subject: [PATCH] Revise intrinsic-move-val test to not require knowledge of whether filling drop is in use. --- src/test/run-pass/intrinsic-move-val.rs | 85 +++++++++++++++++++++---- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/src/test/run-pass/intrinsic-move-val.rs b/src/test/run-pass/intrinsic-move-val.rs index 84af4fd0a08ea..eb482b3230a43 100644 --- a/src/test/run-pass/intrinsic-move-val.rs +++ b/src/test/run-pass/intrinsic-move-val.rs @@ -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" { @@ -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 = 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 = 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 = None; + +fn check_drops_state(num_drops: i32, last_dropped: Option) { + 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); + } } }