From 9d29793614cc810fb8febf7f1a2e0202f3919bb6 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Sun, 17 Jan 2021 23:12:29 -0500 Subject: Improve design of `assert_len` --- library/alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/string.rs | 4 ++-- library/alloc/src/vec/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'library/alloc') diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index eb899468193..0c267cbc106 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = range.assert_len(self.len()); + let Range { start, end } = range.ensure_subset_of(..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 99c42a4ba44..71b4883aca2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,7 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_bounds_assert_len)] +#![feature(range_bounds_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3218b3535c9..3ab5ca4f566 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1510,14 +1510,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = range.assert_len(self.len()); + let Range { start, end } = range.ensure_subset_of(..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `ensure_subset_of` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b40c1a8c57a..5c20f382224 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = range.assert_len(len); + let Range { start, end } = range.ensure_subset_of(..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked -- cgit 1.4.1-3-g733a5 From cb647f3e8e32180cde0f0e7a2599a5dc5b35345a Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 18 Jan 2021 09:22:17 -0500 Subject: Fix possible soundness issue in `ensure_subset_of` --- library/alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/string.rs | 2 +- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 192 +++++++++++---------- library/core/src/slice/mod.rs | 2 +- .../range-bounds-ensure-subset-of.md | 10 -- .../src/library-features/range-ensure-subset-of.md | 10 ++ 8 files changed, 112 insertions(+), 110 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md create mode 100644 src/doc/unstable-book/src/library-features/range-ensure-subset-of.md (limited to 'library/alloc') diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 0c267cbc106..319ca666fc6 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = range.ensure_subset_of(..self.len()); + let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 71b4883aca2..ade2e3fed2c 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,7 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_bounds_ensure_subset_of)] +#![feature(range_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3ab5ca4f566..ef2f264ec7e 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1510,7 +1510,7 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = range.ensure_subset_of(..self.len()); + let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 5c20f382224..1a7b846bd85 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = range.ensure_subset_of(..len); + let Range { start, end } = Range::ensure_subset_of(range, ..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 7a0dd5a8f0f..b30ff9450ff 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -151,6 +151,103 @@ impl> Range { } } +impl Range { + /// Performs bounds-checking of a range. + /// + /// This method is similar to [`Index::index`] for slices, but it returns a + /// `Range` equivalent to `range`. You can use this method to turn any range + /// into `start` and `end` values. + /// + /// `bounds` is the range of the slice to use for bounds-checking. It should + /// be a [`RangeTo`] range that ends at the length of the slice. + /// + /// The returned `Range` is safe to pass to [`slice::get_unchecked`] and + /// [`slice::get_unchecked_mut`] for slices with the given range. + /// + /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked + /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut + /// + /// # Panics + /// + /// Panics if `range` would be out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// let v = [10, 40, 30]; + /// assert_eq!(1..2, Range::ensure_subset_of(1..2, ..v.len())); + /// assert_eq!(0..2, Range::ensure_subset_of(..2, ..v.len())); + /// assert_eq!(1..3, Range::ensure_subset_of(1.., ..v.len())); + /// ``` + /// + /// Panics when [`Index::index`] would panic: + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(2..1, ..3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(1..4, ..3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(1..=usize::MAX, ..3); + /// ``` + /// + /// [`Index::index`]: crate::ops::Index::index + #[track_caller] + #[unstable(feature = "range_ensure_subset_of", issue = "76393")] + pub fn ensure_subset_of(range: R, bounds: RangeTo) -> Self + where + R: RangeBounds, + { + let len = bounds.end; + + let start: Bound<&usize> = range.start_bound(); + let start = match start { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end: Bound<&usize> = range.end_bound(); + let end = match end { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Self { start, end } + } +} + /// A range only bounded inclusively below (`start..`). /// /// The `RangeFrom` `start..` contains all values with `x >= start`. @@ -764,101 +861,6 @@ pub trait RangeBounds { #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; - /// Performs bounds-checking of this range. - /// - /// This method is similar to [`Index::index`] for slices, but it returns a - /// [`Range`] equivalent to this range. You can use this method to turn any - /// range into `start` and `end` values. - /// - /// The given range is the range of the slice to use for bounds-checking. It - /// should be a [`RangeTo`] range that ends at the length of the slice. - /// - /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices with the given range. - /// - /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked - /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if the range would be out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, (1..2).ensure_subset_of(..v.len())); - /// assert_eq!(0..2, (..2).ensure_subset_of(..v.len())); - /// assert_eq!(1..3, (1..).ensure_subset_of(..v.len())); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (2..1).ensure_subset_of(..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (1..4).ensure_subset_of(..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (1..=usize::MAX).ensure_subset_of(..3); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "range_bounds_ensure_subset_of", issue = "76393")] - fn ensure_subset_of(self, range: RangeTo) -> Range - where - Self: RangeBounds, - { - let len = range.end; - - let start: Bound<&usize> = self.start_bound(); - let start = match start { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end: Bound<&usize> = self.end_bound(); - let end = match end { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Range { start, end } - } - /// Returns `true` if `item` is contained in the range. /// /// # Examples diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 90351be6929..e78b6476511 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3052,7 +3052,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = src.ensure_subset_of(..self.len()); + let Range { start: src_start, end: src_end } = Range::ensure_subset_of(src, ..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md deleted file mode 100644 index ea3f01ff5f9..00000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_bounds_ensure_subset_of` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`RangeBounds::ensure_subset_of`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`RangeBounds::ensure_subset_of`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.ensure_subset_of diff --git a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md new file mode 100644 index 00000000000..8b5a21a34cf --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md @@ -0,0 +1,10 @@ +# `range_ensure_subset_of` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`Range::ensure_subset_of`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`Range::ensure_subset_of`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.ensure_subset_of -- cgit 1.4.1-3-g733a5 From 5d519eaa6e9a583257b2f9e28a743ab85d1cabc5 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 1 Feb 2021 21:20:44 -0500 Subject: Rename `Range::ensure_subset_of` to `slice::range` --- library/alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/slice.rs | 2 + library/alloc/src/string.rs | 5 +- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 101 ------------------------ library/core/src/slice/index.rs | 105 ++++++++++++++++++++++++- library/core/src/slice/mod.rs | 8 +- 8 files changed, 115 insertions(+), 112 deletions(-) (limited to 'library/alloc') diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 319ca666fc6..f7cefdce278 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); + let Range { start, end } = slice::range(range, ..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ade2e3fed2c..c020a969f1f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,6 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] @@ -123,6 +122,7 @@ #![feature(set_ptr_value)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] +#![feature(slice_range)] #![feature(staged_api)] #![feature(str_internals)] #![feature(trusted_len)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index cb015b94930..c5ffade1261 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -92,6 +92,8 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; +#[unstable(feature = "slice_range", issue = "76393")] +pub use core::slice::range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ef2f264ec7e..b4deedc5263 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; +use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1510,14 +1511,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); + let Range { start, end } = slice::range(range, ..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `ensure_subset_of` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1a7b846bd85..a8474f8ca59 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = Range::ensure_subset_of(range, ..len); + let Range { start, end } = slice::range(range, ..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index b30ff9450ff..dbeb3912130 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1,9 +1,5 @@ use crate::fmt; use crate::hash::Hash; -use crate::slice::index::{ - slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail, - slice_start_index_overflow_fail, -}; /// An unbounded range (`..`). /// @@ -151,103 +147,6 @@ impl> Range { } } -impl Range { - /// Performs bounds-checking of a range. - /// - /// This method is similar to [`Index::index`] for slices, but it returns a - /// `Range` equivalent to `range`. You can use this method to turn any range - /// into `start` and `end` values. - /// - /// `bounds` is the range of the slice to use for bounds-checking. It should - /// be a [`RangeTo`] range that ends at the length of the slice. - /// - /// The returned `Range` is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices with the given range. - /// - /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked - /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if `range` would be out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, Range::ensure_subset_of(1..2, ..v.len())); - /// assert_eq!(0..2, Range::ensure_subset_of(..2, ..v.len())); - /// assert_eq!(1..3, Range::ensure_subset_of(1.., ..v.len())); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(2..1, ..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(1..4, ..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(1..=usize::MAX, ..3); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "range_ensure_subset_of", issue = "76393")] - pub fn ensure_subset_of(range: R, bounds: RangeTo) -> Self - where - R: RangeBounds, - { - let len = bounds.end; - - let start: Bound<&usize> = range.start_bound(); - let start = match start { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end: Bound<&usize> = range.end_bound(); - let end = match end { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Self { start, end } - } -} - /// A range only bounded inclusively below (`start..`). /// /// The `RangeFrom` `start..` contains all values with `x >= start`. diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 660c8a2da5d..d20986bb724 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -37,28 +37,28 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! { #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { +fn slice_end_index_len_fail(index: usize, len: usize) -> ! { panic!("range end index {} out of range for slice of length {}", index, len); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! { +fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_start_index_overflow_fail() -> ! { +fn slice_start_index_overflow_fail() -> ! { panic!("attempted to index slice from after maximum usize"); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_overflow_fail() -> ! { +fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } @@ -449,3 +449,100 @@ unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { (0..=self.end).index_mut(slice) } } + +/// Performs bounds-checking of a range. +/// +/// This method is similar to [`Index::index`] for slices, but it returns a +/// [`Range`] equivalent to `range`. You can use this method to turn any range +/// into `start` and `end` values. +/// +/// `bounds` is the range of the slice to use for bounds-checking. It should +/// be a [`RangeTo`] range that ends at the length of the slice. +/// +/// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and +/// [`slice::get_unchecked_mut`] for slices with the given range. +/// +/// [`Range`]: ops::Range +/// [`RangeTo`]: ops::RangeTo +/// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked +/// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut +/// +/// # Panics +/// +/// Panics if `range` would be out of bounds. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(1..2, slice::range(1..2, ..v.len())); +/// assert_eq!(0..2, slice::range(..2, ..v.len())); +/// assert_eq!(1..3, slice::range(1.., ..v.len())); +/// ``` +/// +/// Panics when [`Index::index`] would panic: +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(2..1, ..3); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(1..4, ..3); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(1..=usize::MAX, ..3); +/// ``` +/// +/// [`Index::index`]: ops::Index::index +#[track_caller] +#[unstable(feature = "slice_range", issue = "76393")] +pub fn range(range: R, bounds: ops::RangeTo) -> ops::Range +where + R: ops::RangeBounds, +{ + let len = bounds.end; + + let start: ops::Bound<&usize> = range.start_bound(); + let start = match start { + ops::Bound::Included(&start) => start, + ops::Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + ops::Bound::Unbounded => 0, + }; + + let end: ops::Bound<&usize> = range.end_bound(); + let end = match end { + ops::Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + ops::Bound::Excluded(&end) => end, + ops::Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + ops::Range { start, end } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e78b6476511..8256d2cc607 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -18,6 +18,7 @@ use crate::option::Option::{None, Some}; use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; +use crate::slice; #[unstable( feature = "slice_internals", @@ -29,7 +30,7 @@ pub mod memchr; mod ascii; mod cmp; -pub(crate) mod index; +mod index; mod iter; mod raw; mod rotate; @@ -76,6 +77,9 @@ pub use sort::heapsort; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; +#[unstable(feature = "slice_range", issue = "76393")] +pub use index::range; + #[lang = "slice"] #[cfg(not(test))] impl [T] { @@ -3052,7 +3056,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = Range::ensure_subset_of(src, ..self.len()); + let Range { start: src_start, end: src_end } = slice::range(src, ..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, -- cgit 1.4.1-3-g733a5 From fe4fe19ddc38a2da883e1e38d18c821ad1c26fc5 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Fri, 12 Feb 2021 22:03:39 -0500 Subject: Update new usage of `assert_len` --- library/alloc/src/vec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'library/alloc') diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a8474f8ca59..77302d33bc1 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2036,11 +2036,11 @@ impl Vec { where R: RangeBounds, { - let range = src.assert_len(self.len()); + let range = slice::range(src, ..self.len()); self.reserve(range.len()); // SAFETY: - // - `assert_len` guarantees that the given range is valid for indexing self + // - `slice::range` guarantees that the given range is valid for indexing self unsafe { self.spec_extend_from_within(range); } -- cgit 1.4.1-3-g733a5 From 5ef202520f9c4c87dd6218bbfbbf57587e88f8be Mon Sep 17 00:00:00 2001 From: Andrea Nall Date: Mon, 15 Feb 2021 02:27:20 +0000 Subject: add diagnostic items Add diagnostic items to the following types: OsString (os_string_type) PathBuf (path_buf_type) Owned (to_owned_trait) As well as the to_vec method on slice/[T] --- compiler/rustc_span/src/symbol.rs | 4 ++++ library/alloc/src/borrow.rs | 1 + library/alloc/src/slice.rs | 1 + library/std/src/ffi/os_str.rs | 1 + library/std/src/path.rs | 1 + 5 files changed, 8 insertions(+) (limited to 'library/alloc') diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1c37a6b2aca..de6210d1893 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -796,6 +796,7 @@ symbols! { options, or, or_patterns, + os_string_type, other, out, overlapping_marker_traits, @@ -824,6 +825,7 @@ symbols! { pat2018, pat2021, path, + path_buf_type, pattern_parentheses, phantom_data, pin, @@ -1084,6 +1086,7 @@ symbols! { slice, slice_alloc, slice_patterns, + slice_to_vec_method, slice_u8, slice_u8_alloc, slicing_syntax, @@ -1159,6 +1162,7 @@ symbols! { then_with, thread, thread_local, + to_owned_trait, tool_attributes, tool_lints, trace_macros, diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index adf996fc782..2fa349e3a4f 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -32,6 +32,7 @@ where /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_trait")] pub trait ToOwned { /// The resulting type after obtaining ownership. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index cb015b94930..f8cc6a45877 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -442,6 +442,7 @@ impl [T] { /// // Here, `s` and `x` can be modified independently. /// ``` #[rustc_conversion_suggestion] + #[rustc_diagnostic_item = "slice_to_vec_method"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_vec(&self) -> Vec diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c9c8f68cd9c..c1629d8b8f9 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -71,6 +71,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions #[derive(Clone)] +#[cfg_attr(not(test), rustc_diagnostic_item = "os_string_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { inner: Buf, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 1889e549338..66135a719be 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1066,6 +1066,7 @@ impl FusedIterator for Ancestors<'_> {} /// /// Which method works best depends on what kind of situation you're in. #[derive(Clone)] +#[cfg_attr(not(test), rustc_diagnostic_item = "path_buf_type")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `PathBuf::as_mut_vec` current implementation relies -- cgit 1.4.1-3-g733a5 From c6bb62810ae226b35e0181d8c4efc6d0377d196d Mon Sep 17 00:00:00 2001 From: Andrea Nall Date: Mon, 15 Feb 2021 22:58:03 +0000 Subject: requested/proposed changes --- compiler/rustc_span/src/symbol.rs | 7 +++---- library/alloc/src/borrow.rs | 2 +- library/alloc/src/slice.rs | 2 +- library/std/src/ffi/os_str.rs | 2 +- library/std/src/path.rs | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) (limited to 'library/alloc') diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index de6210d1893..83b13e7d93c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -169,10 +169,12 @@ symbols! { Option, Ord, Ordering, + OsString, Output, Param, PartialEq, PartialOrd, + PathBuf, Pending, Pin, Poll, @@ -198,6 +200,7 @@ symbols! { StructuralPartialEq, Sync, Target, + ToOwned, Try, Ty, TyCtxt, @@ -796,7 +799,6 @@ symbols! { options, or, or_patterns, - os_string_type, other, out, overlapping_marker_traits, @@ -825,7 +827,6 @@ symbols! { pat2018, pat2021, path, - path_buf_type, pattern_parentheses, phantom_data, pin, @@ -1086,7 +1087,6 @@ symbols! { slice, slice_alloc, slice_patterns, - slice_to_vec_method, slice_u8, slice_u8_alloc, slicing_syntax, @@ -1162,7 +1162,6 @@ symbols! { then_with, thread, thread_local, - to_owned_trait, tool_attributes, tool_lints, trace_macros, diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 2fa349e3a4f..cec32251819 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -32,7 +32,7 @@ where /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_trait")] +#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] pub trait ToOwned { /// The resulting type after obtaining ownership. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index f8cc6a45877..839f742f1af 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -220,6 +220,7 @@ mod hack { } #[lang = "slice_alloc"] +#[cfg_attr(not(test), rustc_diagnostic_item = "slice")] #[cfg(not(test))] impl [T] { /// Sorts the slice. @@ -442,7 +443,6 @@ impl [T] { /// // Here, `s` and `x` can be modified independently. /// ``` #[rustc_conversion_suggestion] - #[rustc_diagnostic_item = "slice_to_vec_method"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_vec(&self) -> Vec diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c1629d8b8f9..6af5adf4cd8 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -71,7 +71,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions #[derive(Clone)] -#[cfg_attr(not(test), rustc_diagnostic_item = "os_string_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { inner: Buf, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 66135a719be..759b233c7c1 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1066,7 +1066,7 @@ impl FusedIterator for Ancestors<'_> {} /// /// Which method works best depends on what kind of situation you're in. #[derive(Clone)] -#[cfg_attr(not(test), rustc_diagnostic_item = "path_buf_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `PathBuf::as_mut_vec` current implementation relies -- cgit 1.4.1-3-g733a5 From 67fcaaaa7a9c393926e25db600a9976137425d68 Mon Sep 17 00:00:00 2001 From: Andrea Nall Date: Tue, 16 Feb 2021 02:32:21 +0000 Subject: a few more diagnostic items --- compiler/rustc_span/src/symbol.rs | 3 +++ library/alloc/src/borrow.rs | 2 +- library/alloc/src/string.rs | 1 + library/std/src/ffi/os_str.rs | 1 + library/std/src/path.rs | 1 + 5 files changed, 7 insertions(+), 1 deletion(-) (limited to 'library/alloc') diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 83b13e7d93c..1137a83bc77 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -169,11 +169,13 @@ symbols! { Option, Ord, Ordering, + OsStr, OsString, Output, Param, PartialEq, PartialOrd, + Path, PathBuf, Pending, Pin, @@ -201,6 +203,7 @@ symbols! { Sync, Target, ToOwned, + ToString, Try, Ty, TyCtxt, diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index cec32251819..bdb2d67347e 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -31,8 +31,8 @@ where /// implementing the `Clone` trait. But `Clone` works only for going from `&T` /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. -#[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] +#[stable(feature = "rust1", since = "1.0.0")] pub trait ToOwned { /// The resulting type after obtaining ownership. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3218b3535c9..00fd1c2908b 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2174,6 +2174,7 @@ impl FromStr for String { /// implementation for free. /// /// [`Display`]: fmt::Display +#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToString { /// Converts the given value to a `String`. diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 6af5adf4cd8..13c8022820b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -90,6 +90,7 @@ pub struct OsString { /// /// [`&str`]: str /// [conversions]: super#conversions +#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `OsStr::from_inner` current implementation relies diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 759b233c7c1..afb28518b72 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1720,6 +1720,7 @@ impl AsRef for PathBuf { /// let extension = path.extension(); /// assert_eq!(extension, Some(OsStr::new("txt"))); /// ``` +#[cfg_attr(not(test), rustc_diagnostic_item = "Path")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `Path::new` current implementation relies -- cgit 1.4.1-3-g733a5