| //@revisions: stack tree |
| //@[tree]compile-flags: -Zmiri-tree-borrows |
| #![feature(custom_mir, core_intrinsics)] |
| use std::intrinsics::mir::*; |
| |
| pub struct S(i32); |
| |
| #[custom_mir(dialect = "runtime", phase = "optimized")] |
| fn main() { |
| mir! { |
| let _unit: (); |
| { |
| let non_copy = S(42); |
| let ptr = std::ptr::addr_of_mut!(non_copy); |
| // Inside `callee`, the first argument and `*ptr` are basically |
| // aliasing places! |
| Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) |
| } |
| after_call = { |
| Return() |
| } |
| |
| } |
| } |
| |
| pub fn callee(x: S, ptr: *mut S) { |
| // With the setup above, if `x` is indeed moved in |
| // (i.e. we actually just get a pointer to the underlying storage), |
| // then writing to `ptr` will change the value stored in `x`! |
| unsafe { ptr.write(S(0)) }; |
| //~[stack]^ ERROR: not granting access |
| //~[tree]| ERROR: /write access .* forbidden/ |
| assert_eq!(x.0, 42); |
| } |