about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-05-05 13:49:07 +0200
committerRalf Jung <post@ralfj.de>2025-05-05 13:49:18 +0200
commit3f0d24ad4c82df2bb1fb6d6ffde52d5a701b3316 (patch)
treefc4177786e867165eed6c0ca98af320fa209be1c
parentf8a8bbd4c00f29ba4766edd20199190b2bb9135e (diff)
downloadrust-3f0d24ad4c82df2bb1fb6d6ffde52d5a701b3316.tar.gz
rust-3f0d24ad4c82df2bb1fb6d6ffde52d5a701b3316.zip
move tests that are identical between SB and TB to shared files
-rw-r--r--src/tools/miri/tests/pass/both_borrows/2phase.rs (renamed from src/tools/miri/tests/pass/stacked-borrows/2phase.rs)43
-rw-r--r--src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs272
-rw-r--r--src/tools/miri/tests/pass/both_borrows/interior_mutability.rs (renamed from src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs)35
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs176
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs279
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr1
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs27
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs257
8 files changed, 326 insertions, 764 deletions
diff --git a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs b/src/tools/miri/tests/pass/both_borrows/2phase.rs
index fb4ba605837..c53ae4cbd0e 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs
+++ b/src/tools/miri/tests/pass/both_borrows/2phase.rs
@@ -1,3 +1,6 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+
 // FIXME: this miscompiles with optimizations, see <https://github.com/rust-lang/rust/issues/132898>.
 //@compile-flags: -Zmir-opt-level=0
 
@@ -59,52 +62,12 @@ fn two_phase_overlapping2() {
     x.add_assign(x + *l);
 }
 
-fn with_interior_mutability() {
-    use std::cell::Cell;
-
-    trait Thing: Sized {
-        fn do_the_thing(&mut self, _s: i32) {}
-    }
-
-    impl<T> Thing for Cell<T> {}
-
-    let mut x = Cell::new(1);
-    let l = &x;
-
-    x.do_the_thing({
-        x.set(3);
-        l.set(4);
-        x.get() + l.get()
-    });
-}
-
-// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it.
-// Tree Borrows rejects it.
-fn aliasing_violation() {
-    struct Foo(u64);
-    impl Foo {
-        fn add(&mut self, n: u64) -> u64 {
-            self.0 + n
-        }
-    }
-
-    let mut f = Foo(0);
-    let alias = &mut f.0 as *mut u64;
-    let res = f.add(unsafe {
-        *alias = 42;
-        0
-    });
-    assert_eq!(res, 42);
-}
-
 fn main() {
     two_phase1();
     two_phase2();
     two_phase3(false);
     two_phase3(true);
     two_phase_raw();
-    with_interior_mutability();
     two_phase_overlapping1();
     two_phase_overlapping2();
-    aliasing_violation();
 }
diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
new file mode 100644
index 00000000000..c2b6a7e68be
--- /dev/null
+++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
@@ -0,0 +1,272 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+#![feature(allocator_api)]
+use std::ptr;
+
+// Test various aliasing-model-related things.
+fn main() {
+    read_does_not_invalidate1();
+    read_does_not_invalidate2();
+    mut_raw_then_mut_shr();
+    mut_shr_then_mut_raw();
+    mut_raw_mut();
+    partially_invalidate_mut();
+    drop_after_sharing();
+    // direct_mut_to_const_raw();
+    two_raw();
+    shr_and_raw();
+    disjoint_mutable_subborrows();
+    raw_ref_to_part();
+    array_casts();
+    mut_below_shr();
+    wide_raw_ptr_in_tuple();
+    not_unpin_not_protected();
+    write_does_not_invalidate_all_aliases();
+    box_into_raw_allows_interior_mutable_alias();
+}
+
+// Make sure that reading from an `&mut` does, like reborrowing to `&`,
+// NOT invalidate other reborrows.
+fn read_does_not_invalidate1() {
+    fn foo(x: &mut (i32, i32)) -> &i32 {
+        let xraw = x as *mut (i32, i32);
+        let ret = unsafe { &(*xraw).1 };
+        let _val = x.1; // we just read, this does NOT invalidate the reborrows.
+        ret
+    }
+    assert_eq!(*foo(&mut (1, 2)), 2);
+}
+// Same as above, but this time we first create a raw, then read from `&mut`
+// and then freeze from the raw.
+fn read_does_not_invalidate2() {
+    fn foo(x: &mut (i32, i32)) -> &i32 {
+        let xraw = x as *mut (i32, i32);
+        let _val = x.1; // we just read, this does NOT invalidate the raw reborrow.
+        let ret = unsafe { &(*xraw).1 };
+        ret
+    }
+    assert_eq!(*foo(&mut (1, 2)), 2);
+}
+
+// Escape a mut to raw, then share the same mut and use the share, then the raw.
+// That should work.
+fn mut_raw_then_mut_shr() {
+    let mut x = 2;
+    let xref = &mut x;
+    let xraw = &mut *xref as *mut _;
+    let xshr = &*xref;
+    assert_eq!(*xshr, 2);
+    unsafe {
+        *xraw = 4;
+    }
+    assert_eq!(x, 4);
+}
+
+// Create first a shared reference and then a raw pointer from a `&mut`
+// should permit mutation through that raw pointer.
+fn mut_shr_then_mut_raw() {
+    let xref = &mut 2;
+    let _xshr = &*xref;
+    let xraw = xref as *mut _;
+    unsafe {
+        *xraw = 3;
+    }
+    assert_eq!(*xref, 3);
+}
+
+// Ensure that if we derive from a mut a raw, and then from that a mut,
+// and then read through the original mut, that does not invalidate the raw.
+// This shows that the read-exception for `&mut` applies even if the `Shr` item
+// on the stack is not at the top.
+fn mut_raw_mut() {
+    let mut x = 2;
+    {
+        let xref1 = &mut x;
+        let xraw = xref1 as *mut _;
+        let _xref2 = unsafe { &mut *xraw };
+        let _val = *xref1;
+        unsafe {
+            *xraw = 4;
+        }
+        // we can now use both xraw and xref1, for reading
+        assert_eq!(*xref1, 4);
+        assert_eq!(unsafe { *xraw }, 4);
+        assert_eq!(*xref1, 4);
+        assert_eq!(unsafe { *xraw }, 4);
+        // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs`
+    }
+    assert_eq!(x, 4);
+}
+
+fn partially_invalidate_mut() {
+    let data = &mut (0u8, 0u8);
+    let reborrow = &mut *data as *mut (u8, u8);
+    let shard = unsafe { &mut (*reborrow).0 };
+    data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap.
+    *shard += 1; // so we can still use `shard`.
+    assert_eq!(*data, (1, 1));
+}
+
+// Make sure that we can handle the situation where a location is frozen when being dropped.
+fn drop_after_sharing() {
+    let x = String::from("hello!");
+    let _len = x.len();
+}
+
+// Make sure that we can create two raw pointers from a mutable reference and use them both.
+fn two_raw() {
+    unsafe {
+        let x = &mut 0;
+        let y1 = x as *mut _;
+        let y2 = x as *mut _;
+        *y1 += 2;
+        *y2 += 1;
+    }
+}
+
+// Make sure that creating a *mut does not invalidate existing shared references.
+fn shr_and_raw() {
+    unsafe {
+        use std::mem;
+        let x = &mut 0;
+        let y1: &i32 = mem::transmute(&*x); // launder lifetimes
+        let y2 = x as *mut _;
+        let _val = *y1;
+        *y2 += 1;
+    }
+}
+
+fn disjoint_mutable_subborrows() {
+    struct Foo {
+        a: String,
+        b: Vec<u32>,
+    }
+
+    unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String {
+        &mut (*this).a
+    }
+
+    unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec<u32> {
+        &mut (*this).b
+    }
+
+    let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] };
+
+    let ptr = &mut foo as *mut Foo;
+
+    let a = unsafe { borrow_field_a(ptr) };
+    let b = unsafe { borrow_field_b(ptr) };
+    b.push(4);
+    a.push_str(" world");
+    assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#);
+}
+
+fn raw_ref_to_part() {
+    struct Part {
+        _lame: i32,
+    }
+
+    #[repr(C)]
+    struct Whole {
+        part: Part,
+        extra: i32,
+    }
+
+    let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 });
+    let whole = ptr::addr_of_mut!(*Box::leak(it));
+    let part = unsafe { ptr::addr_of_mut!((*whole).part) };
+    let typed = unsafe { &mut *(part as *mut Whole) };
+    assert!(typed.extra == 42);
+    drop(unsafe { Box::from_raw(whole) });
+}
+
+/// When casting an array reference to a raw element ptr, that should cover the whole array.
+fn array_casts() {
+    let mut x: [usize; 2] = [0, 0];
+    let p = &mut x as *mut usize;
+    unsafe {
+        *p.add(1) = 1;
+    }
+
+    let x: [usize; 2] = [0, 1];
+    let p = &x as *const usize;
+    assert_eq!(unsafe { *p.add(1) }, 1);
+}
+
+/// Transmuting &&i32 to &&mut i32 is fine.
+fn mut_below_shr() {
+    let x = 0;
+    let y = &x;
+    let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) };
+    let r = &**p;
+    let _val = *r;
+}
+
+fn wide_raw_ptr_in_tuple() {
+    let mut x: Box<dyn std::any::Any> = Box::new("ouch");
+    let r = &mut *x as *mut dyn std::any::Any;
+    // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw
+    // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and
+    // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong.
+    let pair = (r, &0);
+    let r = unsafe { &mut *pair.0 };
+    // Make sure the fn ptr part of the vtable is still fine.
+    r.type_id();
+}
+
+fn not_unpin_not_protected() {
+    // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
+    // don't add protectors. (We could, but until we have a better idea for where we want to go with
+    // the self-referential-coroutine situation, it does not seem worth the potential trouble.)
+    use std::marker::PhantomPinned;
+
+    pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned);
+
+    fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
+        // `f` is allowed to deallocate `x`.
+        f(x)
+    }
+
+    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
+        let raw = x as *mut _;
+        drop(unsafe { Box::from_raw(raw) });
+    });
+}
+
+fn write_does_not_invalidate_all_aliases() {
+    mod other {
+        /// Some private memory to store stuff in.
+        static mut S: *mut i32 = 0 as *mut i32;
+
+        pub fn lib1(x: &&mut i32) {
+            unsafe {
+                S = (x as *const &mut i32).cast::<*mut i32>().read();
+            }
+        }
+
+        pub fn lib2() {
+            unsafe {
+                *S = 1337;
+            }
+        }
+    }
+
+    let x = &mut 0;
+    other::lib1(&x);
+    *x = 42; // a write to x -- invalidates other pointers?
+    other::lib2();
+    assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated
+}
+
+fn box_into_raw_allows_interior_mutable_alias() {
+    unsafe {
+        let b = Box::new(std::cell::Cell::new(42));
+        let raw = Box::into_raw(b);
+        let c = &*raw;
+        let d = raw.cast::<i32>(); // bypassing `Cell` -- only okay in Miri tests
+        // `c` and `d` should permit arbitrary aliasing with each other now.
+        *d = 1;
+        c.set(2);
+        drop(Box::from_raw(raw));
+    }
+}
diff --git a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs
index 50d745fa363..f095e215e00 100644
--- a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs
+++ b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs
@@ -1,5 +1,7 @@
-//@compile-flags: -Zmiri-tree-borrows
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
 #![allow(dangerous_implicit_autorefs)]
+
 use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
 use std::mem::{self, MaybeUninit};
 
@@ -14,6 +16,7 @@ fn main() {
     ref_protector();
     ref_mut_protector();
     rust_issue_68303();
+    two_phase();
 }
 
 fn aliasing_mut_and_shr() {
@@ -101,13 +104,15 @@ fn unsafe_cell_invalidate() {
     let raw1 = &mut x as *mut _;
     let ref1 = unsafe { &mut *raw1 };
     let raw2 = ref1 as *mut _;
-    // Now the borrow tree is:
+    // Now the borrow stack is: raw1, ref2, raw2.
+    //
+    // For TB, the tree is
     //
     // Act x
     // Res `- raw1
     // Res    `- ref1, raw2
     //
-    // So using raw1 invalidates raw2.
+    // Either way, using raw1 invalidates raw2.
     f(unsafe { mem::transmute(raw2) }, raw1);
 }
 
@@ -179,3 +184,27 @@ fn rust_issue_68303() {
     assert!(optional.is_some());
     *handle = true;
 }
+
+fn two_phase() {
+    use std::cell::Cell;
+
+    trait Thing: Sized {
+        fn do_the_thing(&mut self, _s: i32) {}
+    }
+
+    impl<T> Thing for Cell<T> {}
+
+    let mut x = Cell::new(1);
+    let l = &x;
+
+    x.do_the_thing({
+        // In TB terms:
+        // Several Foreign accesses (both Reads and Writes) to the location
+        // being reborrowed. Reserved + unprotected + interior mut
+        // makes the pointer immune to everything as long as all accesses
+        // are child accesses to its parent pointer x.
+        x.set(3);
+        l.set(4);
+        x.get() + l.get()
+    });
+}
diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs
deleted file mode 100644
index e86cb3711ac..00000000000
--- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-#![allow(dangerous_implicit_autorefs)]
-
-use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
-use std::mem::{self, MaybeUninit};
-
-fn main() {
-    aliasing_mut_and_shr();
-    aliasing_frz_and_shr();
-    into_interior_mutability();
-    unsafe_cell_2phase();
-    unsafe_cell_deallocate();
-    unsafe_cell_invalidate();
-    refcell_basic();
-    ref_protector();
-    ref_mut_protector();
-    rust_issue_68303();
-}
-
-fn aliasing_mut_and_shr() {
-    fn inner(rc: &RefCell<i32>, aliasing: &mut i32) {
-        *aliasing += 4;
-        let _escape_to_raw = rc as *const _;
-        *aliasing += 4;
-        let _shr = &*rc;
-        *aliasing += 4;
-        // also turning this into a frozen ref now must work
-        let aliasing = &*aliasing;
-        let _val = *aliasing;
-        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
-        let _val = *aliasing;
-        let _shr = &*rc; // this must NOT unfreeze
-        let _val = *aliasing;
-    }
-
-    let rc = RefCell::new(23);
-    let mut bmut = rc.borrow_mut();
-    inner(&rc, &mut *bmut);
-    drop(bmut);
-    assert_eq!(*rc.borrow(), 23 + 12);
-}
-
-fn aliasing_frz_and_shr() {
-    fn inner(rc: &RefCell<i32>, aliasing: &i32) {
-        let _val = *aliasing;
-        let _escape_to_raw = rc as *const _; // this must NOT unfreeze
-        let _val = *aliasing;
-        let _shr = &*rc; // this must NOT unfreeze
-        let _val = *aliasing;
-    }
-
-    let rc = RefCell::new(23);
-    let bshr = rc.borrow();
-    inner(&rc, &*bshr);
-    assert_eq!(*rc.borrow(), 23);
-}
-
-// Getting a pointer into a union with interior mutability used to be tricky
-// business (https://github.com/rust-lang/miri/issues/615), but it should work
-// now.
-fn into_interior_mutability() {
-    let mut x: MaybeUninit<(Cell<u32>, u32)> = MaybeUninit::uninit();
-    x.as_ptr();
-    x.write((Cell::new(0), 1));
-    let ptr = unsafe { x.assume_init_ref() };
-    assert_eq!(ptr.1, 1);
-}
-
-// Two-phase borrows of the pointer returned by UnsafeCell::get() should not
-// invalidate aliases.
-fn unsafe_cell_2phase() {
-    unsafe {
-        let x = &UnsafeCell::new(vec![]);
-        let x2 = &*x;
-        (*x.get()).push(0);
-        let _val = (*x2.get()).get(0);
-    }
-}
-
-/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call.
-/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.)
-fn unsafe_cell_deallocate() {
-    fn f(x: &UnsafeCell<i32>) {
-        let b: Box<i32> = unsafe { Box::from_raw(x as *const _ as *mut i32) };
-        drop(b)
-    }
-
-    let b = Box::new(0i32);
-    f(unsafe { mem::transmute(Box::into_raw(b)) });
-}
-
-/// As a side-effect of the above, we also allow this -- at least for now.
-fn unsafe_cell_invalidate() {
-    fn f(_x: &UnsafeCell<i32>, y: *mut i32) {
-        // Writing to y invalidates x, but that is okay.
-        unsafe {
-            *y += 1;
-        }
-    }
-
-    let mut x = 0i32;
-    let raw1 = &mut x as *mut _;
-    let ref1 = unsafe { &mut *raw1 };
-    let raw2 = ref1 as *mut _;
-    // Now the borrow stack is: raw1, ref2, raw2.
-    // So using raw1 invalidates raw2.
-    f(unsafe { mem::transmute(raw2) }, raw1);
-}
-
-fn refcell_basic() {
-    let c = RefCell::new(42);
-    {
-        let s1 = c.borrow();
-        let _x: i32 = *s1;
-        let s2 = c.borrow();
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-    }
-    {
-        let mut m = c.borrow_mut();
-        let _z: i32 = *m;
-        {
-            let s: &i32 = &*m;
-            let _x = *s;
-        }
-        *m = 23;
-        let _z: i32 = *m;
-    }
-    {
-        let s1 = c.borrow();
-        let _x: i32 = *s1;
-        let s2 = c.borrow();
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-        let _x: i32 = *s1;
-        let _y: i32 = *s2;
-    }
-}
-
-// Adding a Stacked Borrows protector for `Ref` would break this
-fn ref_protector() {
-    fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) {
-        // `r` has a shared reference, it is passed in as argument and hence
-        // a protector is added that marks this memory as read-only for the entire
-        // duration of this function.
-        drop(r);
-        // *oops* here we can mutate that memory.
-        *rc.borrow_mut() = 2;
-    }
-
-    let rc = RefCell::new(0);
-    break_it(&rc, rc.borrow())
-}
-
-fn ref_mut_protector() {
-    fn break_it(rc: &RefCell<i32>, r: RefMut<'_, i32>) {
-        // `r` has a shared reference, it is passed in as argument and hence
-        // a protector is added that marks this memory as inaccessible for the entire
-        // duration of this function
-        drop(r);
-        // *oops* here we can mutate that memory.
-        *rc.borrow_mut() = 2;
-    }
-
-    let rc = RefCell::new(0);
-    break_it(&rc, rc.borrow_mut())
-}
-
-/// Make sure we do not have bad enum layout optimizations.
-fn rust_issue_68303() {
-    let optional = Some(RefCell::new(false));
-    let mut handle = optional.as_ref().unwrap().borrow_mut();
-    assert!(optional.is_some());
-    *handle = true;
-}
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
index 4261f411eea..3620f1536fb 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs
@@ -1,100 +1,9 @@
-#![feature(allocator_api)]
-use std::ptr;
-
-// Test various stacked-borrows-related things.
+// Test various stacked-borrows-specific things
+// (i.e., these do not work the same under TB).
 fn main() {
-    read_does_not_invalidate1();
-    read_does_not_invalidate2();
-    mut_raw_then_mut_shr();
-    mut_shr_then_mut_raw();
-    mut_raw_mut();
     mut_raw_mut2();
-    partially_invalidate_mut();
-    drop_after_sharing();
     // direct_mut_to_const_raw();
-    two_raw();
-    shr_and_raw();
-    disjoint_mutable_subborrows();
-    raw_ref_to_part();
-    array_casts();
-    mut_below_shr();
-    wide_raw_ptr_in_tuple();
-    not_unpin_not_protected();
-    write_does_not_invalidate_all_aliases();
-    box_into_raw_allows_interior_mutable_alias();
-}
-
-// Make sure that reading from an `&mut` does, like reborrowing to `&`,
-// NOT invalidate other reborrows.
-fn read_does_not_invalidate1() {
-    fn foo(x: &mut (i32, i32)) -> &i32 {
-        let xraw = x as *mut (i32, i32);
-        let ret = unsafe { &(*xraw).1 };
-        let _val = x.1; // we just read, this does NOT invalidate the reborrows.
-        ret
-    }
-    assert_eq!(*foo(&mut (1, 2)), 2);
-}
-// Same as above, but this time we first create a raw, then read from `&mut`
-// and then freeze from the raw.
-fn read_does_not_invalidate2() {
-    fn foo(x: &mut (i32, i32)) -> &i32 {
-        let xraw = x as *mut (i32, i32);
-        let _val = x.1; // we just read, this does NOT invalidate the raw reborrow.
-        let ret = unsafe { &(*xraw).1 };
-        ret
-    }
-    assert_eq!(*foo(&mut (1, 2)), 2);
-}
-
-// Escape a mut to raw, then share the same mut and use the share, then the raw.
-// That should work.
-fn mut_raw_then_mut_shr() {
-    let mut x = 2;
-    let xref = &mut x;
-    let xraw = &mut *xref as *mut _;
-    let xshr = &*xref;
-    assert_eq!(*xshr, 2);
-    unsafe {
-        *xraw = 4;
-    }
-    assert_eq!(x, 4);
-}
-
-// Create first a shared reference and then a raw pointer from a `&mut`
-// should permit mutation through that raw pointer.
-fn mut_shr_then_mut_raw() {
-    let xref = &mut 2;
-    let _xshr = &*xref;
-    let xraw = xref as *mut _;
-    unsafe {
-        *xraw = 3;
-    }
-    assert_eq!(*xref, 3);
-}
-
-// Ensure that if we derive from a mut a raw, and then from that a mut,
-// and then read through the original mut, that does not invalidate the raw.
-// This shows that the read-exception for `&mut` applies even if the `Shr` item
-// on the stack is not at the top.
-fn mut_raw_mut() {
-    let mut x = 2;
-    {
-        let xref1 = &mut x;
-        let xraw = xref1 as *mut _;
-        let _xref2 = unsafe { &mut *xraw };
-        let _val = *xref1;
-        unsafe {
-            *xraw = 4;
-        }
-        // we can now use both xraw and xref1, for reading
-        assert_eq!(*xref1, 4);
-        assert_eq!(unsafe { *xraw }, 4);
-        assert_eq!(*xref1, 4);
-        assert_eq!(unsafe { *xraw }, 4);
-        // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs`
-    }
-    assert_eq!(x, 4);
+    two_phase_aliasing_violation();
 }
 
 // A variant of `mut_raw_mut` that does *not* get accepted by Tree Borrows.
@@ -109,21 +18,6 @@ fn mut_raw_mut2() {
     }
 }
 
-fn partially_invalidate_mut() {
-    let data = &mut (0u8, 0u8);
-    let reborrow = &mut *data as *mut (u8, u8);
-    let shard = unsafe { &mut (*reborrow).0 };
-    data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap.
-    *shard += 1; // so we can still use `shard`.
-    assert_eq!(*data, (1, 1));
-}
-
-// Make sure that we can handle the situation where a location is frozen when being dropped.
-fn drop_after_sharing() {
-    let x = String::from("hello!");
-    let _len = x.len();
-}
-
 // Make sure that coercing &mut T to *const T produces a writeable pointer.
 // TODO: This is currently disabled, waiting on a decision on <https://github.com/rust-lang/rust/issues/56604>
 /*fn direct_mut_to_const_raw() {
@@ -133,160 +27,21 @@ fn drop_after_sharing() {
     assert_eq!(*x, 1);
 }*/
 
-// Make sure that we can create two raw pointers from a mutable reference and use them both.
-fn two_raw() {
-    unsafe {
-        let x = &mut 0;
-        let y1 = x as *mut _;
-        let y2 = x as *mut _;
-        *y1 += 2;
-        *y2 += 1;
-    }
-}
-
-// Make sure that creating a *mut does not invalidate existing shared references.
-fn shr_and_raw() {
-    unsafe {
-        use std::mem;
-        let x = &mut 0;
-        let y1: &i32 = mem::transmute(&*x); // launder lifetimes
-        let y2 = x as *mut _;
-        let _val = *y1;
-        *y2 += 1;
-    }
-}
-
-fn disjoint_mutable_subborrows() {
-    struct Foo {
-        a: String,
-        b: Vec<u32>,
-    }
-
-    unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String {
-        &mut (*this).a
-    }
-
-    unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec<u32> {
-        &mut (*this).b
-    }
-
-    let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] };
-
-    let ptr = &mut foo as *mut Foo;
-
-    let a = unsafe { borrow_field_a(ptr) };
-    let b = unsafe { borrow_field_b(ptr) };
-    b.push(4);
-    a.push_str(" world");
-    eprintln!("{:?} {:?}", a, b);
-}
-
-fn raw_ref_to_part() {
-    struct Part {
-        _lame: i32,
-    }
-
-    #[repr(C)]
-    struct Whole {
-        part: Part,
-        extra: i32,
-    }
-
-    let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 });
-    let whole = ptr::addr_of_mut!(*Box::leak(it));
-    let part = unsafe { ptr::addr_of_mut!((*whole).part) };
-    let typed = unsafe { &mut *(part as *mut Whole) };
-    assert!(typed.extra == 42);
-    drop(unsafe { Box::from_raw(whole) });
-}
-
-/// When casting an array reference to a raw element ptr, that should cover the whole array.
-fn array_casts() {
-    let mut x: [usize; 2] = [0, 0];
-    let p = &mut x as *mut usize;
-    unsafe {
-        *p.add(1) = 1;
-    }
-
-    let x: [usize; 2] = [0, 1];
-    let p = &x as *const usize;
-    assert_eq!(unsafe { *p.add(1) }, 1);
-}
-
-/// Transmuting &&i32 to &&mut i32 is fine.
-fn mut_below_shr() {
-    let x = 0;
-    let y = &x;
-    let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) };
-    let r = &**p;
-    let _val = *r;
-}
-
-fn wide_raw_ptr_in_tuple() {
-    let mut x: Box<dyn std::any::Any> = Box::new("ouch");
-    let r = &mut *x as *mut dyn std::any::Any;
-    // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw
-    // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and
-    // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong.
-    let pair = (r, &0);
-    let r = unsafe { &mut *pair.0 };
-    // Make sure the fn ptr part of the vtable is still fine.
-    r.type_id();
-}
-
-fn not_unpin_not_protected() {
-    // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
-    // don't add protectors. (We could, but until we have a better idea for where we want to go with
-    // the self-referential-coroutine situation, it does not seem worth the potential trouble.)
-    use std::marker::PhantomPinned;
-
-    pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned);
-
-    fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
-        // `f` may mutate, but it may not deallocate!
-        f(x)
-    }
-
-    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
-        let raw = x as *mut _;
-        drop(unsafe { Box::from_raw(raw) });
-    });
-}
-
-fn write_does_not_invalidate_all_aliases() {
-    mod other {
-        /// Some private memory to store stuff in.
-        static mut S: *mut i32 = 0 as *mut i32;
-
-        pub fn lib1(x: &&mut i32) {
-            unsafe {
-                S = (x as *const &mut i32).cast::<*mut i32>().read();
-            }
-        }
-
-        pub fn lib2() {
-            unsafe {
-                *S = 1337;
-            }
+// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it.
+// Tree Borrows rejects it.
+fn two_phase_aliasing_violation() {
+    struct Foo(u64);
+    impl Foo {
+        fn add(&mut self, n: u64) -> u64 {
+            self.0 + n
         }
     }
 
-    let x = &mut 0;
-    other::lib1(&x);
-    *x = 42; // a write to x -- invalidates other pointers?
-    other::lib2();
-    assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated
-}
-
-fn box_into_raw_allows_interior_mutable_alias() {
-    unsafe {
-        let b = Box::new(std::cell::Cell::new(42));
-        let raw = Box::into_raw(b);
-        let c = &*raw;
-        let d = raw.cast::<i32>(); // bypassing `Cell` -- only okay in Miri tests
-        // `c` and `d` should permit arbitrary aliasing with each other now.
-        *d = 1;
-        c.set(2);
-        drop(Box::from_raw(raw));
-    }
+    let mut f = Foo(0);
+    let alias = &mut f.0 as *mut u64;
+    let res = f.add(unsafe {
+        *alias = 42;
+        0
+    });
+    assert_eq!(res, 42);
 }
diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr
deleted file mode 100644
index 8ee4e25dbef..00000000000
--- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr
+++ /dev/null
@@ -1 +0,0 @@
-"hello world" [0, 1, 2, 4]
diff --git a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs b/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs
deleted file mode 100644
index af52f53791a..00000000000
--- a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@compile-flags: -Zmiri-tree-borrows
-
-// Counterpart to tests/fail/tree-borrows/write-during-2phase.rs,
-// this is the opposite situation: the Write is not problematic because
-// the Protector has not yet been added and the Reserved has interior
-// mutability.
-use core::cell::Cell;
-
-trait Thing: Sized {
-    fn do_the_thing(&mut self, _s: i32) {}
-}
-impl<T> Thing for Cell<T> {}
-
-fn main() {
-    let mut x = Cell::new(1);
-    let l = &x;
-
-    x.do_the_thing({
-        // Several Foreign accesses (both Reads and Writes) to the location
-        // being reborrowed. Reserved + unprotected + interior mut
-        // makes the pointer immune to everything as long as all accesses
-        // are child accesses to its parent pointer x.
-        x.set(3);
-        l.set(4);
-        x.get() + l.get()
-    });
-}
diff --git a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
index eddcb7b1218..87eb447049d 100644
--- a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
+++ b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs
@@ -3,6 +3,8 @@
 
 use std::{mem, ptr};
 
+// Test various tree-borrows-specific things
+// (i.e., these do not work the same under SB).
 fn main() {
     aliasing_read_only_mutable_refs();
     string_as_mut_ptr();
@@ -10,24 +12,6 @@ fn main() {
     direct_mut_to_const_raw();
     local_addr_of_mut();
     returned_mut_is_usable();
-
-    // Stacked Borrows tests
-    read_does_not_invalidate1();
-    read_does_not_invalidate2();
-    mut_raw_then_mut_shr();
-    mut_shr_then_mut_raw();
-    mut_raw_mut();
-    partially_invalidate_mut();
-    drop_after_sharing();
-    two_raw();
-    shr_and_raw();
-    disjoint_mutable_subborrows();
-    raw_ref_to_part();
-    array_casts();
-    mut_below_shr();
-    wide_raw_ptr_in_tuple();
-    not_unpin_not_protected();
-    write_does_not_invalidate_all_aliases();
 }
 
 #[allow(unused_assignments)]
@@ -109,96 +93,6 @@ fn returned_mut_is_usable() {
     *y = 1;
 }
 
-// ----- The tests below were taken from Stacked Borrows ----
-
-// Make sure that reading from an `&mut` does, like reborrowing to `&`,
-// NOT invalidate other reborrows.
-fn read_does_not_invalidate1() {
-    fn foo(x: &mut (i32, i32)) -> &i32 {
-        let xraw = x as *mut (i32, i32);
-        let ret = unsafe { &(*xraw).1 };
-        let _val = x.1; // we just read, this does NOT invalidate the reborrows.
-        ret
-    }
-    assert_eq!(*foo(&mut (1, 2)), 2);
-}
-// Same as above, but this time we first create a raw, then read from `&mut`
-// and then freeze from the raw.
-fn read_does_not_invalidate2() {
-    fn foo(x: &mut (i32, i32)) -> &i32 {
-        let xraw = x as *mut (i32, i32);
-        let _val = x.1; // we just read, this does NOT invalidate the raw reborrow.
-        let ret = unsafe { &(*xraw).1 };
-        ret
-    }
-    assert_eq!(*foo(&mut (1, 2)), 2);
-}
-
-// Escape a mut to raw, then share the same mut and use the share, then the raw.
-// That should work.
-fn mut_raw_then_mut_shr() {
-    let mut x = 2;
-    let xref = &mut x;
-    let xraw = &mut *xref as *mut _;
-    let xshr = &*xref;
-    assert_eq!(*xshr, 2);
-    unsafe {
-        *xraw = 4;
-    }
-    assert_eq!(x, 4);
-}
-
-// Create first a shared reference and then a raw pointer from a `&mut`
-// should permit mutation through that raw pointer.
-fn mut_shr_then_mut_raw() {
-    let xref = &mut 2;
-    let _xshr = &*xref;
-    let xraw = xref as *mut _;
-    unsafe {
-        *xraw = 3;
-    }
-    assert_eq!(*xref, 3);
-}
-
-// Ensure that if we derive from a mut a raw, and then from that a mut,
-// and then read through the original mut, that does not invalidate the raw.
-// This shows that the read-exception for `&mut` applies even if the `Shr` item
-// on the stack is not at the top.
-fn mut_raw_mut() {
-    let mut x = 2;
-    {
-        let xref1 = &mut x;
-        let xraw = xref1 as *mut _;
-        let _xref2 = unsafe { &mut *xraw };
-        let _val = *xref1;
-        unsafe {
-            *xraw = 4;
-        }
-        // we can now use both xraw and xref1, for reading
-        assert_eq!(*xref1, 4);
-        assert_eq!(unsafe { *xraw }, 4);
-        assert_eq!(*xref1, 4);
-        assert_eq!(unsafe { *xraw }, 4);
-        // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs`
-    }
-    assert_eq!(x, 4);
-}
-
-fn partially_invalidate_mut() {
-    let data = &mut (0u8, 0u8);
-    let reborrow = &mut *data as *mut (u8, u8);
-    let shard = unsafe { &mut (*reborrow).0 };
-    data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap.
-    *shard += 1; // so we can still use `shard`.
-    assert_eq!(*data, (1, 1));
-}
-
-// Make sure that we can handle the situation where a location is frozen when being dropped.
-fn drop_after_sharing() {
-    let x = String::from("hello!");
-    let _len = x.len();
-}
-
 // Make sure that coercing &mut T to *const T produces a writeable pointer.
 fn direct_mut_to_const_raw() {
     let x = &mut 0;
@@ -208,150 +102,3 @@ fn direct_mut_to_const_raw() {
     }
     assert_eq!(*x, 1);
 }
-
-// Make sure that we can create two raw pointers from a mutable reference and use them both.
-fn two_raw() {
-    unsafe {
-        let x = &mut 0;
-        let y1 = x as *mut _;
-        let y2 = x as *mut _;
-        *y1 += 2;
-        *y2 += 1;
-    }
-}
-
-// Make sure that creating a *mut does not invalidate existing shared references.
-fn shr_and_raw() {
-    unsafe {
-        let x = &mut 0;
-        let y1: &i32 = mem::transmute(&*x); // launder lifetimes
-        let y2 = x as *mut _;
-        let _val = *y1;
-        *y2 += 1;
-    }
-}
-
-fn disjoint_mutable_subborrows() {
-    struct Foo {
-        a: String,
-        b: Vec<u32>,
-    }
-
-    unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String {
-        &mut (*this).a
-    }
-
-    unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec<u32> {
-        &mut (*this).b
-    }
-
-    let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] };
-
-    let ptr = &mut foo as *mut Foo;
-
-    let a = unsafe { borrow_field_a(ptr) };
-    let b = unsafe { borrow_field_b(ptr) };
-    b.push(4);
-    a.push_str(" world");
-    assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#);
-}
-
-fn raw_ref_to_part() {
-    struct Part {
-        _lame: i32,
-    }
-
-    #[repr(C)]
-    struct Whole {
-        part: Part,
-        extra: i32,
-    }
-
-    let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 });
-    let whole = ptr::addr_of_mut!(*Box::leak(it));
-    let part = unsafe { ptr::addr_of_mut!((*whole).part) };
-    let typed = unsafe { &mut *(part as *mut Whole) };
-    assert!(typed.extra == 42);
-    drop(unsafe { Box::from_raw(whole) });
-}
-
-/// When casting an array reference to a raw element ptr, that should cover the whole array.
-fn array_casts() {
-    let mut x: [usize; 2] = [0, 0];
-    let p = &mut x as *mut usize;
-    unsafe {
-        *p.add(1) = 1;
-    }
-
-    let x: [usize; 2] = [0, 1];
-    let p = &x as *const usize;
-    assert_eq!(unsafe { *p.add(1) }, 1);
-}
-
-/// Transmuting &&i32 to &&mut i32 is fine.
-fn mut_below_shr() {
-    let x = 0;
-    let y = &x;
-    let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) };
-    let r = &**p;
-    let _val = *r;
-}
-
-fn wide_raw_ptr_in_tuple() {
-    let mut x: Box<dyn std::any::Any> = Box::new("ouch");
-    let r = &mut *x as *mut dyn std::any::Any;
-    // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw
-    // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and
-    // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong.
-    let pair = (r, &0);
-    let r = unsafe { &mut *pair.0 };
-    // Make sure the fn ptr part of the vtable is still fine.
-    r.type_id();
-}
-
-fn not_unpin_not_protected() {
-    // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also
-    // don't add protectors. (We could, but until we have a better idea for where we want to go with
-    // the self-referential-coroutine situation, it does not seem worth the potential trouble.)
-    use std::marker::PhantomPinned;
-
-    pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned);
-
-    fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) {
-        // `f` is allowed to deallocate `x`.
-        f(x)
-    }
-
-    inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| {
-        let raw = x as *mut _;
-        drop(unsafe { Box::from_raw(raw) });
-    });
-}
-
-fn write_does_not_invalidate_all_aliases() {
-    // In TB there are other ways to do that (`addr_of!(*x)` has the same tag as `x`),
-    // but let's still make sure this SB test keeps working.
-
-    mod other {
-        /// Some private memory to store stuff in.
-        static mut S: *mut i32 = 0 as *mut i32;
-
-        pub fn lib1(x: &&mut i32) {
-            unsafe {
-                S = (x as *const &mut i32).cast::<*mut i32>().read();
-            }
-        }
-
-        pub fn lib2() {
-            unsafe {
-                *S = 1337;
-            }
-        }
-    }
-
-    let x = &mut 0;
-    other::lib1(&x);
-    *x = 42; // a write to x -- invalidates other pointers?
-    other::lib2();
-    assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated
-}