]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #94225 - matthiaskrgr:rollup-0728x8n, r=matthiaskrgr
authorbors <bors@rust-lang.org>
Mon, 21 Feb 2022 22:53:45 +0000 (22:53 +0000)
committerbors <bors@rust-lang.org>
Mon, 21 Feb 2022 22:53:45 +0000 (22:53 +0000)
Rollup of 10 pull requests

Successful merges:

 - #91192 (Some improvements to the async docs)
 - #94143 (rustc_const_eval: adopt let else in more places)
 - #94156 (Gracefully handle non-UTF-8 string slices when pretty printing)
 - #94186 (Update pin_static_ref stabilization version.)
 - #94189 (Implement LowerHex on Scalar to clean up their display in rustdoc)
 - #94190 (Use Metadata::modified instead of FileTime::from_last_modification_ti…)
 - #94203 (CTFE engine: Scalar: expose size-generic to_(u)int methods)
 - #94211 (Better error if the user tries to do assignment ... else)
 - #94215 (trait system: comments and small nonfunctional changes)
 - #94220 (Correctly handle miniz_oxide extern crate declaration)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup

36 files changed:
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intern.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/interpret/terminator.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_const_eval/src/util/alignment.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_infer/src/infer/higher_ranked/mod.rs
compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/interpret/value.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
library/core/src/future/future.rs
library/core/src/future/mod.rs
library/core/src/pin.rs
library/std/src/keyword_docs.rs
library/std/src/lib.rs
src/bootstrap/compile.rs
src/librustdoc/clean/utils.rs
src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
src/test/mir-opt/const_prop/invalid_constant.rs
src/test/ui/const-generics/issues/issue-75763.rs [deleted file]
src/test/ui/let-else/let-else-destructuring.rs [new file with mode: 0644]
src/test/ui/let-else/let-else-destructuring.stderr [new file with mode: 0644]

index 11eda987b977490e69e49836e9a150c816773e6f..533c32f807df6d5fbb1325a21401f6f63bb4fc88 100644 (file)
@@ -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);
index e157b584052128790b90db8300725e56b7fcf7ad..b2019ce40c3eaa2d2889d70ab2568b07d99d148b 100644 (file)
@@ -318,15 +318,12 @@ fn call_intrinsic(
         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 => {
index 1b86bcfa8c9ad6ed9cef72d69ff896226e79043e..ab50c709143fd0dc0590f086fd1c491bc145f82d 100644 (file)
@@ -631,15 +631,11 @@ pub(super) fn size_and_align_of(
                 // 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`
index a1dd587c17ab5c6921ee428c64a407c11461b0e8..b1f50bc56c908c88a2c5d5afa682692b04d8e0a7 100644 (file)
@@ -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.
index 4aa3c83cc024366bebdd71dd4332dd5976704057..73e7d862ad64186cacb0a7d6f22b4c167f79d600 100644 (file)
@@ -291,21 +291,18 @@ pub fn deallocate(
             );
         }
 
-        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 @@ pub fn read_bytes(
         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 @@ pub fn write_bytes(
         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 @@ pub fn copy_repeatedly(
         // 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
index ec5eafcd6331821b2312d00eab57cde8bd4ee065..60e915a7eee113ae26becdc2e30edc132c209a8a 100644 (file)
@@ -258,15 +258,12 @@ fn try_read_immediate_from_mplace(
             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 {
index 7b06ffaf15d02f86f7917d36750cf663878805ef..e9b2df53a331370f1a42ccc1f24b3766eda0b044 100644 (file)
@@ -420,9 +420,8 @@ pub(super) fn mplace_array_fields<'a>(
     ) -> 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 @@ fn write_immediate_to_mplace_no_validate(
 
         // 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
index 57ba9b4099232f0c7719b9781748e0c23c179c14..0701e0ded9703f89a2af1cb0fd746fe192168f77 100644 (file)
@@ -46,15 +46,12 @@ pub fn step(&mut self) -> InterpResult<'tcx, bool> {
             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];
 
index f3910c9765d2e65c91685ff5339ceba640375a80..8094bf0cf2e2f7361ec1819a40ce85e74dc09641 100644 (file)
@@ -321,10 +321,9 @@ pub(crate) fn eval_fn_call(
             | 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
index e95e327618f0bf8fd9bcf7fad03fe08ec8deb7dc..19c6449078d5b236d9a6b40b22ad6eae0ad8c098 100644 (file)
@@ -697,7 +697,7 @@ fn read_discriminant(
                 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 @@ fn visit_aggregate(
                 // 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);
index 095c8f84f41adb28eb8e1c3e97f7651fb1d19f1f..652f1c94a6149f06d406a512c1cab6b9c9834e49 100644 (file)
@@ -134,11 +134,8 @@ fn in_return_place(
             .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);
index cacc0018fe93772bacd6e28caf08ece6bfb74a22..30764f689c95c379df9a00ac94c4027044c56c1a 100644 (file)
@@ -747,15 +747,12 @@ fn promote_temp(&mut self, temp: Local) -> Local {
         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
+                    );
                 };
 
                 (
index 73adc60577bfcf41e43f243ba057f77256c8d112..e4528b68907838120b98a9909ce029bb42cda750 100644 (file)
@@ -15,12 +15,9 @@ pub fn is_disaligned<'tcx, L>(
     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;
index 25b7a84b3a06929fa5c0df1c8f1c3f92848727e0..5fe2a1fb84bd76a8521db89806ed981c53308325 100644 (file)
@@ -132,11 +132,11 @@ pub enum ProcessResult<O, E> {
     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,
index 82454b89156a6110d5b7a5199aab761ad56e6529..652f5abab151f6659b6bf277ba8bd6e7f51cb358 100644 (file)
@@ -123,7 +123,9 @@ pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T
         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,
index 36d18aebfe2a06630dcb0920770af3e913409460..817aaf10053efdf1812244e07f0fde928e6da47b 100644 (file)
@@ -100,6 +100,7 @@ pub fn leak_check(
 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>,
index e9a857d09124f4cad822cd3213adb0625d761891..c5866924eda43d2408b7a5a9a0d804779f095560 100644 (file)
@@ -370,7 +370,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             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)
             }
index aa8730bf9cddec6b4a12a4008cc4244a78d8106e..acf7847de54169453403e57d5a37b5f4bab963d7 100644 (file)
@@ -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 @@ pub fn to_char(self) -> InterpResult<'tcx, char> {
         }
     }
 
+    /// 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 @@ pub fn to_f64(self) -> InterpResult<'static, Double> {
         // 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),
         }
     }
 }
index 5c5d059878179e0650419b5c0a407d390363cb23..359e4f5e58147c4e2f28d42e507459504273a541 100644 (file)
@@ -1435,8 +1435,7 @@ fn pretty_print_const_value(
                 // 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 => {
index 227a9e37dbcb4e422184cc2010ba4292e77b7afa..965e6a6ca3f2727c8a8ec50019c6ea94e68ed695 100644 (file)
@@ -103,6 +103,16 @@ pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<
             } 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());
index b2aa72e0e67416e4f2b36713e0bcdda14c769440..8b76f3f7151063de3cd84d48bce7b9e8642f772e 100644 (file)
@@ -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();
index 1989184f48f0e26c434e5edc8d4747dbd302e58f..362d669f867e01ac8d86d147553a417b8e3479fa 100644 (file)
@@ -314,7 +314,7 @@ fn process_obligation(
             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>> {
index d92f26288c14e8e94dcdd7af4c12f7f714e16713..4d7c9ef89e62b4915e80d762b3ae8f2db8e9da3a 100644 (file)
@@ -389,7 +389,7 @@ fn assemble_candidates_from_caller_bounds<'o>(
         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));
             }
index 0ed29036e4bdbbcd66ff3a04b118c1b94ef447b7..5b646c6d4477c55231f62cec6548468992ce810e 100644 (file)
@@ -1481,7 +1481,7 @@ fn match_normalize_trait_ref(
             .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>,
index 6b62236b32fafba661caf2dc1a2ae098029f6d73..f29d3e1e98b724777673fef70d399b4408eb2baa 100644 (file)
@@ -5,7 +5,7 @@
 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 @@
 /// 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"]
index 88db584aefd08df0a75ccaca7efab0d29fa8edeb..9b89f766c67bf648779c63e1ddd4df8a555232dc 100644 (file)
@@ -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},
index ebfd12d15337cd9d4701dae97bbddae947d5e323..e2b0e90e2bf7ddfcfae9d6e3d18faa39dcb0a76e 100644 (file)
@@ -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
index 35d230eee96275ac8fd277398c9bc294a7637849..5b76259afc11de8c0bf7f6830e1c33be675fae3e 100644 (file)
@@ -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")]
index 2628afd42379e0bd1a08538e3540801c0868460c..5dc586d3a2adf61ab1fc87f01cb7c26d598064d4 100644 (file)
 
 #[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
index e17de0ba49ebc464d949bc3ca2a8495647b4b525..53226977fd881fae5cb06e4e0f2d6301e3bcaa3f 100644 (file)
@@ -17,7 +17,6 @@
 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),
index c2d1d4756fd8172d86cf8562e4544ca849d90f86..20eea32560b27fdb5f00c5a0e87d2f7a441f9fc0 100644 (file)
@@ -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();
index 03f827f63f37fe43be26ff06ffea1a069d249d7d..9480566897f8d1003e0d6dbd2f0416ae0868ec34 100644 (file)
@@ -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
       }
   }
   
index e0879cf4800caa4219243a89c5f997fd73a26745..492ef404916d49f9f04d62b909e042875357cdc2 100644 (file)
@@ -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 @@ union NoVariants {
         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 (file)
index 214a04b..0000000
+++ /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 (file)
index 0000000..9a09c41
--- /dev/null
@@ -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 (file)
index 0000000..95efb71
--- /dev/null
@@ -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`.