From 05af66a285df0d35809cb7dbd87390b27a89640a 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: [PATCH 01/15] Improve design of `assert_len` --- .../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 +- library/core/src/ops/range.rs | 35 ++++++++++++------- library/core/src/slice/mod.rs | 2 +- .../range-bounds-assert-len.md | 10 ------ .../range-bounds-ensure-subset-of.md | 10 ++++++ 8 files changed, 38 insertions(+), 29 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-bounds-assert-len.md create mode 100644 src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index eb8994681937a..0c267cbc106b9 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 785ce8d606b67..6ec4c0c28f6de 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -112,7 +112,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 3218b3535c970..3ab5ca4f566ad 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 9aea19f04c644..f19827700092d 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1597,7 +1597,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 diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 0571dc74b9af9..7a0dd5a8f0f72 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -766,8 +766,15 @@ pub trait RangeBounds { /// 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 of the given length. + /// [`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 @@ -779,49 +786,51 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// /// let v = [10, 40, 30]; - /// assert_eq!(1..2, (1..2).assert_len(v.len())); - /// assert_eq!(0..2, (..2).assert_len(v.len())); - /// assert_eq!(1..3, (1..).assert_len(v.len())); + /// 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_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (2..1).assert_len(3); + /// (2..1).ensure_subset_of(..3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (1..4).assert_len(3); + /// (1..4).ensure_subset_of(..3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (1..=usize::MAX).assert_len(3); + /// (1..=usize::MAX).ensure_subset_of(..3); /// ``` /// /// [`Index::index`]: crate::ops::Index::index #[track_caller] - #[unstable(feature = "range_bounds_assert_len", issue = "76393")] - fn assert_len(self, len: usize) -> Range + #[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, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 19a3b45e568c0..90351be69291e 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.assert_len(self.len()); + let Range { start: src_start, end: src_end } = src.ensure_subset_of(..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-assert-len.md b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md deleted file mode 100644 index 0e95d5ded9296..0000000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_bounds_assert_len` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`RangeBounds::assert_len`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`RangeBounds::assert_len`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.assert_len 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 new file mode 100644 index 0000000000000..ea3f01ff5f9d1 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md @@ -0,0 +1,10 @@ +# `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 From 866c64eca36b1fe1650105357fcec24f751355a5 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: [PATCH 02/15] Fix possible soundness issue in `ensure_subset_of` --- .../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 - .../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 diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 0c267cbc106b9..319ca666fc622 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 6ec4c0c28f6de..db6c8eac68ed0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -112,7 +112,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 3ab5ca4f566ad..ef2f264ec7ea8 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 f19827700092d..a7fd224af8aaa 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1597,7 +1597,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 7a0dd5a8f0f72..b30ff9450ff02 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 90351be69291e..e78b647651101 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 ea3f01ff5f9d1..0000000000000 --- 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 0000000000000..8b5a21a34cfbb --- /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 From feaca9b8227ab643ad4ba6c8eed35c8e7d5aec62 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 18 Jan 2021 14:48:22 -0500 Subject: [PATCH 03/15] Remove unnecessary documentation page --- .../src/library-features/range-ensure-subset-of.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-ensure-subset-of.md 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 deleted file mode 100644 index 8b5a21a34cfbb..0000000000000 --- a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md +++ /dev/null @@ -1,10 +0,0 @@ -# `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 From dd1ab4c20b40df70410c7e9b70d72da6fdf06e64 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: [PATCH 04/15] Rename `Range::ensure_subset_of` to `slice::range` --- .../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(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 319ca666fc622..f7cefdce27856 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 db6c8eac68ed0..2967f0ba1b38a 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -112,7 +112,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))] @@ -120,6 +119,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 cb015b949305c..c5ffade12619f 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 ef2f264ec7ea8..b4deedc52638c 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 a7fd224af8aaa..0e6bf4abeec7e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1597,7 +1597,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 b30ff9450ff02..dbeb391213006 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 660c8a2da5da0..d20986bb724fc 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 e78b647651101..8256d2cc6070e 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, From 57ace0d250b3b4e1bb87680a94c7c08927300039 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Wed, 3 Feb 2021 16:26:25 -0800 Subject: [PATCH 05/15] Ensures `make` tests run under /bin/dash, like CI, and fixes a Makefile Updates `tools.mk` to explicitly require `SHELL := /bin/dash`, since CI uses `dash` but other environments (including developer local machines) may default to `bash`. Replaces bash-specific shell command in one Makefile with a dash-compatible alternative, and re-enables the affected Makefile test. Removes apparently redundant definition of `UNAME`. --- src/test/run-make-fulldeps/coverage-reports/Makefile | 3 +-- src/test/run-make-fulldeps/coverage/coverage_tools.mk | 2 -- src/test/run-make-fulldeps/tools.mk | 6 ++++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile index a700cf68cd9da..31583eaa8fee5 100644 --- a/src/test/run-make-fulldeps/coverage-reports/Makefile +++ b/src/test/run-make-fulldeps/coverage-reports/Makefile @@ -1,4 +1,3 @@ -# ignore-test Broken; accidentally silently ignored on Linux CI; FIXME(#81688) # needs-profiler-support # ignore-windows-gnu # min-llvm-version: 11.0 @@ -128,7 +127,7 @@ endif $$( \ for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \ do \ - [[ -x $$file ]] && printf "%s %s " -object $$file; \ + [ -x "$$file" ] && printf "%s %s " -object $$file; \ done \ ) \ 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \ diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk index 11fd824e5272f..38643aaf9021e 100644 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ b/src/test/run-make-fulldeps/coverage/coverage_tools.mk @@ -12,5 +12,3 @@ # Enabling `-C link-dead-code` is not necessary when compiling with `-Z instrument-coverage`, # due to improvements in the coverage map generation, to add unreachable functions known to Rust. # Therefore, `-C link-dead-code` is no longer automatically enabled. - -UNAME = $(shell uname) diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index 634c9ece3f5c8..29ca30a7cd89b 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -21,6 +21,12 @@ CGREP := "$(S)/src/etc/cat-and-grep.sh" # diff with common flags for multi-platform diffs against text output DIFF := diff -u --strip-trailing-cr +# CI platforms use `/bin/dash`. When compiling in other environments, the +# default may be different (for example, may default to `/bin/bash`), and syntax +# and results could be different. Ensure Makefile `$(shell ...)` invocations +# always run in `dash`. +SHELL := /bin/dash + # This is the name of the binary we will generate and run; use this # e.g. for `$(CC) -o $(RUN_BINFILE)`. RUN_BINFILE = $(TMPDIR)/$(1) From ca3a7140965144bb5fec914de843514fd03809c8 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Fri, 5 Feb 2021 17:50:37 -0800 Subject: [PATCH 06/15] Set SHELL = /bin/dash only if it exists --- src/test/run-make-fulldeps/tools.mk | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index 29ca30a7cd89b..83f640e2f4013 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -21,11 +21,18 @@ CGREP := "$(S)/src/etc/cat-and-grep.sh" # diff with common flags for multi-platform diffs against text output DIFF := diff -u --strip-trailing-cr -# CI platforms use `/bin/dash`. When compiling in other environments, the -# default may be different (for example, may default to `/bin/bash`), and syntax -# and results could be different. Ensure Makefile `$(shell ...)` invocations -# always run in `dash`. +# Some of the Rust CI platforms use `/bin/dash` to run `shell` script in +# Makefiles. Other platforms, including many developer platforms, default to +# `/bin/bash`. (In many cases, `make` is actually using `/bin/sh`, but `sh` +# is configured to execute one or the other shell binary). `dash` features +# support only a small subset of `bash` features, so `dash` can be thought of as +# the lowest common denominator, and tests should be validated against `dash` +# whenever possible. Most developer platforms include `/bin/dash`, but to ensure +# tests still work when `/bin/dash`, if not available, this `SHELL` override is +# conditional: +ifneq (,$(wildcard /bin/dash)) SHELL := /bin/dash +endif # This is the name of the binary we will generate and run; use this # e.g. for `$(CC) -o $(RUN_BINFILE)`. From 471ed5f80fd1a53a26dc8ca750910f75ed744795 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 9 Feb 2021 19:05:18 -0600 Subject: [PATCH 07/15] Use ItemCtxt::to_ty --- compiler/rustc_typeck/src/collect.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b1d98d75196d5..2c1e07fb7003d 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -278,7 +278,7 @@ impl ItemCtxt<'tcx> { ItemCtxt { tcx, item_def_id } } - pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> { + pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { AstConv::ast_ty_to_ty(self, ast_ty) } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index fd44bafab6f76..542fa1a5acce0 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -421,8 +421,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id); let env_def_id = tcx.hir().local_def_id(env_node_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); - - astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty) + item_cx.to_ty(hir_ty) } pub fn hir_trait_to_predicates<'tcx>( From 883988b350c13f0dcd1e1cdd7e866e427d41db6e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 9 Feb 2021 19:45:32 -0800 Subject: [PATCH 08/15] RELEASES.md 1.50: Group platform support notes together Move the note about dropping cloudabi next to the other platform support changes. --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 18492213a5dd3..f5b71f295c629 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -12,6 +12,7 @@ Compiler - [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142] - [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484] - [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484] +- [Dropped support for all cloudabi targets.][78439] \* Refer to Rust's [platform support page][forge-platform-support] for more information on Rust's tiered platform support. @@ -77,7 +78,6 @@ Compatibility Notes - [`#![test]` as an inner attribute is now considered unstable like other inner macro attributes, and reports an error by default through the `soft_unstable` lint.][79003] - [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864] -- [Dropped support for all cloudabi targets.][78439] - [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's recommended to use the `#[panic_handler]` attribute to provide your own implementation. - [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296] From d3fea13ae0949a64b5809ba6a7304307ddf3528e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 9 Feb 2021 19:04:29 -0800 Subject: [PATCH 09/15] bootstrap: Locate llvm-dwp based on llvm-config bindir --- src/bootstrap/compile.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 833c13e9a2615..dee0c15420136 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1075,8 +1075,11 @@ impl Step for Assemble { let src_exe = exe("llvm-dwp", target_compiler.host); let dst_exe = exe("rust-llvm-dwp", target_compiler.host); let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host }); - let llvm_bin_dir = llvm_config_bin.parent().unwrap(); - builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); + if !builder.config.dry_run { + let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir")); + let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); + builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); + } } // Ensure that `libLLVM.so` ends up in the newly build compiler directory, From 3c1d792f498ae40eb759d4554540a94612a3df55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 17 Jan 2021 20:20:16 +0100 Subject: [PATCH 10/15] Only initialize what is used --- compiler/rustc_data_structures/src/graph/dominators/mod.rs | 4 ++++ compiler/rustc_mir/src/borrow_check/mod.rs | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index ad62e3c9fc8f4..1cd170599ba51 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -85,6 +85,10 @@ pub struct Dominators { } impl Dominators { + pub fn dummy() -> Self { + Self { post_order_rank: IndexVec::new(), immediate_dominators: IndexVec::new() } + } + pub fn is_reachable(&self, node: Node) -> bool { self.immediate_dominators[node].is_some() } diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 0bd0a4060b599..375d464917118 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -266,7 +266,6 @@ fn do_mir_borrowck<'a, 'tcx>( for (idx, move_data_results) in promoted_errors { let promoted_body = &promoted[idx]; - let dominators = promoted_body.dominators(); if let Err((move_data, move_errors)) = move_data_results { let mut promoted_mbcx = MirBorrowckCtxt { @@ -274,7 +273,7 @@ fn do_mir_borrowck<'a, 'tcx>( param_env, body: promoted_body, move_data: &move_data, - location_table: &LocationTable::new(promoted_body), + location_table, // no need to create a real one for the promoted, it is not used movable_generator, fn_self_span_reported: Default::default(), locals_are_invalidated_at_exit, @@ -288,7 +287,7 @@ fn do_mir_borrowck<'a, 'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - dominators, + dominators: Dominators::dummy(), // not used upvars: Vec::new(), local_names: IndexVec::from_elem(None, &promoted_body.local_decls), region_names: RefCell::default(), From a6d413715c2b0439ab27cb69a757377f1c8c397a Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Wed, 10 Feb 2021 09:36:26 +0100 Subject: [PATCH 11/15] Fix assosiated typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced in d3c4dbd85d63c8bdfa362d7cac8b3e8cbca51272, noticed only after the fact, sorry. 😅 Signed-off-by: Daniel Egger --- .../rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 0467bf76afecc..98450f5a547da 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -540,7 +540,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } - // Attempt to search similar mutable assosiated items for suggestion. + // Attempt to search similar mutable associated items for suggestion. // In the future, attempt in all path but initially for RHS of for_loop fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) { let hir = self.infcx.tcx.hir(); From d64b749f2cebcfec942ecbbb87e24a9f8cc28469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Thu, 28 Jan 2021 20:22:33 +0300 Subject: [PATCH 12/15] Allow casting mut array ref to mut ptr We now allow two new casts: - mut array reference to mut ptr. Example: let mut x: [usize; 2] = [0, 0]; let p = &mut x as *mut usize; We allow casting const array references to const pointers so not allowing mut references to mut pointers was inconsistent. - mut array reference to const ptr. Example: let mut x: [usize; 2] = [0, 0]; let p = &mut x as *const usize; This was similarly inconsistent as we allow casting mut references to const pointers. Existing test 'vector-cast-weirdness' updated to test both cases. Fixes #24151 --- .../src/borrow_check/type_check/mod.rs | 39 ++++++++++++------- compiler/rustc_typeck/src/check/cast.rs | 5 +-- .../array-slice-vec/vector-cast-weirdness.rs | 14 ++++++- .../vector-cast-weirdness.stderr | 22 ++++++++--- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 3ba06bdd6e05f..52b1ff3877da7 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -2191,19 +2191,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CastKind::Pointer(PointerCast::ArrayToPointer) => { let ty_from = op.ty(body, tcx); - let opt_ty_elem = match ty_from.kind() { - ty::RawPtr(ty::TypeAndMut { - mutbl: hir::Mutability::Not, - ty: array_ty, - }) => match array_ty.kind() { - ty::Array(ty_elem, _) => Some(ty_elem), - _ => None, - }, + let opt_ty_elem_mut = match ty_from.kind() { + ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => { + match array_ty.kind() { + ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)), + _ => None, + } + } _ => None, }; - let ty_elem = match opt_ty_elem { - Some(ty_elem) => ty_elem, + let (ty_elem, ty_mut) = match opt_ty_elem_mut { + Some(ty_elem_mut) => ty_elem_mut, None => { span_mirbug!( self, @@ -2215,11 +2214,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; - let ty_to = match ty.kind() { - ty::RawPtr(ty::TypeAndMut { - mutbl: hir::Mutability::Not, - ty: ty_to, - }) => ty_to, + let (ty_to, ty_to_mut) = match ty.kind() { + ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => { + (ty_to, *ty_to_mut) + } _ => { span_mirbug!( self, @@ -2231,6 +2229,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; + if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not { + span_mirbug!( + self, + rvalue, + "ArrayToPointer cast from const {:?} to mut {:?}", + ty, + ty_to + ); + return; + } + if let Err(terr) = self.sub_types( ty_elem, ty_to, diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7924ffe8a6fd5..16c344e8e2b9e 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -765,9 +765,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { m_expr: ty::TypeAndMut<'tcx>, m_cast: ty::TypeAndMut<'tcx>, ) -> Result { - // array-ptr-cast. - - if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not { + // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const + if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not { if let ty::Array(ety, _) = m_expr.ty.kind() { // Due to the limitations of LLVM global constants, // region pointers end up pointing at copies of diff --git a/src/test/ui/array-slice-vec/vector-cast-weirdness.rs b/src/test/ui/array-slice-vec/vector-cast-weirdness.rs index 79b9243765b95..e8f2c71477a5f 100644 --- a/src/test/ui/array-slice-vec/vector-cast-weirdness.rs +++ b/src/test/ui/array-slice-vec/vector-cast-weirdness.rs @@ -1,7 +1,11 @@ // Issue #14893. Tests that casts from vectors don't behave strangely in the // presence of the `_` type shorthand notation. +// // Update: after a change to the way casts are done, we have more type information // around and so the errors here are no longer exactly the same. +// +// Update: With PR #81479 some of the previously rejected cases are now allowed. +// New test cases added. struct X { y: [u8; 2], @@ -12,13 +16,19 @@ fn main() { // No longer a type mismatch - the `_` can be fully resolved by type inference. let p1: *const u8 = &x1.y as *const _; + let p1: *mut u8 = &x1.y as *mut _; + //~^ ERROR: casting `&[u8; 2]` as `*mut u8` is invalid let t1: *const [u8; 2] = &x1.y as *const _; + let t1: *mut [u8; 2] = &x1.y as *mut _; + //~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid let h1: *const [u8; 2] = &x1.y as *const [u8; 2]; + let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2]; + //~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid let mut x1 = X { y: [0, 0] }; - // This is still an error since we don't allow casts from &mut [T; n] to *mut T. - let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR casting + let p1: *mut u8 = &mut x1.y as *mut _; + let p2: *const u8 = &mut x1.y as *const _; let t1: *mut [u8; 2] = &mut x1.y as *mut _; let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2]; } diff --git a/src/test/ui/array-slice-vec/vector-cast-weirdness.stderr b/src/test/ui/array-slice-vec/vector-cast-weirdness.stderr index 37055bb75f559..6fdb1ac9e3059 100644 --- a/src/test/ui/array-slice-vec/vector-cast-weirdness.stderr +++ b/src/test/ui/array-slice-vec/vector-cast-weirdness.stderr @@ -1,9 +1,21 @@ -error[E0606]: casting `&mut [u8; 2]` as `*mut u8` is invalid - --> $DIR/vector-cast-weirdness.rs:21:23 +error[E0606]: casting `&[u8; 2]` as `*mut u8` is invalid + --> $DIR/vector-cast-weirdness.rs:19:23 | -LL | let p1: *mut u8 = &mut x1.y as *mut _; - | ^^^^^^^^^^^^^^^^^^^ +LL | let p1: *mut u8 = &x1.y as *mut _; + | ^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid + --> $DIR/vector-cast-weirdness.rs:22:28 + | +LL | let t1: *mut [u8; 2] = &x1.y as *mut _; + | ^^^^^^^^^^^^^^^ + +error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid + --> $DIR/vector-cast-weirdness.rs:25:28 + | +LL | let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2]; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0606`. From f13bbea1243d35467601e82096b3db956774b2a5 Mon Sep 17 00:00:00 2001 From: Ophir LOJKINE Date: Wed, 10 Feb 2021 14:53:22 +0100 Subject: [PATCH 13/15] Catch errors on localStorage setting failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/rust-lang/rust/issues/81928 “Ask forgiveness not permission” : this makes the code both simpler and more robust --- src/librustdoc/html/static/storage.js | 31 +++++++-------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 9c5ac1625afea..11265ae0ee339 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -89,35 +89,20 @@ function hasOwnProperty(obj, property) { return Object.prototype.hasOwnProperty.call(obj, property); } -function usableLocalStorage() { - // Check if the browser supports localStorage at all: - if (typeof Storage === "undefined") { - return false; - } - // Check if we can access it; this access will fail if the browser - // preferences deny access to localStorage, e.g., to prevent storage of - // "cookies" (or cookie-likes, as is the case here). - try { - return window.localStorage !== null && window.localStorage !== undefined; - } catch(err) { - // Storage is supported, but browser preferences deny access to it. - return false; - } -} - function updateLocalStorage(name, value) { - if (usableLocalStorage()) { - localStorage[name] = value; - } else { - // No Web Storage support so we do nothing + try { + window.localStorage.setItem(name, value); + } catch(e) { + // localStorage is not accessible, do nothing } } function getCurrentValue(name) { - if (usableLocalStorage() && localStorage[name] !== undefined) { - return localStorage[name]; + try { + window.localStorage.getItem(name); + } catch(e) { + return null; } - return null; } function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { From 16f0ccda86b7cce1b2cfb7b6bcdef42e3e76dfbc Mon Sep 17 00:00:00 2001 From: Ophir LOJKINE Date: Wed, 10 Feb 2021 14:55:53 +0100 Subject: [PATCH 14/15] Fix getCurrentValue --- src/librustdoc/html/static/storage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 11265ae0ee339..a50ed5b662bf6 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -99,7 +99,7 @@ function updateLocalStorage(name, value) { function getCurrentValue(name) { try { - window.localStorage.getItem(name); + return window.localStorage.getItem(name); } catch(e) { return null; } From 5034b504b4e91c8fdc001a6bb5ae5db988feb355 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 10 Feb 2021 18:33:43 +0100 Subject: [PATCH 15/15] bootstrap: fix wrong docs installation path --- src/bootstrap/install.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index fd0acc3a919b0..22124ec67f5f3 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -29,7 +29,7 @@ fn install_sh( let prefix = default_path(&builder.config.prefix, "/usr/local"); let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); let datadir = prefix.join(default_path(&builder.config.datadir, "share")); - let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc")); + let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust")); let mandir = prefix.join(default_path(&builder.config.mandir, "share/man")); let libdir = prefix.join(default_path(&builder.config.libdir, "lib")); let bindir = prefix.join(&builder.config.bindir); // Default in config.rs