//@compile-flags: -Zmiri-tree-borrows // These tests fail Stacked Borrows, but pass Tree Borrows. // The first four have in common that in SB a mutable reborrow is enough to produce // write access errors, but in TB an actual write is needed. // A modified version of each is also available that fails Tree Borrows. mod fnentry_invalidation { // Copied directly from fail/stacked_borrows/fnentry_invalidation.rs // Version that fails TB: fail/tree_borrows/fnentry_invalidation.rs pub fn main() { let mut x = 0i32; let z = &mut x as *mut i32; x.do_bad(); unsafe { let _oof = *z; // In SB this is an error, but in TB the mutable reborrow did // not invalidate z for reading. } } trait Bad { fn do_bad(&mut self) { // who knows } } impl Bad for i32 {} } mod pass_invalid_mut { // Copied directly from fail/stacked_borrows/pass_invalid_mut.rs // Version that fails TB: fail/tree_borrows/pass_invalid_mut.rs fn foo(_: &mut i32) {} pub fn main() { let x = &mut 42; let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // In SB this invalidates xref... foo(xref); // ...which then cannot be reborrowed here. // But in TB xref is Reserved and thus still writeable. } } mod return_invalid_mut { // Copied directly from fail/stacked_borrows/return_invalid_mut.rs // Version that fails TB: fail/tree_borrows/return_invalid_mut.rs fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // In SB this invalidates ret... ret // ...which then cannot be reborrowed here. // But in TB ret is Reserved and thus still writeable. } pub fn main() { foo(&mut (1, 2)); } } mod static_memory_modification { // Copied directly from fail/stacked_borrows/static_memory_modification.rs // Version that fails TB: fail/tree_borrows/static_memory_modification.rs static X: usize = 5; #[allow(mutable_transmutes)] pub fn main() { let x = unsafe { std::mem::transmute::<&usize, &mut usize>(&X) // In SB this mutable reborrow fails. // But in TB we are allowed to transmute as long as we don't write. }; assert_eq!(*&*x, 5); } } // This one is about direct writes to local variables not being in conflict // with interior mutable reborrows. #[allow(unused_assignments)] // spurious warning fn interior_mut_reborrow() { use std::cell::UnsafeCell; let mut c = UnsafeCell::new(42); let ptr = c.get(); // first create interior mutable ptr c = UnsafeCell::new(13); // then write to parent assert_eq!(unsafe { ptr.read() }, 13); // then read through previous ptr } fn main() { fnentry_invalidation::main(); pass_invalid_mut::main(); return_invalid_mut::main(); static_memory_modification::main(); interior_mut_reborrow(); }