about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs60
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs11
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs15
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs9
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs9
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs1
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs64
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs3
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--library/core/src/future/future.rs3
-rw-r--r--library/core/src/future/mod.rs9
-rw-r--r--library/core/src/pin.rs4
-rw-r--r--library/std/src/keyword_docs.rs14
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--src/bootstrap/compile.rs6
-rw-r--r--src/librustdoc/clean/utils.rs6
-rw-r--r--src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff70
-rw-r--r--src/test/mir-opt/const_prop/invalid_constant.rs8
-rw-r--r--src/test/ui/const-generics/issues/issue-75763.rs16
-rw-r--r--src/test/ui/let-else/let-else-destructuring.rs18
-rw-r--r--src/test/ui/let-else/let-else-destructuring.stderr17
36 files changed, 260 insertions, 244 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 11eda987b97..533c32f807d 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -231,9 +231,8 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
     // Catch such calls and evaluate them instead of trying to load a constant's MIR.
     if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
         let ty = key.value.instance.ty(tcx, key.param_env);
-        let substs = match ty.kind() {
-            ty::FnDef(_, substs) => substs,
-            _ => bug!("intrinsic with type {:?}", ty),
+        let ty::FnDef(_, substs) = ty.kind() else {
+            bug!("intrinsic with type {:?}", ty);
         };
         return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| {
             let span = tcx.def_span(def_id);
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index e157b584052..b2019ce40c3 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -318,15 +318,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         let intrinsic_name = ecx.tcx.item_name(instance.def_id());
 
         // CTFE-specific intrinsics.
-        let (dest, ret) = match ret {
-            None => {
-                return Err(ConstEvalErrKind::NeedsRfc(format!(
-                    "calling intrinsic `{}`",
-                    intrinsic_name
-                ))
-                .into());
-            }
-            Some(p) => p,
+        let Some((dest, ret)) = ret else {
+            return Err(ConstEvalErrKind::NeedsRfc(format!(
+                "calling intrinsic `{}`",
+                intrinsic_name
+            ))
+            .into());
         };
         match intrinsic_name {
             sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 1b86bcfa8c9..ab50c709143 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -631,15 +631,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // the last field).  Can't have foreign types here, how would we
                 // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1);
-                let (unsized_size, unsized_align) =
-                    match self.size_and_align_of(metadata, &field)? {
-                        Some(size_and_align) => size_and_align,
-                        None => {
-                            // A field with an extern type. We don't know the actual dynamic size
-                            // or the alignment.
-                            return Ok(None);
-                        }
-                    };
+                let Some((unsized_size, unsized_align)) = self.size_and_align_of(metadata, &field)? else {
+                    // A field with an extern type. We don't know the actual dynamic size
+                    // or the alignment.
+                    return Ok(None);
+                };
 
                 // FIXME (#26403, #27023): We should be adding padding
                 // to `sized_size` (to accommodate the `unsized_align`
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index a1dd587c17a..b1f50bc56c9 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -84,22 +84,19 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
     trace!("intern_shallow {:?} with {:?}", alloc_id, mode);
     // remove allocation
     let tcx = ecx.tcx;
-    let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) {
-        Some(entry) => entry,
-        None => {
-            // Pointer not found in local memory map. It is either a pointer to the global
-            // map, or dangling.
-            // If the pointer is dangling (neither in local nor global memory), we leave it
-            // to validation to error -- it has the much better error messages, pointing out where
-            // in the value the dangling reference lies.
-            // The `delay_span_bug` ensures that we don't forget such a check in validation.
-            if tcx.get_global_alloc(alloc_id).is_none() {
-                tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
-            }
-            // treat dangling pointers like other statics
-            // just to stop trying to recurse into them
-            return Some(IsStaticOrFn);
+    let Some((kind, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) else {
+        // Pointer not found in local memory map. It is either a pointer to the global
+        // map, or dangling.
+        // If the pointer is dangling (neither in local nor global memory), we leave it
+        // to validation to error -- it has the much better error messages, pointing out where
+        // in the value the dangling reference lies.
+        // The `delay_span_bug` ensures that we don't forget such a check in validation.
+        if tcx.get_global_alloc(alloc_id).is_none() {
+            tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
         }
+        // treat dangling pointers like other statics
+        // just to stop trying to recurse into them
+        return Some(IsStaticOrFn);
     };
     // This match is just a canary for future changes to `MemoryKind`, which most likely need
     // changes in this function.
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 4aa3c83cc02..73e7d862ad6 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -291,21 +291,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             );
         }
 
-        let (alloc_kind, mut alloc) = match self.alloc_map.remove(&alloc_id) {
-            Some(alloc) => alloc,
-            None => {
-                // Deallocating global memory -- always an error
-                return Err(match self.tcx.get_global_alloc(alloc_id) {
-                    Some(GlobalAlloc::Function(..)) => {
-                        err_ub_format!("deallocating {}, which is a function", alloc_id)
-                    }
-                    Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
-                        err_ub_format!("deallocating {}, which is static memory", alloc_id)
-                    }
-                    None => err_ub!(PointerUseAfterFree(alloc_id)),
+        let Some((alloc_kind, mut alloc)) = self.alloc_map.remove(&alloc_id) else {
+            // Deallocating global memory -- always an error
+            return Err(match self.tcx.get_global_alloc(alloc_id) {
+                Some(GlobalAlloc::Function(..)) => {
+                    err_ub_format!("deallocating {}, which is a function", alloc_id)
                 }
-                .into());
+                Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
+                    err_ub_format!("deallocating {}, which is static memory", alloc_id)
+                }
+                None => err_ub!(PointerUseAfterFree(alloc_id)),
             }
+            .into());
         };
 
         if alloc.mutability == Mutability::Not {
@@ -957,9 +954,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         ptr: Pointer<Option<M::PointerTag>>,
         size: Size,
     ) -> InterpResult<'tcx, &[u8]> {
-        let alloc_ref = match self.get(ptr, size, Align::ONE)? {
-            Some(a) => a,
-            None => return Ok(&[]), // zero-sized access
+        let Some(alloc_ref) = self.get(ptr, size, Align::ONE)? else {
+            // zero-sized access
+            return Ok(&[]);
         };
         // Side-step AllocRef and directly access the underlying bytes more efficiently.
         // (We are staying inside the bounds here so all is good.)
@@ -983,17 +980,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         assert_eq!(lower, len, "can only write iterators with a precise length");
 
         let size = Size::from_bytes(len);
-        let alloc_ref = match self.get_mut(ptr, size, Align::ONE)? {
-            Some(alloc_ref) => alloc_ref,
-            None => {
-                // zero-sized access
-                assert_matches!(
-                    src.next(),
-                    None,
-                    "iterator said it was empty but returned an element"
-                );
-                return Ok(());
-            }
+        let Some(alloc_ref) = self.get_mut(ptr, size, Align::ONE)? else {
+            // zero-sized access
+            assert_matches!(
+                src.next(),
+                None,
+                "iterator said it was empty but returned an element"
+            );
+            return Ok(());
         };
 
         // Side-step AllocRef and directly access the underlying bytes more efficiently.
@@ -1043,18 +1037,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         // and once below to get the underlying `&[mut] Allocation`.
 
         // Source alloc preparations and access hooks.
-        let (src_alloc_id, src_offset, src) = match src_parts {
-            None => return Ok(()), // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
-            Some(src_ptr) => src_ptr,
+        let Some((src_alloc_id, src_offset, src)) = src_parts else {
+            // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
+            return Ok(());
         };
         let src_alloc = self.get_raw(src_alloc_id)?;
         let src_range = alloc_range(src_offset, size);
         M::memory_read(&self.extra, &src_alloc.extra, src.provenance, src_range)?;
         // We need the `dest` ptr for the next operation, so we get it now.
         // We already did the source checks and called the hooks so we are good to return early.
-        let (dest_alloc_id, dest_offset, dest) = match dest_parts {
-            None => return Ok(()), // Zero-sized *destiantion*.
-            Some(dest_ptr) => dest_ptr,
+        let Some((dest_alloc_id, dest_offset, dest)) = dest_parts else {
+            // Zero-sized *destination*.
+            return Ok(());
         };
 
         // This checks relocation edges on the src, which needs to happen before
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index ec5eafcd633..60e915a7eee 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -258,15 +258,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             return Ok(None);
         }
 
-        let alloc = match self.get_alloc(mplace)? {
-            Some(ptr) => ptr,
-            None => {
-                return Ok(Some(ImmTy {
-                    // zero-sized type
-                    imm: Scalar::ZST.into(),
-                    layout: mplace.layout,
-                }));
-            }
+        let Some(alloc) = self.get_alloc(mplace)? else {
+            return Ok(Some(ImmTy {
+                // zero-sized type
+                imm: Scalar::ZST.into(),
+                layout: mplace.layout,
+            }));
         };
 
         match mplace.layout.abi {
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 7b06ffaf15d..e9b2df53a33 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -420,9 +420,8 @@ where
     ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
     {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
-        let stride = match base.layout.fields {
-            FieldsShape::Array { stride, .. } => stride,
-            _ => span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"),
+        let FieldsShape::Array { stride, .. } = base.layout.fields else {
+            span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout");
         };
         let layout = base.layout.field(self, 0);
         let dl = &self.tcx.data_layout;
@@ -747,9 +746,9 @@ where
 
         // Invalid places are a thing: the return place of a diverging function
         let tcx = *self.tcx;
-        let mut alloc = match self.get_alloc_mut(dest)? {
-            Some(a) => a,
-            None => return Ok(()), // zero-sized access
+        let Some(mut alloc) = self.get_alloc_mut(dest)? else {
+            // zero-sized access
+            return Ok(());
         };
 
         // FIXME: We should check that there are dest.layout.size many bytes available in
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 57ba9b40992..0701e0ded97 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -46,15 +46,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             return Ok(false);
         }
 
-        let loc = match self.frame().loc {
-            Ok(loc) => loc,
-            Err(_) => {
-                // We are unwinding and this fn has no cleanup code.
-                // Just go on unwinding.
-                trace!("unwinding: skipping frame");
-                self.pop_stack_frame(/* unwinding */ true)?;
-                return Ok(true);
-            }
+        let Ok(loc) = self.frame().loc else {
+            // We are unwinding and this fn has no cleanup code.
+            // Just go on unwinding.
+            trace!("unwinding: skipping frame");
+            self.pop_stack_frame(/* unwinding */ true)?;
+            return Ok(true);
         };
         let basic_block = &self.body().basic_blocks()[loc.block];
 
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index f3910c9765d..8094bf0cf2e 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -321,10 +321,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | ty::InstanceDef::CloneShim(..)
             | ty::InstanceDef::Item(_) => {
                 // We need MIR for this fn
-                let (body, instance) =
-                    match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? {
-                        Some(body) => body,
-                        None => return Ok(()),
+                let Some((body, instance)) =
+                    M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? else {
+                        return Ok(());
                     };
 
                 // Compute callee information using the `instance` returned by
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index e95e327618f..19c6449078d 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -697,7 +697,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 this.ecx.read_discriminant(op),
                 this.path,
                 err_ub!(InvalidTag(val)) =>
-                    { "{}", val } expected { "a valid enum tag" },
+                    { "{:x}", val } expected { "a valid enum tag" },
                 err_ub!(InvalidUninitBytes(None)) =>
                     { "uninitialized bytes" } expected { "a valid enum tag" },
                 err_unsup!(ReadPointerAsBytes) =>
@@ -851,12 +851,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 // to reject those pointers, we just do not have the machinery to
                 // talk about parts of a pointer.
                 // We also accept uninit, for consistency with the slow path.
-                let alloc = match self.ecx.memory.get(mplace.ptr, size, mplace.align)? {
-                    Some(a) => a,
-                    None => {
-                        // Size 0, nothing more to check.
-                        return Ok(());
-                    }
+                let Some(alloc) = self.ecx.memory.get(mplace.ptr, size, mplace.align)? else {
+                    // Size 0, nothing more to check.
+                    return Ok(());
                 };
 
                 let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 095c8f84f41..652f1c94a61 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -134,11 +134,8 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
             .find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
             .map(|(bb, _)| bb);
 
-        let return_block = match return_block {
-            None => {
-                return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
-            }
-            Some(bb) => bb,
+        let Some(return_block) = return_block else {
+            return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
         };
 
         let return_loc = ccx.body.terminator_loc(return_block);
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index cacc0018fe9..30764f689c9 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -747,15 +747,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         if loc.statement_index < num_stmts {
             let (mut rvalue, source_info) = {
                 let statement = &mut self.source[loc.block].statements[loc.statement_index];
-                let rhs = match statement.kind {
-                    StatementKind::Assign(box (_, ref mut rhs)) => rhs,
-                    _ => {
-                        span_bug!(
-                            statement.source_info.span,
-                            "{:?} is not an assignment",
-                            statement
-                        );
-                    }
+                let StatementKind::Assign(box (_, ref mut rhs)) = statement.kind else {
+                    span_bug!(
+                        statement.source_info.span,
+                        "{:?} is not an assignment",
+                        statement
+                    );
                 };
 
                 (
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index 73adc60577b..e4528b68907 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -15,12 +15,9 @@ where
     L: HasLocalDecls<'tcx>,
 {
     debug!("is_disaligned({:?})", place);
-    let pack = match is_within_packed(tcx, local_decls, place) {
-        None => {
-            debug!("is_disaligned({:?}) - not within packed", place);
-            return false;
-        }
-        Some(pack) => pack,
+    let Some(pack) = is_within_packed(tcx, local_decls, place) else {
+        debug!("is_disaligned({:?}) - not within packed", place);
+        return false;
     };
 
     let ty = place.ty(local_decls, tcx).ty;
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 25b7a84b3a0..5fe2a1fb84b 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -132,11 +132,11 @@ type ObligationTreeIdGenerator =
     std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
 
 pub struct ObligationForest<O: ForestObligation> {
-    /// The list of obligations. In between calls to `process_obligations`,
+    /// The list of obligations. In between calls to [Self::process_obligations],
     /// this list only contains nodes in the `Pending` or `Waiting` state.
     ///
     /// `usize` indices are used here and throughout this module, rather than
-    /// `rustc_index::newtype_index!` indices, because this code is hot enough
+    /// [`rustc_index::newtype_index!`] indices, because this code is hot enough
     /// that the `u32`-to-`usize` conversions that would be required are
     /// significant, and space considerations are not important.
     nodes: Vec<Node<O>>,
@@ -146,10 +146,11 @@ pub struct ObligationForest<O: ForestObligation> {
 
     /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately,
     /// its contents are not guaranteed to match those of `nodes`. See the
-    /// comments in `process_obligation` for details.
+    /// comments in [`Self::process_obligation` for details.
     active_cache: FxHashMap<O::CacheKey, usize>,
 
-    /// A vector reused in compress() and find_cycles_from_node(), to avoid allocating new vectors.
+    /// A vector reused in [Self::compress()] and [Self::find_cycles_from_node()],
+    /// to avoid allocating new vectors.
     reused_node_vec: Vec<usize>,
 
     obligation_tree_id_generator: ObligationTreeIdGenerator,
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 82454b89156..652f5abab15 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -123,7 +123,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         result
     }
 
-    /// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
+    /// See [RegionConstraintCollector::leak_check][1].
+    ///
+    /// [1]: crate::infer::region_constraints::RegionConstraintCollector::leak_check
     pub fn leak_check(
         &self,
         overly_polymorphic: bool,
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 36d18aebfe2..817aaf10053 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -100,6 +100,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
 struct LeakCheck<'me, 'tcx> {
     tcx: TyCtxt<'tcx>,
     universe_at_start_of_snapshot: ty::UniverseIndex,
+    /// Only used when reporting region errors.
     overly_polymorphic: bool,
     mini_graph: &'me MiniGraph<'tcx>,
     rcc: &'me RegionConstraintCollector<'me, 'tcx>,
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index e9a857d0912..c5866924eda 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -370,7 +370,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
             InvalidChar(c) => {
                 write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
             }
-            InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
+            InvalidTag(val) => write!(f, "enum value has invalid tag: {:x}", val),
             InvalidFunctionPointer(p) => {
                 write!(f, "using {:?} as function pointer but it does not point to a function", p)
             }
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index aa8730bf9cd..acf7847de54 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -153,7 +153,16 @@ impl<Tag: Provenance> fmt::Display for Scalar<Tag> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
-            Scalar::Int(int) => write!(f, "{:?}", int),
+            Scalar::Int(int) => write!(f, "{}", int),
+        }
+    }
+}
+
+impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
+            Scalar::Int(int) => write!(f, "0x{:x}", int),
         }
     }
 }
@@ -370,78 +379,82 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
         }
     }
 
+    /// Converts the scalar to produce an unsigned integer of the given size.
+    /// Fails if the scalar is a pointer.
     #[inline]
-    fn to_unsigned_with_bit_width(self, bits: u64) -> InterpResult<'static, u128> {
-        let sz = Size::from_bits(bits);
-        self.to_bits(sz)
+    pub fn to_uint(self, size: Size) -> InterpResult<'static, u128> {
+        self.to_bits(size)
     }
 
     /// Converts the scalar to produce a `u8`. Fails if the scalar is a pointer.
     pub fn to_u8(self) -> InterpResult<'static, u8> {
-        self.to_unsigned_with_bit_width(8).map(|v| u8::try_from(v).unwrap())
+        self.to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u16`. Fails if the scalar is a pointer.
     pub fn to_u16(self) -> InterpResult<'static, u16> {
-        self.to_unsigned_with_bit_width(16).map(|v| u16::try_from(v).unwrap())
+        self.to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u32`. Fails if the scalar is a pointer.
     pub fn to_u32(self) -> InterpResult<'static, u32> {
-        self.to_unsigned_with_bit_width(32).map(|v| u32::try_from(v).unwrap())
+        self.to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u64`. Fails if the scalar is a pointer.
     pub fn to_u64(self) -> InterpResult<'static, u64> {
-        self.to_unsigned_with_bit_width(64).map(|v| u64::try_from(v).unwrap())
+        self.to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce a `u128`. Fails if the scalar is a pointer.
     pub fn to_u128(self) -> InterpResult<'static, u128> {
-        self.to_unsigned_with_bit_width(128)
+        self.to_uint(Size::from_bits(128))
     }
 
+    /// Converts the scalar to produce a machine-pointer-sized unsigned integer.
+    /// Fails if the scalar is a pointer.
     pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> {
-        let b = self.to_bits(cx.data_layout().pointer_size)?;
+        let b = self.to_uint(cx.data_layout().pointer_size)?;
         Ok(u64::try_from(b).unwrap())
     }
 
+    /// Converts the scalar to produce a signed integer of the given size.
+    /// Fails if the scalar is a pointer.
     #[inline]
-    fn to_signed_with_bit_width(self, bits: u64) -> InterpResult<'static, i128> {
-        let sz = Size::from_bits(bits);
-        let b = self.to_bits(sz)?;
-        Ok(sz.sign_extend(b) as i128)
+    pub fn to_int(self, size: Size) -> InterpResult<'static, i128> {
+        let b = self.to_bits(size)?;
+        Ok(size.sign_extend(b) as i128)
     }
 
     /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer.
     pub fn to_i8(self) -> InterpResult<'static, i8> {
-        self.to_signed_with_bit_width(8).map(|v| i8::try_from(v).unwrap())
+        self.to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i16`. Fails if the scalar is a pointer.
     pub fn to_i16(self) -> InterpResult<'static, i16> {
-        self.to_signed_with_bit_width(16).map(|v| i16::try_from(v).unwrap())
+        self.to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i32`. Fails if the scalar is a pointer.
     pub fn to_i32(self) -> InterpResult<'static, i32> {
-        self.to_signed_with_bit_width(32).map(|v| i32::try_from(v).unwrap())
+        self.to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i64`. Fails if the scalar is a pointer.
     pub fn to_i64(self) -> InterpResult<'static, i64> {
-        self.to_signed_with_bit_width(64).map(|v| i64::try_from(v).unwrap())
+        self.to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap())
     }
 
     /// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer.
     pub fn to_i128(self) -> InterpResult<'static, i128> {
-        self.to_signed_with_bit_width(128)
+        self.to_int(Size::from_bits(128))
     }
 
+    /// Converts the scalar to produce a machine-pointer-sized signed integer.
+    /// Fails if the scalar is a pointer.
     pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> {
-        let sz = cx.data_layout().pointer_size;
-        let b = self.to_bits(sz)?;
-        let b = sz.sign_extend(b) as i128;
+        let b = self.to_int(cx.data_layout().pointer_size)?;
         Ok(i64::try_from(b).unwrap())
     }
 
@@ -456,11 +469,6 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
         // Going through `u64` to check size and truncation.
         Ok(Double::from_bits(self.to_u64()?.into()))
     }
-
-    // FIXME: Replace current `impl Display for Scalar` with `impl LowerHex`.
-    pub fn rustdoc_display(&self) -> String {
-        if let Scalar::Int(int) = self { int.to_string() } else { self.to_string() }
-    }
 }
 
 #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)]
@@ -494,7 +502,7 @@ impl<Tag: Provenance> fmt::Display for ScalarMaybeUninit<Tag> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"),
-            ScalarMaybeUninit::Scalar(s) => write!(f, "{}", s),
+            ScalarMaybeUninit::Scalar(s) => write!(f, "{:x}", s),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 5c5d0598781..359e4f5e581 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1435,8 +1435,7 @@ pub trait PrettyPrinter<'tcx>:
                 // relocations (we have an active `str` reference here). We don't use this
                 // result to affect interpreter execution.
                 let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
-                let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
-                p!(write("{:?}", s));
+                p!(write("{:?}", String::from_utf8_lossy(slice)));
                 Ok(self)
             }
             (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 227a9e37dbc..965e6a6ca3f 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -103,6 +103,16 @@ impl<'a> Parser<'a> {
             } else {
                 self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))
             }?;
+            if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(kw::Else) {
+                let bl = self.parse_block()?;
+                // Destructuring assignment ... else.
+                // This is not allowed, but point it out in a nice way.
+                let mut err = self.struct_span_err(
+                    e.span.to(bl.span),
+                    "<assignment> ... else { ... } is not allowed",
+                );
+                err.emit();
+            }
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
             self.error_outer_attrs(&attrs.take_for_recovery());
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index b2aa72e0e67..8b76f3f7151 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -160,20 +160,12 @@ fn overlap<'cx, 'tcx>(
     );
 
     selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
-        overlap_within_probe(
-            selcx,
-            skip_leak_check,
-            impl1_def_id,
-            impl2_def_id,
-            overlap_mode,
-            snapshot,
-        )
+        overlap_within_probe(selcx, impl1_def_id, impl2_def_id, overlap_mode, snapshot)
     })
 }
 
 fn overlap_within_probe<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    skip_leak_check: SkipLeakCheck,
     impl1_def_id: DefId,
     impl2_def_id: DefId,
     overlap_mode: OverlapMode,
@@ -207,11 +199,11 @@ fn overlap_within_probe<'cx, 'tcx>(
         }
     }
 
-    if !skip_leak_check.is_yes() {
-        if infcx.leak_check(true, snapshot).is_err() {
-            debug!("overlap: leak check failed");
-            return None;
-        }
+    // We disable the leak when when creating the `snapshot` by using
+    // `infcx.probe_maybe_disable_leak_check`.
+    if infcx.leak_check(true, snapshot).is_err() {
+        debug!("overlap: leak check failed");
+        return None;
     }
 
     let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 1989184f48f..362d669f867 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -314,7 +314,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
             return ProcessResult::Unchanged;
         }
 
-        self.progress_changed_obligations(pending_obligation)
+        self.process_changed_obligations(pending_obligation)
     }
 
     fn process_backedge<'c, I>(
@@ -338,7 +338,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
     // actually uses this, so move this part of the code
     // out of that loop.
     #[inline(never)]
-    fn progress_changed_obligations(
+    fn process_changed_obligations(
         &mut self,
         pending_obligation: &mut PendingPredicateObligation<'tcx>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index d92f26288c1..4d7c9ef89e6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -389,7 +389,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         for bound in matching_bounds {
             // FIXME(oli-obk): it is suspicious that we are dropping the constness and
             // polarity here.
-            let wc = self.evaluate_where_clause(stack, bound.map_bound(|t| t.trait_ref))?;
+            let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?;
             if wc.may_apply() {
                 candidates.vec.push(ParamCandidate(bound));
             }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0ed29036e4b..5b646c6d447 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1481,7 +1481,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .map_err(|_| ())
     }
 
-    fn evaluate_where_clause<'o>(
+    fn where_clause_may_apply<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
         where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs
index 6b62236b32f..f29d3e1e98b 100644
--- a/library/core/src/future/future.rs
+++ b/library/core/src/future/future.rs
@@ -5,7 +5,7 @@ use crate::ops;
 use crate::pin::Pin;
 use crate::task::{Context, Poll};
 
-/// A future represents an asynchronous computation.
+/// A future represents an asynchronous computation obtained by use of [`async`].
 ///
 /// A future is a value that might not have finished computing yet. This kind of
 /// "asynchronous value" makes it possible for a thread to continue doing useful
@@ -23,6 +23,7 @@ use crate::task::{Context, Poll};
 /// When using a future, you generally won't call `poll` directly, but instead
 /// `.await` the value.
 ///
+/// [`async`]: ../../std/keyword.async.html
 /// [`Waker`]: crate::task::Waker
 #[doc(notable_trait)]
 #[must_use = "futures do nothing unless you `.await` or poll them"]
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index 88db584aefd..9b89f766c67 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -1,6 +1,13 @@
 #![stable(feature = "futures_api", since = "1.36.0")]
 
-//! Asynchronous values.
+//! Asynchronous basic functionality.
+//!
+//! Please see the fundamental [`async`] and [`await`] keywords and the [async book]
+//! for more information on asynchronous programming in Rust.
+//!
+//! [`async`]: ../../std/keyword.async.html
+//! [`await`]: ../../std/keyword.await.html
+//! [async book]: https://rust-lang.github.io/async-book/
 
 use crate::{
     ops::{Generator, GeneratorState},
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index ebfd12d1533..e2b0e90e2bf 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -805,7 +805,7 @@ impl<T: ?Sized> Pin<&'static T> {
     ///
     /// This is safe, because `T` is borrowed for the `'static` lifetime, which
     /// never ends.
-    #[stable(feature = "pin_static_ref", since = "1.60.0")]
+    #[stable(feature = "pin_static_ref", since = "1.61.0")]
     #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
     pub const fn static_ref(r: &'static T) -> Pin<&'static T> {
         // SAFETY: The 'static borrow guarantees the data will not be
@@ -858,7 +858,7 @@ impl<T: ?Sized> Pin<&'static mut T> {
     ///
     /// This is safe, because `T` is borrowed for the `'static` lifetime, which
     /// never ends.
-    #[stable(feature = "pin_static_ref", since = "1.60.0")]
+    #[stable(feature = "pin_static_ref", since = "1.61.0")]
     #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
     pub const fn static_mut(r: &'static mut T) -> Pin<&'static mut T> {
         // SAFETY: The 'static borrow guarantees the data will not be
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 35d230eee96..5b76259afc1 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -2203,17 +2203,18 @@ mod where_keyword {}
 ///
 /// Use `async` in front of `fn`, `closure`, or a `block` to turn the marked code into a `Future`.
 /// As such the code will not be run immediately, but will only be evaluated when the returned
-/// future is `.await`ed.
+/// future is [`.await`]ed.
 ///
-/// We have written an [async book] detailing async/await and trade-offs compared to using threads.
+/// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads.
 ///
 /// ## Editions
 ///
 /// `async` is a keyword from the 2018 edition onwards.
 ///
-/// It is available for use in stable rust from version 1.39 onwards.
+/// It is available for use in stable Rust from version 1.39 onwards.
 ///
 /// [`Future`]: future::Future
+/// [`.await`]: ../std/keyword.await.html
 /// [async book]: https://rust-lang.github.io/async-book/
 mod async_keyword {}
 
@@ -2221,19 +2222,20 @@ mod async_keyword {}
 //
 /// Suspend execution until the result of a [`Future`] is ready.
 ///
-/// `.await`ing a future will suspend the current function's execution until the `executor`
+/// `.await`ing a future will suspend the current function's execution until the executor
 /// has run the future to completion.
 ///
-/// Read the [async book] for details on how async/await and executors work.
+/// Read the [async book] for details on how [`async`]/`await` and executors work.
 ///
 /// ## Editions
 ///
 /// `await` is a keyword from the 2018 edition onwards.
 ///
-/// It is available for use in stable rust from version 1.39 onwards.
+/// It is available for use in stable Rust from version 1.39 onwards.
 ///
 /// [`Future`]: future::Future
 /// [async book]: https://rust-lang.github.io/async-book/
+/// [`async`]: ../std/keyword.async.html
 mod await_keyword {}
 
 #[doc(keyword = "dyn")]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 2628afd4237..5dc586d3a2a 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -366,6 +366,7 @@ extern crate unwind;
 
 #[doc(masked)]
 #[allow(unused_extern_crates)]
+#[cfg(feature = "miniz_oxide")]
 extern crate miniz_oxide;
 
 // During testing, this crate is not actually the "real" std library, but rather
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index e17de0ba49e..53226977fd8 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -17,7 +17,6 @@ use std::process::{exit, Command, Stdio};
 use std::str;
 
 use build_helper::{output, t, up_to_date};
-use filetime::FileTime;
 use serde::Deserialize;
 
 use crate::builder::Cargo;
@@ -1334,8 +1333,9 @@ pub fn run_cargo(
                     .map(|s| s.starts_with('-') && s.ends_with(&extension[..]))
                     .unwrap_or(false)
         });
-        let max = candidates
-            .max_by_key(|&&(_, _, ref metadata)| FileTime::from_last_modification_time(metadata));
+        let max = candidates.max_by_key(|&&(_, _, ref metadata)| {
+            metadata.modified().expect("mtime should be available on all relevant OSes")
+        });
         let path_to_add = match max {
             Some(triple) => triple.0.to_str().unwrap(),
             None => panic!("no output generated for {:?} {:?}", prefix, extension),
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c2d1d4756fd..20eea32560b 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -302,11 +302,7 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: ty::Const<'_>) -> S
     // For all other types, fallback to the original `pretty_print_const`.
     match (ct.val(), ct.ty().kind()) {
         (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Uint(ui)) => {
-            format!(
-                "{}{}",
-                format_integer_with_underscore_sep(&int.rustdoc_display()),
-                ui.name_str()
-            )
+            format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
         }
         (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Int(i)) => {
             let ty = tcx.lift(ct.ty()).unwrap();
diff --git a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
index 03f827f63f3..9480566897f 100644
--- a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
@@ -2,63 +2,69 @@
 + // MIR for `main` after ConstProp
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/invalid_constant.rs:13:11: 13:11
-      let _1: main::InvalidChar;           // in scope 0 at $DIR/invalid_constant.rs:19:9: 19:22
-      let mut _3: main::InvalidTag;        // in scope 0 at $DIR/invalid_constant.rs:26:25: 26:46
-      let mut _5: main::NoVariants;        // in scope 0 at $DIR/invalid_constant.rs:33:35: 33:56
+      let mut _0: ();                      // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11
+      let _1: main::InvalidChar;           // in scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
+      let mut _3: main::InvalidTag;        // in scope 0 at $DIR/invalid_constant.rs:28:25: 28:46
+      let mut _5: main::NoVariants;        // in scope 0 at $DIR/invalid_constant.rs:35:35: 35:56
       scope 1 {
-          debug _invalid_char => _1;       // in scope 1 at $DIR/invalid_constant.rs:19:9: 19:22
-          let _2: [main::InvalidTag; 1];   // in scope 1 at $DIR/invalid_constant.rs:26:9: 26:21
+          debug _invalid_char => _1;       // in scope 1 at $DIR/invalid_constant.rs:21:9: 21:22
+          let _2: [main::InvalidTag; 1];   // in scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
           scope 2 {
-              debug _invalid_tag => _2;    // in scope 2 at $DIR/invalid_constant.rs:26:9: 26:21
-              let _4: [main::NoVariants; 1]; // in scope 2 at $DIR/invalid_constant.rs:33:9: 33:31
+              debug _invalid_tag => _2;    // in scope 2 at $DIR/invalid_constant.rs:28:9: 28:21
+              let _4: [main::NoVariants; 1]; // in scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
               scope 3 {
-                  debug _enum_without_variants => _4; // in scope 3 at $DIR/invalid_constant.rs:33:9: 33:31
+                  debug _enum_without_variants => _4; // in scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
+                  let _6: main::Str<"���">; // in scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
+                  scope 4 {
+                      debug _non_utf8_str => _6; // in scope 4 at $DIR/invalid_constant.rs:39:9: 39:22
+                  }
               }
           }
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/invalid_constant.rs:19:9: 19:22
--         _1 = const { InvalidChar { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:19:25: 19:64
-+         _1 = const InvalidChar { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:19:25: 19:64
+          StorageLive(_1);                 // scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
+-         _1 = const { InvalidChar { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
++         _1 = const InvalidChar { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:21:25: 21:64
                                            // ty::Const
                                            // + ty: main::InvalidChar
 -                                          // + val: Unevaluated(main::{constant#0}, [main::InvalidChar], None)
 +                                          // + val: Value(Scalar(0x00110001))
                                            // mir::Constant
-                                           // + span: $DIR/invalid_constant.rs:19:25: 19:64
+                                           // + span: $DIR/invalid_constant.rs:21:25: 21:64
 -                                          // + literal: Const { ty: main::InvalidChar, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ invalid_constant[726d]::main::{constant#0}), const_param_did: None }, substs: [main::InvalidChar], promoted: None }) }
 +                                          // + literal: Const { ty: main::InvalidChar, val: Value(Scalar(0x00110001)) }
-          StorageLive(_2);                 // scope 1 at $DIR/invalid_constant.rs:26:9: 26:21
-          StorageLive(_3);                 // scope 1 at $DIR/invalid_constant.rs:26:25: 26:46
-          (_3.0: u32) = const 4_u32;       // scope 1 at $DIR/invalid_constant.rs:26:25: 26:46
--         _2 = [move _3];                  // scope 1 at $DIR/invalid_constant.rs:26:24: 26:47
-+         _2 = [const InvalidTag { int: 4_u32, e: Scalar(0x00000004): E }]; // scope 1 at $DIR/invalid_constant.rs:26:24: 26:47
+          StorageLive(_2);                 // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
+          StorageLive(_3);                 // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
+          (_3.0: u32) = const 4_u32;       // scope 1 at $DIR/invalid_constant.rs:28:25: 28:46
+-         _2 = [move _3];                  // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
++         _2 = [const InvalidTag { int: 4_u32, e: Scalar(0x00000004): E }]; // scope 1 at $DIR/invalid_constant.rs:28:24: 28:47
 +                                          // ty::Const
 +                                          // + ty: main::InvalidTag
 +                                          // + val: Value(Scalar(0x00000004))
 +                                          // mir::Constant
-+                                          // + span: $DIR/invalid_constant.rs:26:24: 26:47
++                                          // + span: $DIR/invalid_constant.rs:28:24: 28:47
 +                                          // + literal: Const { ty: main::InvalidTag, val: Value(Scalar(0x00000004)) }
-          StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:26:46: 26:47
-          StorageLive(_4);                 // scope 2 at $DIR/invalid_constant.rs:33:9: 33:31
-          StorageLive(_5);                 // scope 2 at $DIR/invalid_constant.rs:33:35: 33:56
-          (_5.0: u32) = const 0_u32;       // scope 2 at $DIR/invalid_constant.rs:33:35: 33:56
--         _4 = [move _5];                  // scope 2 at $DIR/invalid_constant.rs:33:34: 33:57
-+         _4 = [const NoVariants { int: 0_u32, empty: Scalar(<ZST>): Empty }]; // scope 2 at $DIR/invalid_constant.rs:33:34: 33:57
+          StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:28:46: 28:47
+          StorageLive(_4);                 // scope 2 at $DIR/invalid_constant.rs:35:9: 35:31
+          StorageLive(_5);                 // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
+          (_5.0: u32) = const 0_u32;       // scope 2 at $DIR/invalid_constant.rs:35:35: 35:56
+-         _4 = [move _5];                  // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
++         _4 = [const NoVariants { int: 0_u32, empty: Scalar(<ZST>): Empty }]; // scope 2 at $DIR/invalid_constant.rs:35:34: 35:57
 +                                          // ty::Const
 +                                          // + ty: main::NoVariants
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/invalid_constant.rs:33:34: 33:57
++                                          // + span: $DIR/invalid_constant.rs:35:34: 35:57
 +                                          // + literal: Const { ty: main::NoVariants, val: Value(Scalar(0x00000000)) }
-          StorageDead(_5);                 // scope 2 at $DIR/invalid_constant.rs:33:56: 33:57
-          nop;                             // scope 0 at $DIR/invalid_constant.rs:13:11: 34:2
-          StorageDead(_4);                 // scope 2 at $DIR/invalid_constant.rs:34:1: 34:2
-          StorageDead(_2);                 // scope 1 at $DIR/invalid_constant.rs:34:1: 34:2
-          StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:34:1: 34:2
-          return;                          // scope 0 at $DIR/invalid_constant.rs:34:2: 34:2
+          StorageDead(_5);                 // scope 2 at $DIR/invalid_constant.rs:35:56: 35:57
+          StorageLive(_6);                 // scope 3 at $DIR/invalid_constant.rs:39:9: 39:22
+          nop;                             // scope 0 at $DIR/invalid_constant.rs:15:11: 42:2
+          StorageDead(_6);                 // scope 3 at $DIR/invalid_constant.rs:42:1: 42:2
+          StorageDead(_4);                 // scope 2 at $DIR/invalid_constant.rs:42:1: 42:2
+          StorageDead(_2);                 // scope 1 at $DIR/invalid_constant.rs:42:1: 42:2
+          StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:42:1: 42:2
+          return;                          // scope 0 at $DIR/invalid_constant.rs:42:2: 42:2
       }
   }
   
diff --git a/src/test/mir-opt/const_prop/invalid_constant.rs b/src/test/mir-opt/const_prop/invalid_constant.rs
index e0879cf4800..492ef404916 100644
--- a/src/test/mir-opt/const_prop/invalid_constant.rs
+++ b/src/test/mir-opt/const_prop/invalid_constant.rs
@@ -1,6 +1,8 @@
 // Verify that we can pretty print invalid constants.
 
+#![feature(adt_const_params)]
 #![feature(inline_const)]
+#![allow(incomplete_features)]
 
 #[derive(Copy, Clone)]
 #[repr(u32)]
@@ -31,4 +33,10 @@ fn main() {
         empty: Empty,
     }
     let _enum_without_variants = [NoVariants { int: 0 }];
+
+    // A non-UTF-8 string slice. Regression test for #75763 and #78520.
+    struct Str<const S: &'static str>;
+    let _non_utf8_str: Str::<{
+        unsafe { std::mem::transmute::<&[u8], &str>(&[0xC0, 0xC1, 0xF5]) }
+    }>;
 }
diff --git a/src/test/ui/const-generics/issues/issue-75763.rs b/src/test/ui/const-generics/issues/issue-75763.rs
deleted file mode 100644
index 214a04b8a6b..00000000000
--- a/src/test/ui/const-generics/issues/issue-75763.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-// ignore-test
-// FIXME(const_generics): This test causes an ICE after reverting #76030.
-#![feature(adt_const_params)]
-#![allow(incomplete_features)]
-
-
-struct Bug<const S: &'static str>;
-
-fn main() {
-    let b: Bug::<{
-        unsafe {
-            // FIXME(adt_const_params): Decide on how to deal with invalid values as const params.
-            std::mem::transmute::<&[u8], &str>(&[0xC0, 0xC1, 0xF5])
-        }
-    }>;
-}
diff --git a/src/test/ui/let-else/let-else-destructuring.rs b/src/test/ui/let-else/let-else-destructuring.rs
new file mode 100644
index 00000000000..9a09c414ac8
--- /dev/null
+++ b/src/test/ui/let-else/let-else-destructuring.rs
@@ -0,0 +1,18 @@
+#![feature(let_else)]
+#[derive(Debug)]
+enum Foo {
+    Done,
+    Nested(Option<&'static Foo>),
+}
+
+fn walk(mut value: &Foo) {
+    loop {
+        println!("{:?}", value);
+        &Foo::Nested(Some(value)) = value else { break }; //~ ERROR invalid left-hand side of assignment
+        //~^ERROR <assignment> ... else { ... } is not allowed
+    }
+}
+
+fn main() {
+    walk(&Foo::Done);
+}
diff --git a/src/test/ui/let-else/let-else-destructuring.stderr b/src/test/ui/let-else/let-else-destructuring.stderr
new file mode 100644
index 00000000000..95efb711682
--- /dev/null
+++ b/src/test/ui/let-else/let-else-destructuring.stderr
@@ -0,0 +1,17 @@
+error: <assignment> ... else { ... } is not allowed
+  --> $DIR/let-else-destructuring.rs:11:9
+   |
+LL |         &Foo::Nested(Some(value)) = value else { break };
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/let-else-destructuring.rs:11:35
+   |
+LL |         &Foo::Nested(Some(value)) = value else { break };
+   |         ------------------------- ^
+   |         |
+   |         cannot assign to this expression
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0070`.