diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 0efe87a2d5368..d6906702ec861 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -27,6 +27,7 @@ where I: [const] SliceIndex<[T]>, { #[inline(always)] + #[rustc_no_writable] fn index_mut(&mut self, index: I) -> &mut I::Output { index.index_mut(self) } @@ -225,6 +226,7 @@ unsafe impl const SliceIndex<[T]> for usize { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { if self < slice.len() { // SAFETY: `self` is checked to be in bounds. @@ -273,6 +275,7 @@ unsafe impl const SliceIndex<[T]> for usize { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut T { // N.B., use intrinsic indexing &mut (*slice)[self] @@ -296,6 +299,7 @@ unsafe impl const SliceIndex<[T]> for ops::IndexRange { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. @@ -344,6 +348,7 @@ unsafe impl const SliceIndex<[T]> for ops::IndexRange { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. @@ -376,6 +381,7 @@ unsafe impl const SliceIndex<[T]> for ops::Range { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { if let Some(new_len) = usize::checked_sub(self.end, self.start) && self.end <= slice.len() @@ -445,6 +451,7 @@ unsafe impl const SliceIndex<[T]> for ops::Range { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { // Using checked_sub is a safe way to get `SubUnchecked` in MIR if let Some(new_len) = usize::checked_sub(self.end, self.start) @@ -469,6 +476,7 @@ unsafe impl const SliceIndex<[T]> for range::Range { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { ops::Range::from(self).get_mut(slice) } @@ -491,6 +499,7 @@ unsafe impl const SliceIndex<[T]> for range::Range { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { ops::Range::from(self).index_mut(slice) } @@ -508,6 +517,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeTo { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { (0..self.end).get_mut(slice) } @@ -530,6 +540,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeTo { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { (0..self.end).index_mut(slice) } @@ -547,6 +558,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeFrom { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { (self.start..slice.len()).get_mut(slice) } @@ -576,6 +588,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeFrom { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { if self.start > slice.len() { slice_index_fail(self.start, slice.len(), slice.len()) @@ -599,6 +612,7 @@ unsafe impl const SliceIndex<[T]> for range::RangeFrom { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { ops::RangeFrom::from(self).get_mut(slice) } @@ -621,6 +635,7 @@ unsafe impl const SliceIndex<[T]> for range::RangeFrom { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { ops::RangeFrom::from(self).index_mut(slice) } @@ -637,6 +652,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeFull { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { Some(slice) } @@ -657,6 +673,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeFull { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { slice } @@ -676,6 +693,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeInclusive { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { if *self.end() >= slice.len() { None } else { self.into_slice_range().get_mut(slice) } } @@ -708,6 +726,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeInclusive { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { let Self { mut start, mut end, exhausted } = self; let len = slice.len(); @@ -734,6 +753,7 @@ unsafe impl const SliceIndex<[T]> for range::RangeInclusive { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { ops::RangeInclusive::from(self).get_mut(slice) } @@ -756,6 +776,7 @@ unsafe impl const SliceIndex<[T]> for range::RangeInclusive { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { ops::RangeInclusive::from(self).index_mut(slice) } @@ -773,6 +794,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { (0..=self.end).get_mut(slice) } @@ -795,6 +817,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { (0..=self.end).index_mut(slice) } @@ -812,6 +835,7 @@ unsafe impl const SliceIndex<[T]> for range::RangeToInclusive { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { (0..=self.last).get_mut(slice) } @@ -834,6 +858,7 @@ unsafe impl const SliceIndex<[T]> for range::RangeToInclusive { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut [T] { (0..=self.last).index_mut(slice) } @@ -1047,6 +1072,7 @@ unsafe impl SliceIndex<[T]> for (ops::Bound, ops::Bound) { } #[inline] + #[rustc_no_writable] fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { try_into_slice_range(slice.len(), self)?.get_mut(slice) } @@ -1069,6 +1095,7 @@ unsafe impl SliceIndex<[T]> for (ops::Bound, ops::Bound) { } #[inline] + #[rustc_no_writable] fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { into_slice_range(slice.len(), self).index_mut(slice) } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index a838ba009b484..41c49b11e0b03 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -596,6 +596,7 @@ impl [T] { #[inline] #[must_use] #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where I: [const] SliceIndex, @@ -681,6 +682,7 @@ impl [T] { #[must_use] #[track_caller] #[rustc_const_unstable(feature = "const_index", issue = "143775")] + #[rustc_no_writable] pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where I: [const] SliceIndex, diff --git a/src/tools/miri/tests/pass/tree_borrows/slice_get_mut_no_implicit_write.rs b/src/tools/miri/tests/pass/tree_borrows/slice_get_mut_no_implicit_write.rs new file mode 100644 index 0000000000000..789f0a8b88ce6 --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/slice_get_mut_no_implicit_write.rs @@ -0,0 +1,48 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes + +// This test reproduces the pattern used by `BorrowedCursor::as_mut`, which appears in `Socket::recv_with_flags` and `std::fs::read`. +// Many crates depend on similar patterns. Before https://github.com/rust-lang/rust/pull/157202 this failed under Tree +// Borrows with Implicit Writes. With the attribute `#[rustc_no_writable]` added to +// `slice::get_unchecked_mut`, both this test and the affected crates work. +fn borrowed_buf() { + struct BorrowedBuf<'a> { + buf: &'a mut [u8], + } + + impl<'a> BorrowedBuf<'a> { + fn capacity(&self) -> usize { + self.buf.len() + } + + unsafe fn as_mut(&mut self) -> &mut [u8] { + unsafe { self.buf.get_unchecked_mut(..) } + } + } + + let mut arr = [0u8; 4]; + let mut buf = BorrowedBuf { buf: &mut arr }; + + let ptr = unsafe { buf.as_mut() }.as_mut_ptr(); + let _ = buf.capacity(); + unsafe { + ptr.write(42); + } +} + +// A variant of the above that uses `index_mut` notation. +fn index_mut() { + fn dostuff(x: &mut [u8]) { + unsafe { + let ptr = (&mut x[..]).as_mut_ptr(); + let _len = x.len(); + ptr.write(99); + } + } + + dostuff(&mut [1, 2, 3, 4]); +} + +fn main() { + borrowed_buf(); + index_mut(); +}