]> git.lizzy.rs Git - rust.git/blob - src/test/run-pass/intrinsic-move-val.rs
Auto merge of #28816 - petrochenkov:unistruct, r=nrc
[rust.git] / src / test / run-pass / intrinsic-move-val.rs
1 // Copyright 2012 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
12 #![feature(box_syntax)]
13 #![feature(intrinsics)]
14
15 mod rusti {
16     extern "rust-intrinsic" {
17         pub fn init<T>() -> T;
18         pub fn move_val_init<T>(dst: *mut T, src: T);
19     }
20 }
21
22 pub fn main() {
23     unsafe {
24         // sanity check
25         check_drops_state(0, None);
26
27         let mut x: Box<D> = box D(1);
28         assert_eq!(x.0, 1);
29
30         // A normal overwrite, to demonstrate `check_drops_state`.
31         x = box D(2);
32
33         // At this point, one destructor has run, because the
34         // overwrite of `x` drops its initial value.
35         check_drops_state(1, Some(1));
36
37         let mut y: Box<D> = rusti::init();
38
39         // An initial binding does not overwrite anything.
40         check_drops_state(1, Some(1));
41
42         // Since `y` has been initialized via the `init` intrinsic, it
43         // would be unsound to directly overwrite its value via normal
44         // assignment.
45         //
46         // The code currently generated by the compiler is overly
47         // accepting, however, in that it will check if `y` is itself
48         // null and thus avoid the unsound action of attempting to
49         // free null. In other words, if we were to do a normal
50         // assignment like `y = box D(4);` here, it probably would not
51         // crash today. But the plan is that it may well crash in the
52         // future, (I believe).
53
54         // `x` is moved here; the manner in which this is tracked by the
55         // compiler is hidden.
56         rusti::move_val_init(&mut y, x);
57
58         // In particular, it may be tracked via a drop-flag embedded
59         // in the value, or via a null pointer, or via
60         // mem::POST_DROP_USIZE, or (most preferably) via a
61         // stack-local drop flag.
62         //
63         // (This test used to build-in knowledge of how it was
64         // tracked, and check that the underlying stack slot had been
65         // set to `mem::POST_DROP_USIZE`.)
66
67         // But what we *can* observe is how many times the destructor
68         // for `D` is invoked, and what the last value we saw was
69         // during such a destructor call. We do so after the end of
70         // this scope.
71
72         assert_eq!(y.0, 2);
73         y.0 = 3;
74         assert_eq!(y.0, 3);
75
76         check_drops_state(1, Some(1));
77     }
78
79     check_drops_state(2, Some(3));
80 }
81
82 static mut NUM_DROPS: i32 = 0;
83 static mut LAST_DROPPED: Option<i32> = None;
84
85 fn check_drops_state(num_drops: i32, last_dropped: Option<i32>) {
86     unsafe {
87         assert_eq!(NUM_DROPS, num_drops);
88         assert_eq!(LAST_DROPPED, last_dropped);
89     }
90 }
91
92 struct D(i32);
93 impl Drop for D {
94     fn drop(&mut self) {
95         unsafe {
96             NUM_DROPS += 1;
97             LAST_DROPPED = Some(self.0);
98         }
99     }
100 }