blob: 7da20e76229dbc091823432ae631995d9338e003 [file] [log] [blame] [edit]
//@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();
}