From 0c6e8b61b6a4df87216570931c687874f28022fd Mon Sep 17 00:00:00 2001 From: Philippe Nadon Date: Sat, 8 Aug 2020 07:53:47 -0600 Subject: [PATCH 01/13] Miri: Renamed "undef" to "uninit" Renamed remaining references to "undef" to "uninit" when referring to Miri. Impacted directories are: - src/librustc_codegen_llvm/consts.rs - src/librustc_middle/mir/interpret/ - src/librustc_middle/ty/print/pretty.rs - src/librustc_mir/ - src/tools/clippy/clippy_lints/src/consts.rs Upon building Miri based on the new changes it was verified that no changes needed to be made with the Miri project. Related issue #71193 --- src/librustc_codegen_llvm/consts.rs | 10 ++++---- .../mir/interpret/allocation.rs | 24 +++++++++---------- src/librustc_middle/mir/interpret/value.rs | 2 +- src/librustc_middle/ty/print/pretty.rs | 4 ++-- src/librustc_mir/interpret/memory.rs | 6 ++--- src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/place.rs | 4 ++-- src/librustc_mir/interpret/validity.rs | 8 +++---- src/librustc_mir/transform/const_prop.rs | 2 +- src/librustc_mir/util/pretty.rs | 6 ++--- src/tools/clippy/clippy_lints/src/consts.rs | 6 ++--- 11 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index acfb294f7c12b..024834bfe2aa5 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -41,7 +41,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll // some arbitrary byte value. // // FIXME: relay undef bytes to codegen as undef const bytes - let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(next_offset..offset); + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset); llvals.push(cx.const_bytes(bytes)); } let ptr_offset = read_target_uint( @@ -49,7 +49,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll // This `inspect` is okay since it is within the bounds of the allocation, it doesn't // affect interpreter execution (we inspect the result after interpreter execution), // and we properly interpret the relocation as a relocation pointer offset. - alloc.inspect_with_undef_and_ptr_outside_interpreter(offset..(offset + pointer_size)), + alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), ) .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; @@ -74,7 +74,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll // arbitrary byte value. // // FIXME: relay undef bytes to codegen as undef const bytes - let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(range); + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range); llvals.push(cx.const_bytes(bytes)); } @@ -452,7 +452,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // BSS. let all_bytes_are_zero = alloc.relocations().is_empty() && alloc - .inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len()) + .inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()) .iter() .all(|&byte| byte == 0); @@ -480,7 +480,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // because we are doing this access to inspect the final interpreter state (not // as part of the interpreter execution). let bytes = - alloc.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len()); + alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); let alloc = llvm::LLVMMDStringInContext( self.llcx, bytes.as_ptr().cast(), diff --git a/src/librustc_middle/mir/interpret/allocation.rs b/src/librustc_middle/mir/interpret/allocation.rs index dd4fc7adff117..b23deb2e3bc9b 100644 --- a/src/librustc_middle/mir/interpret/allocation.rs +++ b/src/librustc_middle/mir/interpret/allocation.rs @@ -154,10 +154,10 @@ impl Allocation { } /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs - /// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the + /// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the /// edges) at all. It further ignores `AllocationExtra` callbacks. /// This must not be used for reads affecting the interpreter execution. - pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range) -> &[u8] { + pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range) -> &[u8] { &self.bytes[range] } @@ -194,7 +194,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// The last argument controls whether we error out when there are uninitialized /// or pointer bytes. You should never call this, call `get_bytes` or - /// `get_bytes_with_undef_and_ptr` instead, + /// `get_bytes_with_uninit_and_ptr` instead, /// /// This function also guarantees that the resulting pointer will remain stable /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies @@ -244,7 +244,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// /// It is the caller's responsibility to check bounds and alignment beforehand. #[inline] - pub fn get_bytes_with_undef_and_ptr( + pub fn get_bytes_with_uninit_and_ptr( &self, cx: &impl HasDataLayout, ptr: Pointer, @@ -302,19 +302,19 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { } /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a - /// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the + /// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the /// given range contains neither relocations nor uninitialized bytes. pub fn check_bytes( &self, cx: &impl HasDataLayout, ptr: Pointer, size: Size, - allow_ptr_and_undef: bool, + allow_uninit_and_ptr: bool, ) -> InterpResult<'tcx> { // Check bounds and relocations on the edges. - self.get_bytes_with_undef_and_ptr(cx, ptr, size)?; + self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?; // Check uninit and ptr. - if !allow_ptr_and_undef { + if !allow_uninit_and_ptr { self.check_init(ptr, size)?; self.check_relocations(cx, ptr, size)?; } @@ -361,7 +361,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { size: Size, ) -> InterpResult<'tcx, ScalarMaybeUninit> { // `get_bytes_unchecked` tests relocation edges. - let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?; + let bytes = self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?; // Uninit check happens *after* we established that the alignment is correct. // We must not return `Ok()` for unaligned pointers! if self.is_init(ptr, size).is_err() { @@ -594,7 +594,7 @@ impl InitMaskCompressed { /// Transferring the initialization mask to other allocations. impl Allocation { /// Creates a run-length encoding of the initialization mask. - pub fn compress_undef_range(&self, src: Pointer, size: Size) -> InitMaskCompressed { + pub fn compress_uninit_range(&self, src: Pointer, size: Size) -> InitMaskCompressed { // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), // a naive initialization mask copying algorithm would repeatedly have to read the initialization mask from // the source and write it to the destination. Even if we optimized the memory accesses, @@ -636,8 +636,8 @@ impl Allocation { size: Size, repeat: u64, ) { - // An optimization where we can just overwrite an entire range of definedness bits if - // they are going to be uniformly `1` or `0`. + // An optimization where we can just overwrite an entire range of initialization + // bits if they are going to be uniformly `1` or `0`. if defined.ranges.len() <= 1 { self.init_mask.set_range_inbounds( dest.offset, diff --git a/src/librustc_middle/mir/interpret/value.rs b/src/librustc_middle/mir/interpret/value.rs index b4e7a5b98e33b..50c76e29663f6 100644 --- a/src/librustc_middle/mir/interpret/value.rs +++ b/src/librustc_middle/mir/interpret/value.rs @@ -58,7 +58,7 @@ impl<'tcx> ConstValue<'tcx> { pub fn try_to_str_slice(&self) -> Option<&'tcx str> { if let ConstValue::Slice { data, start, end } = *self { - ::std::str::from_utf8(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) + ::std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)) .ok() } else { None diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 3bb9c20370e8c..87944db60de66 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -1107,7 +1107,7 @@ pub trait PrettyPrinter<'tcx>: // The `inspect` here is okay since we checked the bounds, and there are // no relocations (we have an active slice reference here). We don't use // this result to affect interpreter execution. - let byte_str = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); + let byte_str = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end); self.pretty_print_byte_str(byte_str) } ( @@ -1117,7 +1117,7 @@ pub trait PrettyPrinter<'tcx>: // The `inspect` here is okay since we checked the bounds, and there are no // relocations (we have an active `str` reference here). We don't use this // result to affect interpreter execution. - let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); + 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)); Ok(self) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 7dfa913fd08bd..705a547262f02 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -926,7 +926,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // first copy the relocations to a temporary buffer, because // `get_bytes_mut` will clear the relocations, which is correct, // since we don't want to keep any relocations at the target. - // (`get_bytes_with_undef_and_ptr` below checks that there are no + // (`get_bytes_with_uninit_and_ptr` below checks that there are no // relocations overlapping the edges; those would not be handled correctly). let relocations = self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length); @@ -935,7 +935,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // This checks relocation edges on the src. let src_bytes = - self.get_raw(src.alloc_id)?.get_bytes_with_undef_and_ptr(&tcx, src, size)?.as_ptr(); + self.get_raw(src.alloc_id)?.get_bytes_with_uninit_and_ptr(&tcx, src, size)?.as_ptr(); let dest_bytes = self.get_raw_mut(dest.alloc_id)?.get_bytes_mut(&tcx, dest, size * length)?; // `Size` multiplication @@ -948,7 +948,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let dest_bytes = dest_bytes.as_mut_ptr(); // Prepare a copy of the initialization mask. - let compressed = self.get_raw(src.alloc_id)?.compress_undef_range(src, size); + let compressed = self.get_raw(src.alloc_id)?.compress_uninit_range(src, size); if compressed.no_bytes_init() { // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 49fde4009132d..0b58caef54d2b 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -106,7 +106,7 @@ impl std::fmt::Display for ImmTy<'tcx, Tag> { } ScalarMaybeUninit::Uninit => cx.typed_value( |mut this| { - this.write_str("{undef ")?; + this.write_str("{uninit ")?; Ok(this) }, |this| this.print_type(ty), diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 15e341d9c4c01..20fd8e43361d6 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -61,7 +61,7 @@ impl MemPlaceMeta { pub struct MemPlace { /// A place may have an integral pointer for ZSTs, and since it might /// be turned back into a reference before ever being dereferenced. - /// However, it may never be undef. + /// However, it may never be uninit. pub ptr: Scalar, pub align: Align, /// Metadata for unsized places. Interpretation is up to the type. @@ -729,7 +729,7 @@ where "Size mismatch when writing bits" ) } - Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // undef can have any size + Immediate::Scalar(ScalarMaybeUninit::Uninit) => {} // uninit can have any size Immediate::ScalarPair(_, _) => { // FIXME: Can we check anything here? } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index f1c5a67ed33f1..9cd20340138cf 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -508,12 +508,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } } else { // At run-time, for now, we accept *anything* for these types, including - // undef. We should fix that, but let's start low. + // uninit. We should fix that, but let's start low. } Ok(true) } ty::RawPtr(..) => { - // We are conservative with undef for integers, but try to + // We are conservative with uninit for integers, but try to // actually enforce the strict rules for raw pointers (mostly because // that lets us re-use `ref_to_mplace`). let place = try_validation!( @@ -807,12 +807,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // reject it. However, that's good: We don't inherently want // to reject those pointers, we just do not have the machinery to // talk about parts of a pointer. - // We also accept undef, for consistency with the slow path. + // We also accept uninit, for consistency with the slow path. match self.ecx.memory.get_raw(ptr.alloc_id)?.check_bytes( self.ecx, ptr, size, - /*allow_ptr_and_undef*/ self.ref_tracking_for_consts.is_none(), + /*allow_uninit_and_ptr*/ self.ref_tracking_for_consts.is_none(), ) { // In the happy case, we needn't check anything else. Ok(()) => {} diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index db0b0415728ae..31d390d51f381 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -1076,7 +1076,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { // ```rust // let mut x = 42; // x = SOME_MUTABLE_STATIC; - // // x must now be undefined + // // x must now be uninit // ``` // FIXME: we overzealously erase the entire local, because that's easier to // implement. diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 25657ba98b893..c3dbac08ed800 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -743,8 +743,8 @@ fn write_allocation_bytes( if let Some(&(tag, target_id)) = alloc.relocations().get(&i) { // Memory with a relocation must be defined let j = i.bytes_usize(); - let offset = - alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize()); + let offset = alloc + .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize()); let offset = read_target_uint(tcx.data_layout.endian, offset).unwrap(); let offset = Size::from_bytes(offset); let relocation_width = |bytes| bytes * 3; @@ -803,7 +803,7 @@ fn write_allocation_bytes( // Checked definedness (and thus range) and relocations. This access also doesn't // influence interpreter execution but is only for debugging. - let c = alloc.inspect_with_undef_and_ptr_outside_interpreter(j..j + 1)[0]; + let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0]; write!(w, "{:02x}", c)?; if c.is_ascii_control() || c >= 0x80 { ascii.push('.'); diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs index 49ff86a205d96..c77b80bc23733 100644 --- a/src/tools/clippy/clippy_lints/src/consts.rs +++ b/src/tools/clippy/clippy_lints/src/consts.rs @@ -517,7 +517,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind { ty::Ref(_, tam, _) => match tam.kind { ty::Str => String::from_utf8( - data.inspect_with_undef_and_ptr_outside_interpreter(start..end) + data.inspect_with_uninit_and_ptr_outside_interpreter(start..end) .to_owned(), ) .ok() @@ -530,7 +530,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { ty::Array(sub_type, len) => match sub_type.kind { ty::Float(FloatTy::F32) => match miri_to_const(len) { Some(Constant::Int(len)) => alloc - .inspect_with_undef_and_ptr_outside_interpreter(0..(4 * len as usize)) + .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize)) .to_owned() .chunks(4) .map(|chunk| { @@ -544,7 +544,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { }, ty::Float(FloatTy::F64) => match miri_to_const(len) { Some(Constant::Int(len)) => alloc - .inspect_with_undef_and_ptr_outside_interpreter(0..(8 * len as usize)) + .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize)) .to_owned() .chunks(8) .map(|chunk| { From aec6df9b944c052ed7899b150f6537c6c6fae535 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Aug 2020 18:01:37 +0200 Subject: [PATCH 02/13] move stack size check to const_eval machine --- src/librustc_mir/const_eval/machine.rs | 9 +++++++++ src/librustc_mir/interpret/eval_context.rs | 6 +----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 0dac8b6491011..3a753a0edb665 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -301,6 +301,15 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Ok(()) } + fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + // Enforce stack size limit. + if !ecx.tcx.sess.recursion_limit().value_within_limit(ecx.stack().len()) { + throw_exhaust!(StackFrameLimitReached) + } else { + Ok(()) + } + } + #[inline(always)] fn stack( ecx: &'a InterpCx<'mir, 'tcx, Self>, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 1e9be09781508..edf0dd0d5ed25 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -653,11 +653,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::after_stack_push(self)?; info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance); - if !self.tcx.sess.recursion_limit().value_within_limit(self.stack().len()) { - throw_exhaust!(StackFrameLimitReached) - } else { - Ok(()) - } + Ok(()) } /// Jump to the given block. From 8c705f83dbe1d8daef8ee0735abf8583a66f7732 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 9 Aug 2020 21:23:19 +0200 Subject: [PATCH 03/13] Rustdoc: Fix natural ordering to look at all numbers. The old implementation only looks at numbers at the end, but not in other places in a name: "u8" and "u16" got sorted properly, but "u8_bla" and "u16_bla" did not. --- src/librustdoc/html/render/mod.rs | 54 +++++++++++++++++++---------- src/librustdoc/html/render/tests.rs | 38 ++++++++++++++------ 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5fb2d9f6f917c..f98ca8a5089d2 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1903,23 +1903,41 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { } } -fn name_key(name: &str) -> (&str, u64, usize) { - let end = name.bytes().rposition(|b| b.is_ascii_digit()).map_or(name.len(), |i| i + 1); - - // find number at end - let split = name[0..end].bytes().rposition(|b| !b.is_ascii_digit()).map_or(0, |i| i + 1); - - // count leading zeroes - let after_zeroes = - name[split..end].bytes().position(|b| b != b'0').map_or(name.len(), |extra| split + extra); - - // sort leading zeroes last - let num_zeroes = after_zeroes - split; - - match name[split..end].parse() { - Ok(n) => (&name[..split], n, num_zeroes), - Err(_) => (name, 0, num_zeroes), +/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order). +pub fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering { + /// Takes a non-numeric and a numeric part from the given &str. + fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) { + let i = s.find(|c: char| c.is_ascii_digit()); + let (a, b) = s.split_at(i.unwrap_or(s.len())); + let i = b.find(|c: char| !c.is_ascii_digit()); + let (b, c) = b.split_at(i.unwrap_or(b.len())); + *s = c; + (a, b) + } + + while !lhs.is_empty() || !rhs.is_empty() { + let (la, lb) = take_parts(&mut lhs); + let (ra, rb) = take_parts(&mut rhs); + // First process the non-numeric part. + match la.cmp(ra) { + Ordering::Equal => (), + x => return x, + } + // Then process the numeric part, if both sides have one (and they fit in a u64). + if let (Ok(ln), Ok(rn)) = (lb.parse::(), rb.parse::()) { + match ln.cmp(&rn) { + Ordering::Equal => (), + x => return x, + } + } + // Then process the numeric part again, but this time as strings. + match lb.cmp(rb) { + Ordering::Equal => (), + x => return x, + } } + + Ordering::Equal } fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { @@ -1962,7 +1980,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: } let lhs = i1.name.as_ref().map_or("", |s| &**s); let rhs = i2.name.as_ref().map_or("", |s| &**s); - name_key(lhs).cmp(&name_key(rhs)) + compare_names(lhs, rhs) } if cx.shared.sort_modules_alphabetically { @@ -2395,7 +2413,7 @@ fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering { let rhs = format!("{}", rhs.inner_impl().print()); // lhs and rhs are formatted as HTML, which may be unnecessary - name_key(&lhs).cmp(&name_key(&rhs)) + compare_names(&lhs, &rhs) } fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, cache: &Cache) { diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs index 99ad26549f5d3..abf5f05fe58ab 100644 --- a/src/librustdoc/html/render/tests.rs +++ b/src/librustdoc/html/render/tests.rs @@ -1,24 +1,40 @@ use super::*; #[test] -fn test_name_key() { - assert_eq!(name_key("0"), ("", 0, 1)); - assert_eq!(name_key("123"), ("", 123, 0)); - assert_eq!(name_key("Fruit"), ("Fruit", 0, 0)); - assert_eq!(name_key("Fruit0"), ("Fruit", 0, 1)); - assert_eq!(name_key("Fruit0000"), ("Fruit", 0, 4)); - assert_eq!(name_key("Fruit01"), ("Fruit", 1, 1)); - assert_eq!(name_key("Fruit10"), ("Fruit", 10, 0)); - assert_eq!(name_key("Fruit123"), ("Fruit", 123, 0)); +fn test_compare_names() { + for &(a, b) in &[ + ("hello", "world"), + ("", "world"), + ("123", "hello"), + ("123", ""), + ("123test", "123"), + ("hello", ""), + ("hello", "hello"), + ("hello123", "hello123"), + ("hello123", "hello12"), + ("hello12", "hello123"), + ("hello01abc", "hello01xyz"), + ("hello0abc", "hello0"), + ("hello0", "hello0abc"), + ("01", "1"), + ] { + assert_eq!(compare_names(a, b), a.cmp(b), "{:?} - {:?}", a, b); + } + assert_eq!(compare_names("u8", "u16"), Ordering::Less); + assert_eq!(compare_names("u32", "u16"), Ordering::Greater); + assert_eq!(compare_names("u8_to_f64", "u16_to_f64"), Ordering::Less); + assert_eq!(compare_names("u32_to_f64", "u16_to_f64"), Ordering::Greater); + assert_eq!(compare_names("u16_to_f64", "u16_to_f64"), Ordering::Equal); + assert_eq!(compare_names("u16_to_f32", "u16_to_f64"), Ordering::Less); } #[test] fn test_name_sorting() { let names = [ - "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit1", "Fruit01", "Fruit2", "Fruit02", + "Apple", "Banana", "Fruit", "Fruit0", "Fruit00", "Fruit01", "Fruit1", "Fruit02", "Fruit2", "Fruit20", "Fruit30x", "Fruit100", "Pear", ]; let mut sorted = names.to_owned(); - sorted.sort_by_key(|&s| name_key(s)); + sorted.sort_by(|&l, r| compare_names(l, r)); assert_eq!(names, sorted); } From 9149ec74db635751e204b9793e2ad3ffcad6a849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 9 Aug 2020 16:56:47 -0700 Subject: [PATCH 04/13] Tweak conditions for E0026 and E0769 When we have a tuple struct used with struct we don't want to suggest using the (valid) struct syntax with numeric field names. Instead we want to suggest the expected syntax. Given ```rust fn main() { match MyOption::MySome(42) { MyOption::MySome { x: 42 } => (), _ => (), } } ``` We now emit E0769 "tuple variant `MyOption::MySome` written as struct variant" instead of E0026 "variant `MyOption::MySome` does not have a field named `x`". --- src/librustc_typeck/check/pat.rs | 11 +++++++++-- src/test/ui/issues/issue-17800.rs | 2 +- src/test/ui/issues/issue-17800.stderr | 11 ++++------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index f598ada900fee..1c78bef98527a 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1229,8 +1229,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); - // we don't want to throw `E0027` in case we have thrown `E0026` for them - unmentioned_fields.retain(|&x| x.name != suggested_name); + // When we have a tuple struct used with struct we don't want to suggest using + // the (valid) struct syntax with numeric field names. Instead we want to + // suggest the expected syntax. We infer that this is the case by parsing the + // `Ident` into an unsized integer. The suggestion will be emitted elsewhere in + // `smart_resolve_context_dependent_help`. + if suggested_name.to_ident_string().parse::().is_err() { + // We don't want to throw `E0027` in case we have thrown `E0026` for them. + unmentioned_fields.retain(|&x| x.name != suggested_name); + } } } } diff --git a/src/test/ui/issues/issue-17800.rs b/src/test/ui/issues/issue-17800.rs index 45879d68b3541..5254f45d7c2de 100644 --- a/src/test/ui/issues/issue-17800.rs +++ b/src/test/ui/issues/issue-17800.rs @@ -6,7 +6,7 @@ enum MyOption { fn main() { match MyOption::MySome(42) { MyOption::MySome { x: 42 } => (), - //~^ ERROR variant `MyOption::MySome` does not have a field named `x` + //~^ ERROR tuple variant `MyOption::MySome` written as struct variant _ => (), } } diff --git a/src/test/ui/issues/issue-17800.stderr b/src/test/ui/issues/issue-17800.stderr index 6efc7f0c06e11..fc034a0cbf3b8 100644 --- a/src/test/ui/issues/issue-17800.stderr +++ b/src/test/ui/issues/issue-17800.stderr @@ -1,12 +1,9 @@ -error[E0026]: variant `MyOption::MySome` does not have a field named `x` - --> $DIR/issue-17800.rs:8:28 +error[E0769]: tuple variant `MyOption::MySome` written as struct variant + --> $DIR/issue-17800.rs:8:9 | LL | MyOption::MySome { x: 42 } => (), - | ^ - | | - | variant `MyOption::MySome` does not have this field - | help: a field with a similar name exists: `0` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `MyOption::MySome(42)` error: aborting due to previous error -For more information about this error, try `rustc --explain E0026`. +For more information about this error, try `rustc --explain E0769`. From 7e0180906b0fe738596bff512c96c3f36afaf6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 9 Aug 2020 17:48:32 -0700 Subject: [PATCH 05/13] Small cleanup Remove unnecessary `unwrap`. --- src/librustc_resolve/late/diagnostics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index ec6dbb070dfa8..fdc524a8e39e0 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -378,15 +378,15 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { /// return the span of whole call and the span for all arguments expect the first one (`self`). fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option)> { let mut has_self_arg = None; - if let PathSource::Expr(parent) = source { - match &parent?.kind { + if let PathSource::Expr(Some(parent)) = source { + match &parent.kind { ExprKind::Call(_, args) if !args.is_empty() => { let mut expr_kind = &args[0].kind; loop { match expr_kind { ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => { if arg_name.segments[0].ident.name == kw::SelfLower { - let call_span = parent.unwrap().span; + let call_span = parent.span; let tail_args_span = if args.len() > 1 { Some(Span::new( args[1].span.lo(), From 0210fd3d7303a626f6e821bde8fdfea056cc043b Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 5 Aug 2020 10:29:38 +0000 Subject: [PATCH 06/13] Transmute between big endian `s6_addr` and `[u16; 8]`. The old code already made the assumption to reinterpret `Ipv6Addr` as `[u16; 8]`. Glibc, Linux, FreeBSD, Win32 all makes this assumption. The main motivation of using union it to better optimize code. ref: * https://docs.microsoft.com/en-us/windows/win32/api/in6addr/ns-in6addr-in6_addr * https://github.com/freebsd/freebsd/blob/1d6e4247415d264485ee94b59fdbc12e0c566fd0/contrib/ntp/lib/isc/include/isc/ipv6.h#L63 * https://github.com/zephyrproject-rtos/zephyr/blob/8b531aa996bba254c03129658490af59597acd78/include/net/net_ip.h#L137 * https://sourceware.org/git/?p=glibc.git;a=blob;f=inet/netinet/in.h;h=f6355c7efe5192b88337b136ef687fe9a5ed648c;hb=HEAD#l216 Co-authored-by: Josh Stone Co-authored-by: Peter Atashian --- library/std/src/lib.rs | 1 + library/std/src/net/ip.rs | 54 +++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0569e46241a80..f0487e0dff148 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -249,6 +249,7 @@ #![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] +#![feature(const_fn_transmute)] #![feature(const_raw_ptr_deref)] #![feature(container_error_extra)] #![feature(core_intrinsics)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 159ab981b237d..5d103e6403750 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -10,6 +10,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Write as FmtWrite}; use crate::hash; use crate::io::Write as IoWrite; +use crate::mem::transmute; use crate::sys::net::netc as c; use crate::sys_common::{AsInner, FromInner}; @@ -1045,27 +1046,23 @@ impl Ipv6Addr { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] + #[allow_internal_unstable(const_fn_transmute)] pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { + let addr16 = [ + a.to_be(), + b.to_be(), + c.to_be(), + d.to_be(), + e.to_be(), + f.to_be(), + g.to_be(), + h.to_be(), + ]; Ipv6Addr { inner: c::in6_addr { - s6_addr: [ - (a >> 8) as u8, - a as u8, - (b >> 8) as u8, - b as u8, - (c >> 8) as u8, - c as u8, - (d >> 8) as u8, - d as u8, - (e >> 8) as u8, - e as u8, - (f >> 8) as u8, - f as u8, - (g >> 8) as u8, - g as u8, - (h >> 8) as u8, - h as u8, - ], + // All elements in `addr16` are big endian. + // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`. + s6_addr: unsafe { transmute::<_, [u8; 16]>(addr16) }, }, } } @@ -1108,16 +1105,19 @@ impl Ipv6Addr { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn segments(&self) -> [u16; 8] { - let arr = &self.inner.s6_addr; + // All elements in `s6_addr` must be big endian. + // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. + let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) }; + // We want native endian u16 [ - u16::from_be_bytes([arr[0], arr[1]]), - u16::from_be_bytes([arr[2], arr[3]]), - u16::from_be_bytes([arr[4], arr[5]]), - u16::from_be_bytes([arr[6], arr[7]]), - u16::from_be_bytes([arr[8], arr[9]]), - u16::from_be_bytes([arr[10], arr[11]]), - u16::from_be_bytes([arr[12], arr[13]]), - u16::from_be_bytes([arr[14], arr[15]]), + u16::from_be(a), + u16::from_be(b), + u16::from_be(c), + u16::from_be(d), + u16::from_be(e), + u16::from_be(f), + u16::from_be(g), + u16::from_be(h), ] } From bf4be5de52623859ae3c9666ec629322fd473fc2 Mon Sep 17 00:00:00 2001 From: Erin Power Date: Sat, 25 Jul 2020 16:36:17 +0200 Subject: [PATCH 07/13] Update RELEASES.md for 1.46.0 Co-authored-by: Yuki Okushi Co-authored-by: Lonami --- RELEASES.md | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 4859532f7a1f7..b3d8c2f65f633 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,104 @@ +Version 1.46.0 (2020-08-27) +========================== + +Language +-------- +- [`if`, `match`, and `loop` expressions can now be used in const functions.][72437] +- [Additionally you are now also able to coerce and cast to slices (`&[T]`) in + const functions.][73862] +- [The `#[track_caller]` attribute can now be added to functions to use the + function's caller's location information for panic messages.][72445] +- [Recursively indexing into tuples no longer needs parentheses.][71322] E.g. + `x.0.0` over `(x.0).0`. +- [`mem::transmute` can now be used in static and constants.][72920] **Note** + You currently can't use `mem::transmute` in constant functions. + +Compiler +-------- +- [You can now use the `cdylib` target on Apple iOS and tvOS platforms.][73516] +- [Enabled static "Position Independent Executables" by default + for `x86_64-unknown-linux-musl`.][70740] + +Libraries +--------- +- [`mem::forget` is now a `const fn`.][73887] +- [`String` now implements `From`.][73466] +- [The `leading_ones`, and `trailing_ones` methods have been stabilised for all + integer types.][73032] +- [`vec::IntoIter` now implements `AsRef<[T]>`.][72583] +- [All non-zero integer types (`NonZeroU8`) now implement `TryFrom` for their + zero-able equivalent (e.g. `TryFrom`).][72717] +- [`&[T]` and `&mut [T]` now implement `PartialEq>`.][71660] +- [`(String, u16)` now implements `ToSocketAddrs`.][73007] +- [`vec::Drain<'_, T>` now implements `AsRef<[T]>`.][72584] + +Stabilized APIs +--------------- +- [`Option::zip`] +- [`vec::Drain::as_slice`] + +Cargo +----- +Added a number of new environment variables that are now available when +compiling your crate. + +- [`CARGO_BIN_NAME` and `CARGO_CRATE_NAME`][cargo/8270] Providing the name of + the specific binary being compiled and the name of the crate. +- [`CARGO_PKG_LICENSE`][cargo/8325] The license from the manifest of the package. +- [`CARGO_PKG_LICENSE_FILE`][cargo/8387] The path to the license file. + +Compatibility Notes +------------------- +- [The target configuration option `abi_blacklist` has been renamed + to `unsupported_abis`.][74150] The old name will still continue to work. +- [Rustc will now warn if you have a C-like enum that implements `Drop`.][72331] + This was previously accepted but will become a hard error in a future release. +- [Rustc will fail to compile if you have a struct with + `#[repr(i128)]` or `#[repr(u128)]`.][74109] This representation is currently only + allowed on `enum`s. +- [Tokens passed to `macro_rules!` are now always captured.][73293] This helps + ensure that spans have the correct information, and may cause breakage if you + were relying on receiving spans with dummy information. +- [The InnoSetup installer for Windows is no longer available.][72569] This was + a legacy installer that was replaced by a MSI installer a few years ago but + was still being built. +- [`{f32, f64}::asinh` now returns the correct values for negative numbers.][72486] +- [Rustc will no longer accept overlapping trait implementations that only + differ in how the lifetime was bound.][72493] +- [Rustc now correctly relates the lifetime of an existential associated + type.][71896] This fixes some edge cases where `rustc` would erroneously allow + you to pass a shorter lifetime than expected. + +[74109]: https://github.com/rust-lang/rust/pull/74109/ +[74150]: https://github.com/rust-lang/rust/pull/74150/ +[73862]: https://github.com/rust-lang/rust/pull/73862/ +[73887]: https://github.com/rust-lang/rust/pull/73887/ +[73466]: https://github.com/rust-lang/rust/pull/73466/ +[73516]: https://github.com/rust-lang/rust/pull/73516/ +[73293]: https://github.com/rust-lang/rust/pull/73293/ +[73007]: https://github.com/rust-lang/rust/pull/73007/ +[73032]: https://github.com/rust-lang/rust/pull/73032/ +[72920]: https://github.com/rust-lang/rust/pull/72920/ +[72569]: https://github.com/rust-lang/rust/pull/72569/ +[72583]: https://github.com/rust-lang/rust/pull/72583/ +[72584]: https://github.com/rust-lang/rust/pull/72584/ +[72717]: https://github.com/rust-lang/rust/pull/72717/ +[72437]: https://github.com/rust-lang/rust/pull/72437/ +[72445]: https://github.com/rust-lang/rust/pull/72445/ +[72486]: https://github.com/rust-lang/rust/pull/72486/ +[72493]: https://github.com/rust-lang/rust/pull/72493/ +[72331]: https://github.com/rust-lang/rust/pull/72331/ +[71896]: https://github.com/rust-lang/rust/pull/71896/ +[71660]: https://github.com/rust-lang/rust/pull/71660/ +[71322]: https://github.com/rust-lang/rust/pull/71322/ +[70740]: https://github.com/rust-lang/rust/pull/70740/ +[cargo/8270]: https://github.com/rust-lang/cargo/pull/8270/ +[cargo/8325]: https://github.com/rust-lang/cargo/pull/8325/ +[cargo/8387]: https://github.com/rust-lang/cargo/pull/8387/ +[`Option::zip`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.zip +[`vec::Drain::as_slice`]: https://doc.rust-lang.org/stable/std/vec/struct.Drain.html#method.as_slice + + Version 1.45.2 (2020-08-03) ========================== @@ -7,6 +108,7 @@ Version 1.45.2 (2020-08-03) [74954]: https://github.com/rust-lang/rust/issues/74954 [74784]: https://github.com/rust-lang/rust/issues/74784 + Version 1.45.1 (2020-07-30) ========================== @@ -20,6 +122,7 @@ Version 1.45.1 (2020-07-30) [74509]: https://github.com/rust-lang/rust/pull/74509 [74457]: https://github.com/rust-lang/rust/pull/74457 + Version 1.45.0 (2020-07-16) ========================== From 66db8e52d7e75e20048af38d137db2fbe4aa9201 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 10 Aug 2020 12:04:51 +0200 Subject: [PATCH 08/13] unused_delims: trim expr --- src/librustc_lint/unused.rs | 36 ++++++++++--------- .../ui/const-generics/unused_braces.fixed | 2 +- src/test/ui/lint/unused_braces.fixed | 8 ++--- src/test/ui/lint/unused_braces_borrow.fixed | 2 +- .../try-block/try-block-unused-delims.fixed | 2 +- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 5de9a16e09881..ecc8a192f18ea 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -481,25 +481,27 @@ trait UnusedDelimLint { let mut err = lint.build(&span_msg); let mut ate_left_paren = false; let mut ate_right_paren = false; - let parens_removed = pattern.trim_matches(|c| match c { - '(' | '{' => { - if ate_left_paren { - false - } else { - ate_left_paren = true; - true + let parens_removed = pattern + .trim_matches(|c| match c { + '(' | '{' => { + if ate_left_paren { + false + } else { + ate_left_paren = true; + true + } } - } - ')' | '}' => { - if ate_right_paren { - false - } else { - ate_right_paren = true; - true + ')' | '}' => { + if ate_right_paren { + false + } else { + ate_right_paren = true; + true + } } - } - _ => false, - }); + _ => false, + }) + .trim(); let replace = { let mut replace = if keep_space.0 { diff --git a/src/test/ui/const-generics/unused_braces.fixed b/src/test/ui/const-generics/unused_braces.fixed index 5c2b9267af583..836f26efc9601 100644 --- a/src/test/ui/const-generics/unused_braces.fixed +++ b/src/test/ui/const-generics/unused_braces.fixed @@ -10,6 +10,6 @@ struct A; fn main() { let _: A<7>; // ok - let _: A< 7 >; //~ WARN unnecessary braces + let _: A<7>; //~ WARN unnecessary braces let _: A<{ 3 + 5 }>; // ok } diff --git a/src/test/ui/lint/unused_braces.fixed b/src/test/ui/lint/unused_braces.fixed index c0225911c6ed0..1a88d985dd86a 100644 --- a/src/test/ui/lint/unused_braces.fixed +++ b/src/test/ui/lint/unused_braces.fixed @@ -23,18 +23,18 @@ fn main() { } } - if true { + if true { //~^ WARN unnecessary braces } - while false { + while false { //~^ WARN unnecessary braces } - let _: [u8; 3 ]; + let _: [u8; 3]; //~^ WARN unnecessary braces - consume( 7 ); + consume(7); //~^ WARN unnecessary braces // Do not emit lint for multiline blocks. diff --git a/src/test/ui/lint/unused_braces_borrow.fixed b/src/test/ui/lint/unused_braces_borrow.fixed index 25950334549f9..583506f891d01 100644 --- a/src/test/ui/lint/unused_braces_borrow.fixed +++ b/src/test/ui/lint/unused_braces_borrow.fixed @@ -21,6 +21,6 @@ fn main() { }; consume(&{ a.b }); - consume( a.b ); + consume(a.b); //~^ WARN unnecessary braces } diff --git a/src/test/ui/try-block/try-block-unused-delims.fixed b/src/test/ui/try-block/try-block-unused-delims.fixed index c8b03c2006840..756081738c3d7 100644 --- a/src/test/ui/try-block/try-block-unused-delims.fixed +++ b/src/test/ui/try-block/try-block-unused-delims.fixed @@ -11,7 +11,7 @@ fn main() { consume(try {}); //~^ WARN unnecessary parentheses - consume( try {} ); + consume(try {}); //~^ WARN unnecessary braces match try {} { From ec23f4ed3fdb7f09a4398a32eaf486da22bd3ae9 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 10 Aug 2020 18:51:14 +0800 Subject: [PATCH 09/13] Add sample fix for E0749 Even though the description is clear but the solution may not be as straightforward. Adding a suggested fix. --- src/librustc_error_codes/error_codes/E0749.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_error_codes/error_codes/E0749.md b/src/librustc_error_codes/error_codes/E0749.md index 7a1a745b53c12..74cd2903f6d01 100644 --- a/src/librustc_error_codes/error_codes/E0749.md +++ b/src/librustc_error_codes/error_codes/E0749.md @@ -11,6 +11,7 @@ trait MyTrait { impl !MyTrait for u32 { type Foo = i32; // error! } +// impl !MyTrait for u32 {} // fix # fn main() {} ``` From 20f4e168249ca0828b7297942d47040c59376fbe Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 9 Aug 2020 11:22:50 +0100 Subject: [PATCH 10/13] polymorphize: constrain unevaluated const handling This commit constrains the support added for handling unevaluated consts in polymorphization (introduced in #75260) by: - Skipping associated constants as this causes cycle errors. - Skipping promoted constants when they contain `Self` as this ensures `T` is used in constants of the form `>`. Signed-off-by: David Wood --- src/librustc_mir/monomorphize/polymorphize.rs | 14 ++++++++++---- .../ui/polymorphization/promoted-function-3.rs | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/polymorphization/promoted-function-3.rs diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs index a996b6fb9d924..fc9f7f1af622f 100644 --- a/src/librustc_mir/monomorphize/polymorphize.rs +++ b/src/librustc_mir/monomorphize/polymorphize.rs @@ -269,15 +269,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> { self.unused_parameters.clear(param.index); false } - ty::ConstKind::Unevaluated(_, _, Some(p)) => { + ty::ConstKind::Unevaluated(def, _, Some(p)) + // Avoid considering `T` unused when constants are of the form: + // `>::foo::promoted[p]` + if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self => + { // If there is a promoted, don't look at the substs - since it will always contain // the generic parameters, instead, traverse the promoted MIR. - let promoted = self.tcx.promoted_mir(self.def_id); + let promoted = self.tcx.promoted_mir(def.did); self.visit_body(&promoted[p]); false } - ty::ConstKind::Unevaluated(def_id, unevaluated_substs, None) => { - self.visit_child_body(def_id.did, unevaluated_substs); + ty::ConstKind::Unevaluated(def, unevaluated_substs, None) + if self.tcx.def_kind(def.did) == DefKind::AnonConst => + { + self.visit_child_body(def.did, unevaluated_substs); false } _ => c.super_visit_with(self), diff --git a/src/test/ui/polymorphization/promoted-function-3.rs b/src/test/ui/polymorphization/promoted-function-3.rs new file mode 100644 index 0000000000000..1c84df13e10b0 --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-3.rs @@ -0,0 +1,14 @@ +// run-pass +// compile-flags: -Zpolymorphize=on -Zmir-opt-level=3 + +fn caller() -> &'static usize { + callee::() +} + +fn callee() -> &'static usize { + &std::mem::size_of::() +} + +fn main() { + assert_eq!(caller::<(), ()>(), &0); +} From a2d7c33aa83d39cd0ab1fba0a8ccdfd2c7f29576 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 10 Aug 2020 22:33:17 +0800 Subject: [PATCH 11/13] Split fix into another section for E0749 --- src/librustc_error_codes/error_codes/E0749.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0749.md b/src/librustc_error_codes/error_codes/E0749.md index 74cd2903f6d01..962da0eda08f6 100644 --- a/src/librustc_error_codes/error_codes/E0749.md +++ b/src/librustc_error_codes/error_codes/E0749.md @@ -11,10 +11,20 @@ trait MyTrait { impl !MyTrait for u32 { type Foo = i32; // error! } -// impl !MyTrait for u32 {} // fix # fn main() {} ``` Negative impls are not allowed to have any items. Negative impls declare that a trait is **not** implemented (and never will be) and hence there is no need to specify the values for trait methods or other items. + +One way to fix this is to remove the items in negative impls. + +``` +# #![feature(negative_impls)] +trait MyTrait { + type Foo; +} + +impl !MyTrait for u32 {} +``` From 8cb1a2f8a2a3fe9dce850e512c003bffd7786ab6 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 10 Aug 2020 22:46:15 +0800 Subject: [PATCH 12/13] Use : rather than . in example description Co-authored-by: Guillaume Gomez --- src/librustc_error_codes/error_codes/E0749.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0749.md b/src/librustc_error_codes/error_codes/E0749.md index 962da0eda08f6..5b6bfe75cfc90 100644 --- a/src/librustc_error_codes/error_codes/E0749.md +++ b/src/librustc_error_codes/error_codes/E0749.md @@ -18,7 +18,7 @@ Negative impls are not allowed to have any items. Negative impls declare that a trait is **not** implemented (and never will be) and hence there is no need to specify the values for trait methods or other items. -One way to fix this is to remove the items in negative impls. +One way to fix this is to remove the items in negative impls: ``` # #![feature(negative_impls)] From a7f61bf3bb416f03da478bbe2421946ef9b80379 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 11 Aug 2020 01:06:30 +0800 Subject: [PATCH 13/13] Remove empty fn main from E0749 --- src/librustc_error_codes/error_codes/E0749.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0749.md b/src/librustc_error_codes/error_codes/E0749.md index 5b6bfe75cfc90..dfe90ae89e4cb 100644 --- a/src/librustc_error_codes/error_codes/E0749.md +++ b/src/librustc_error_codes/error_codes/E0749.md @@ -11,7 +11,6 @@ trait MyTrait { impl !MyTrait for u32 { type Foo = i32; // error! } -# fn main() {} ``` Negative impls are not allowed to have any items. Negative impls declare that a