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]
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<N: Idx> {
 }
 
 impl<Node: Idx> Dominators<Node> {
+    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/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();
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(),
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<CastKind, CastError> {
-        // 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/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index e5045f906df59..66d158b0ee965 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -280,7 +280,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>(
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index eb8994681937a..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<T> VecDeque<T> {
     where
         R: RangeBounds<usize>,
     {
-        let Range { start, end } = range.assert_len(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 99c42a4ba4423..c020a969f1fb9 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_bounds_assert_len)]
 #![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 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 3218b3535c970..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.assert_len(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: `assert_len` 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 c7b4c98041b2e..cfe6c203d1a81 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1597,7 +1597,7 @@ impl<T, A: Allocator> Vec<T, A> {
         // 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 } = 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 0571dc74b9af9..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 (`..`).
 ///
@@ -764,92 +760,6 @@ pub trait RangeBounds<T: ?Sized> {
     #[stable(feature = "collections_range", since = "1.28.0")]
     fn end_bound(&self) -> Bound<&T>;
 
-    /// Performs bounds-checking of this range.
-    ///
-    /// 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`]: ../../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_assert_len)]
-    ///
-    /// 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()));
-    /// ```
-    ///
-    /// Panics when [`Index::index`] would panic:
-    ///
-    /// ```should_panic
-    /// #![feature(range_bounds_assert_len)]
-    ///
-    /// use std::ops::RangeBounds;
-    ///
-    /// (2..1).assert_len(3);
-    /// ```
-    ///
-    /// ```should_panic
-    /// #![feature(range_bounds_assert_len)]
-    ///
-    /// use std::ops::RangeBounds;
-    ///
-    /// (1..4).assert_len(3);
-    /// ```
-    ///
-    /// ```should_panic
-    /// #![feature(range_bounds_assert_len)]
-    ///
-    /// use std::ops::RangeBounds;
-    ///
-    /// (1..=usize::MAX).assert_len(3);
-    /// ```
-    ///
-    /// [`Index::index`]: crate::ops::Index::index
-    #[track_caller]
-    #[unstable(feature = "range_bounds_assert_len", issue = "76393")]
-    fn assert_len(self, len: usize) -> Range<usize>
-    where
-        Self: RangeBounds<usize>,
-    {
-        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/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<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
         (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<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
+where
+    R: ops::RangeBounds<usize>,
+{
+    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 19a3b45e568c0..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> [T] {
@@ -3052,7 +3056,7 @@ impl<T> [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 } = 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,
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,
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
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/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js
index 9c5ac1625afea..a50ed5b662bf6 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 {
+        return window.localStorage.getItem(name);
+    } catch(e) {
+        return null;
     }
-    return null;
 }
 
 function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
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..83f640e2f4013 100644
--- a/src/test/run-make-fulldeps/tools.mk
+++ b/src/test/run-make-fulldeps/tools.mk
@@ -21,6 +21,19 @@ 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
 
+# 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)`.
 RUN_BINFILE = $(TMPDIR)/$(1)
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`.