From 5cc292eb1dcb22bd6a46478165b5820f8177c87f Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 19 Feb 2022 00:47:43 +0100 Subject: [PATCH 01/14] rustc_const_eval: adopt let else in more places --- .../src/const_eval/eval_queries.rs | 5 +- .../src/const_eval/machine.rs | 15 ++--- .../src/interpret/eval_context.rs | 14 ++--- .../rustc_const_eval/src/interpret/intern.rs | 27 ++++----- .../rustc_const_eval/src/interpret/memory.rs | 60 +++++++++---------- .../rustc_const_eval/src/interpret/operand.rs | 15 ++--- .../rustc_const_eval/src/interpret/place.rs | 11 ++-- .../rustc_const_eval/src/interpret/step.rs | 15 ++--- .../src/interpret/terminator.rs | 7 +-- .../src/interpret/validity.rs | 9 +-- .../src/transform/check_consts/check.rs | 7 +-- .../src/transform/promote_consts.rs | 15 ++--- .../rustc_const_eval/src/util/alignment.rs | 9 +-- 13 files changed, 86 insertions(+), 123 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 bfb9c40be57df..9b58e279d2a34 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 e157b58405212..b2019ce40c3ea 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 1b86bcfa8c9ad..ab50c709143fd 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 a1dd587c17ab5..b1f50bc56c908 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 4aa3c83cc0243..a1f94b095cfb8 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>, 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 *destiantion*. + 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 ec5eafcd63318..60e915a7eee11 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 7b06ffaf15d02..e9b2df53a3313 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>> + '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 57ba9b4099232..0701e0ded9703 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 f3910c9765d2e..8094bf0cf2e2f 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 4060bee7e056c..c82594cf4a91c 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -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 095c8f84f41ad..652f1c94a6149 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 cacc0018fe937..30764f689c95c 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 73adc60577bfc..e4528b6890783 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; From 297364eb07a3f3d1dfab35fc6187202293ecffe0 Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Sat, 19 Feb 2022 17:17:40 +0100 Subject: [PATCH 02/14] Some improvements to the async docs --- library/core/src/future/future.rs | 3 ++- library/core/src/future/mod.rs | 9 ++++++++- library/std/src/keyword_docs.rs | 14 ++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 09d8a2aac26e9..906e48cb62bf3 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 7a3af70d6d97c..dfa339f44d22e 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/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index a370485102e35..ed32e2f4f67a6 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")] From f233323f6d4529322613de04289a8d6efc2ab618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 19 Feb 2022 00:00:00 +0000 Subject: [PATCH 03/14] Gracefully handle non-UTF-8 string slices when pretty printing --- compiler/rustc_middle/src/ty/print/pretty.rs | 3 +- .../invalid_constant.main.ConstProp.diff | 70 ++++++++++--------- .../mir-opt/const_prop/invalid_constant.rs | 8 +++ .../ui/const-generics/issues/issue-75763.rs | 16 ----- 4 files changed, 47 insertions(+), 50 deletions(-) delete mode 100644 src/test/ui/const-generics/issues/issue-75763.rs diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index fbf30b58818f3..636b571a922c1 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1443,8 +1443,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/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff index 03f827f63f37f..9480566897f8d 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(): 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(): 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 e0879cf4800ca..492ef404916d4 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; + 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 214a04b8a6bed..0000000000000 --- 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; - -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]) - } - }>; -} From 72a7e731e16dab4f0638a3155a22c1d14b18c055 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 20 Feb 2022 06:42:20 -0800 Subject: [PATCH 04/14] Update pin_static_ref stabilization version. --- library/core/src/pin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index ebfd12d15337c..e2b0e90e2bf7d 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -805,7 +805,7 @@ impl 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 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 From c358ffe7b378923830937c2317efd5e0763b96e3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 20 Feb 2022 16:43:21 +0100 Subject: [PATCH 05/14] Implement LowerHex on Scalar to clean up their display in rustdoc --- .../rustc_const_eval/src/interpret/validity.rs | 2 +- .../rustc_middle/src/mir/interpret/error.rs | 2 +- .../rustc_middle/src/mir/interpret/value.rs | 18 +++++++++++------- src/librustdoc/clean/utils.rs | 6 +----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 4060bee7e056c..a41ed0b469bd8 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) => diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e9a857d09124f..c5866924eda43 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 aa8730bf9cdde..abcf416109ba6 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -153,7 +153,16 @@ impl fmt::Display for Scalar { 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 fmt::LowerHex for Scalar { + 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), } } } @@ -456,11 +465,6 @@ impl<'tcx, Tag: Provenance> Scalar { // 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 +498,7 @@ impl fmt::Display for ScalarMaybeUninit { 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/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index fe1992a5d7e31..1d312df1f7858 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(); From b45cb09d3068f45d5b752ba46034c8dbc92138eb Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 Feb 2022 16:59:20 +0100 Subject: [PATCH 06/14] Use Metadata::modified instead of FileTime::from_last_modification_time in run_cargo Metadata::modified works in all platforms supported by the filetime crate. This changes brings rustbuild a tiny bit closer towards dropping the filetime dependency. --- src/bootstrap/compile.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e17de0ba49ebc..53226977fd881 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), From 1e3609b1ba6cc83a7a7897202ddfca42e5dbf0ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Feb 2022 21:31:02 -0500 Subject: [PATCH 07/14] CTFE engine: Scalar: expose size-generic to_(u)int methods --- .../rustc_middle/src/mir/interpret/value.rs | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index aa8730bf9cdde..9bea6ccec708b 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -370,78 +370,82 @@ impl<'tcx, Tag: Provenance> Scalar { } } + /// 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()) } From 413f3f787c9e8e4c2cb8abd73cdc16cb8d175590 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 21 Feb 2022 08:28:20 +0100 Subject: [PATCH 08/14] Fix typo Co-authored-by: lcnr --- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index a1f94b095cfb8..73e7d862ad641 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1047,7 +1047,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // 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 Some((dest_alloc_id, dest_offset, dest)) = dest_parts else { - // Zero-sized *destiantion*. + // Zero-sized *destination*. return Ok(()); }; From 76ea56667703ac06689ff1d6fba5d170fa7392a7 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 21 Feb 2022 08:27:24 +0100 Subject: [PATCH 09/14] Better error if the user tries to do assignment ... else --- compiler/rustc_parse/src/parser/stmt.rs | 10 ++++++++++ src/test/ui/let-else/let-else-destructuring.rs | 18 ++++++++++++++++++ .../ui/let-else/let-else-destructuring.stderr | 17 +++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/test/ui/let-else/let-else-destructuring.rs create mode 100644 src/test/ui/let-else/let-else-destructuring.stderr diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 227a9e37dbcb4..965e6a6ca3f27 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), + " ... 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/src/test/ui/let-else/let-else-destructuring.rs b/src/test/ui/let-else/let-else-destructuring.rs new file mode 100644 index 0000000000000..9a09c414ac80f --- /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 ... 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 0000000000000..95efb7116829e --- /dev/null +++ b/src/test/ui/let-else/let-else-destructuring.stderr @@ -0,0 +1,17 @@ +error: ... 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`. From 239f33ea5bd5aa7b3af61f2e1226949350f2b428 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 21 Feb 2022 10:23:36 +0100 Subject: [PATCH 10/14] add comment --- compiler/rustc_infer/src/infer/region_constraints/leak_check.rs | 1 + 1 file changed, 1 insertion(+) 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 36d18aebfe2a0..817aaf10053ef 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>, From 15e95c0b7fe5d836db3911c7a83e9afbed84c39f Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 21 Feb 2022 10:26:25 +0100 Subject: [PATCH 11/14] rename function --- .../src/traits/select/candidate_assembly.rs | 2 +- compiler/rustc_trait_selection/src/traits/select/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 d92f26288c14e..4d7c9ef89e62b 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 ad31751e6bbda..4f804069df997 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>, From ec0a0ca3f496746c188373bf2530559ec9973c19 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 21 Feb 2022 10:40:41 +0100 Subject: [PATCH 12/14] don't check for the leak_check twice --- .../src/traits/coherence.rs | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index b2aa72e0e6741..8b76f3f715106 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(); From 6a1f5eab83eda92bbdad3f0e680f4a32f5c8a2a1 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 21 Feb 2022 11:56:36 +0100 Subject: [PATCH 13/14] obligation forest docs --- .../rustc_data_structures/src/obligation_forest/mod.rs | 9 +++++---- compiler/rustc_infer/src/infer/higher_ranked/mod.rs | 4 +++- compiler/rustc_trait_selection/src/traits/fulfill.rs | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 25b7a84b3a069..5fe2a1fb84bd7 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, fn(usize) -> ObligationTreeId>; pub struct ObligationForest { - /// 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>, @@ -146,10 +146,11 @@ pub struct ObligationForest { /// 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, - /// 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, 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 82454b89156a6..652f5abab151f 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_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1989184f48f0e..362d669f867e0 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, FulfillmentErrorCode<'tcx>> { From 910d46fd60686e031e82ee87dec14f8002f5c8f3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 21 Feb 2022 17:27:55 +0100 Subject: [PATCH 14/14] Correctly handle miniz_oxide extern crate declaration --- library/std/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 2628afd42379e..5dc586d3a2adf 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