| //@compile-flags: -Zmiri-tree-borrows | |
| // We invalidate a reference during a 2-phase borrow by doing a Foreign | |
| // Write in between the initial reborrow and function entry. UB occurs | |
| // on function entry when reborrow from a Disabled fails. | |
| // This test would pass under Stacked Borrows, but Tree Borrows | |
| // is more strict on 2-phase borrows. | |
| struct Foo(u64); | |
| impl Foo { | |
| fn add(&mut self, n: u64) -> u64 { | |
| //~^ ERROR: /reborrow through .* is forbidden/ | |
| self.0 + n | |
| } | |
| } | |
| fn main() { | |
| let mut f = Foo(0); | |
| let alias = &mut f.0 as *mut u64; | |
| let res = f.add(unsafe { | |
| // This is the access at fault, but it's not immediately apparent because | |
| // the reference that got invalidated is not under a Protector. | |
| *alias = 42; | |
| 0 | |
| }); | |
| // `res` could be optimized to be `0`, since at the time the reference for the `self` argument | |
| // is created, it has value `0`, and then later we add `0` to that. But turns out there is | |
| // a sneaky alias that's used to change the value of `*self` before it is read... | |
| assert_eq!(res, 42); | |
| } |