From 3f20a5dff7926da1b7bfe511cc26887ddf70c0b5 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 18 Feb 2019 10:54:16 +0100 Subject: [PATCH 01/37] Optimize copying large ranges of undefmask blocks --- src/librustc/mir/interpret/allocation.rs | 45 ++++++++++++++++++++---- src/librustc_mir/interpret/memory.rs | 22 ++++++++++-- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index e96392edd64bf..06d5f27ccd744 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -613,7 +613,6 @@ impl DerefMut for Relocations { //////////////////////////////////////////////////////////////////////////////// type Block = u64; -const BLOCK_SIZE: u64 = 64; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct UndefMask { @@ -624,6 +623,8 @@ pub struct UndefMask { impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len}); impl UndefMask { + pub const BLOCK_SIZE: u64 = 64; + pub fn new(size: Size) -> Self { let mut m = UndefMask { blocks: vec![], @@ -643,6 +644,7 @@ impl UndefMask { return Err(self.len); } + // FIXME(oli-obk): optimize this for allocations larger than a block. let idx = (start.bytes()..end.bytes()) .map(|i| Size::from_bytes(i)) .find(|&i| !self.get(i)); @@ -662,8 +664,31 @@ impl UndefMask { } pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) { - for i in start.bytes()..end.bytes() { - self.set(Size::from_bytes(i), new_state); + let (blocka, bita) = bit_index(start); + let (blockb, bitb) = bit_index(end); + if blocka == blockb { + // within a single block + for i in bita .. bitb { + self.set_bit(blocka, i, new_state); + } + return; + } + // across block boundaries + for i in bita .. Self::BLOCK_SIZE as usize { + self.set_bit(blocka, i, new_state); + } + for i in 0 .. bitb { + self.set_bit(blockb, i, new_state); + } + // fill in all the other blocks (much faster than one bit at a time) + if new_state { + for block in (blocka + 1) .. blockb { + self.blocks[block] = 0xFFFF_FFFF_FFFF_FFFF; + } + } else { + for block in (blocka + 1) .. blockb { + self.blocks[block] = 0; + } } } @@ -676,6 +701,11 @@ impl UndefMask { #[inline] pub fn set(&mut self, i: Size, new_state: bool) { let (block, bit) = bit_index(i); + self.set_bit(block, bit, new_state); + } + + #[inline] + fn set_bit(&mut self, block: usize, bit: usize, new_state: bool) { if new_state { self.blocks[block] |= 1 << bit; } else { @@ -684,11 +714,12 @@ impl UndefMask { } pub fn grow(&mut self, amount: Size, new_state: bool) { - let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes(); + let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes(); if amount.bytes() > unused_trailing_bits { - let additional_blocks = amount.bytes() / BLOCK_SIZE + 1; + let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1; assert_eq!(additional_blocks as usize as u64, additional_blocks); self.blocks.extend( + // FIXME(oli-obk): optimize this by repeating `new_state as Block` iter::repeat(0).take(additional_blocks as usize), ); } @@ -701,8 +732,8 @@ impl UndefMask { #[inline] fn bit_index(bits: Size) -> (usize, usize) { let bits = bits.bytes(); - let a = bits / BLOCK_SIZE; - let b = bits % BLOCK_SIZE; + let a = bits / UndefMask::BLOCK_SIZE; + let b = bits % UndefMask::BLOCK_SIZE; assert_eq!(a as usize as u64, a); assert_eq!(b as usize as u64, b); (a as usize, b as usize) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 88b936afaa4c1..78668c5ad875e 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -20,7 +20,7 @@ use syntax::ast::Mutability; use super::{ Pointer, AllocId, Allocation, GlobalId, AllocationExtra, EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic, - Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, + Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, UndefMask, }; #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] @@ -785,10 +785,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { assert_eq!(size.bytes() as usize as u64, size.bytes()); let undef_mask = self.get(src.alloc_id)?.undef_mask.clone(); + let get = |i| undef_mask.get(src.offset + Size::from_bytes(i)); let dest_allocation = self.get_mut(dest.alloc_id)?; + // an optimization where we can just overwrite an entire range of definedness bits if + // they are going to be uniformly `1` or `0`. + if size.bytes() * repeat > UndefMask::BLOCK_SIZE { + let first = undef_mask.get(src.offset); + // check that all bits are the same as the first bit + // FIXME(oli-obk): consider making this a function on `UndefMask` and optimize it, too + if (1..size.bytes()).all(|i| get(i) == first) { + dest_allocation.undef_mask.set_range( + dest.offset, + dest.offset + size * repeat, + first, + ); + return Ok(()) + } + } + + // the default path for i in 0..size.bytes() { - let defined = undef_mask.get(src.offset + Size::from_bytes(i)); + let defined = get(i); for j in 0..repeat { dest_allocation.undef_mask.set( From 1e3d1b65c500a33993462c84ecb80136d184acb2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 18 Feb 2019 13:55:55 +0100 Subject: [PATCH 02/37] No magic numbers --- src/librustc/mir/interpret/allocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 06d5f27ccd744..18880c551ed55 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -683,7 +683,7 @@ impl UndefMask { // fill in all the other blocks (much faster than one bit at a time) if new_state { for block in (blocka + 1) .. blockb { - self.blocks[block] = 0xFFFF_FFFF_FFFF_FFFF; + self.blocks[block] = u64::max_value(); } } else { for block in (blocka + 1) .. blockb { From aa8c48a2746e85b1a2e2ff53a34f30b81920fa5f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 19 Feb 2019 09:35:06 +0100 Subject: [PATCH 03/37] Don't try to copy relocations if there are none --- src/librustc_mir/interpret/memory.rs | 39 ++++++++++++++++------------ 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 78668c5ad875e..8cbc404e28b31 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -700,24 +700,29 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // relocations overlapping the edges; those would not be handled correctly). let relocations = { let relocations = self.get(src.alloc_id)?.relocations(self, src, size); - let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); - for i in 0..length { - new_relocations.extend( - relocations - .iter() - .map(|&(offset, reloc)| { - // compute offset for current repetition - let dest_offset = dest.offset + (i * size); - ( - // shift offsets from source allocation to destination allocation - offset + dest_offset - src.offset, - reloc, - ) - }) - ); - } + if relocations.is_empty() { + // nothing to copy, ignore even the `length` loop + Vec::new() + } else { + let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); + for i in 0..length { + new_relocations.extend( + relocations + .iter() + .map(|&(offset, reloc)| { + // compute offset for current repetition + let dest_offset = dest.offset + (i * size); + ( + // shift offsets from source allocation to destination allocation + offset + dest_offset - src.offset, + reloc, + ) + }) + ); + } - new_relocations + new_relocations + } }; let tcx = self.tcx.tcx; From d32b7e5b13ee833675c8fb3c905a4286690ceb15 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 19 Feb 2019 09:43:39 +0100 Subject: [PATCH 04/37] Test the `UndefMask` type --- src/test/run-pass-fulldeps/undef_mask.rs | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/run-pass-fulldeps/undef_mask.rs diff --git a/src/test/run-pass-fulldeps/undef_mask.rs b/src/test/run-pass-fulldeps/undef_mask.rs new file mode 100644 index 0000000000000..37c44e2df6c5e --- /dev/null +++ b/src/test/run-pass-fulldeps/undef_mask.rs @@ -0,0 +1,26 @@ +// ignore-cross-compile +// ignore-stage1 + +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::mir::interpret::UndefMask; +use rustc::ty::layout::Size; + +fn main() { + let mut mask = UndefMask::new(Size::from_bytes(500)); + assert!(!mask.get(Size::from_bytes(499))); + mask.set(Size::from_bytes(499), true); + assert!(mask.get(Size::from_bytes(499))); + mask.set_range_inbounds(Size::from_bytes(100), Size::from_bytes(256), true); + for i in 0..100 { + assert!(!mask.get(Size::from_bytes(i))); + } + for i in 100..256 { + assert!(mask.get(Size::from_bytes(i))); + } + for i in 256..499 { + assert!(!mask.get(Size::from_bytes(i))); + } +} From 4ded592f60c3f1a16db56fadcd7924121ed92ce8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 19 Feb 2019 12:40:56 +0100 Subject: [PATCH 05/37] Use a more general approach for setting large definedness ranges --- src/librustc_mir/interpret/memory.rs | 70 ++++++++++++++++++---------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 8cbc404e28b31..6cbb611c1a3ec 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -20,7 +20,7 @@ use syntax::ast::Mutability; use super::{ Pointer, AllocId, Allocation, GlobalId, AllocationExtra, EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic, - Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, UndefMask, + Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, }; #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] @@ -789,38 +789,58 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // The bits have to be saved locally before writing to dest in case src and dest overlap. assert_eq!(size.bytes() as usize as u64, size.bytes()); - let undef_mask = self.get(src.alloc_id)?.undef_mask.clone(); - let get = |i| undef_mask.get(src.offset + Size::from_bytes(i)); - let dest_allocation = self.get_mut(dest.alloc_id)?; + let undef_mask = &self.get(src.alloc_id)?.undef_mask; + + // a precomputed cache for ranges of defined/undefined bits + // 0000010010001110 will become + // [5, 1, 2, 1, 3, 3, 1] + // where each element toggles the state + let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); + let first = undef_mask.get(src.offset); + let mut cur_len = 1; + let mut cur = first; + for i in 1..size.bytes() { + // FIXME: optimize to bitshift the current undef block's bits and read the top bit + if undef_mask.get(src.offset + Size::from_bytes(i)) == cur { + cur_len += 1; + } else { + ranges.push(cur_len); + cur_len = 1; + cur = !cur; + } + } + // now fill in all the data + let dest_allocation = self.get_mut(dest.alloc_id)?; // an optimization where we can just overwrite an entire range of definedness bits if // they are going to be uniformly `1` or `0`. - if size.bytes() * repeat > UndefMask::BLOCK_SIZE { - let first = undef_mask.get(src.offset); - // check that all bits are the same as the first bit - // FIXME(oli-obk): consider making this a function on `UndefMask` and optimize it, too - if (1..size.bytes()).all(|i| get(i) == first) { - dest_allocation.undef_mask.set_range( - dest.offset, - dest.offset + size * repeat, - first, - ); - return Ok(()) - } + if ranges.is_empty() { + dest_allocation.undef_mask.set_range( + dest.offset, + dest.offset + size * repeat, + first, + ); + return Ok(()) } - // the default path - for i in 0..size.bytes() { - let defined = get(i); - - for j in 0..repeat { - dest_allocation.undef_mask.set( - dest.offset + Size::from_bytes(i + (size.bytes() * j)), - defined + // remember to fill in the trailing bits + ranges.push(cur_len); + + for mut j in 0..repeat { + j *= size.bytes(); + j += dest.offset.bytes(); + let mut cur = first; + for range in &ranges { + let old_j = j; + j += range; + dest_allocation.undef_mask.set_range_inbounds( + Size::from_bytes(old_j), + Size::from_bytes(j), + cur, ); + cur = !cur; } } - Ok(()) } } From 60fde17a293ab94c56e415f5d5dd036527b4f201 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 20 Feb 2019 15:07:25 +0100 Subject: [PATCH 06/37] Use bit operations for setting large ranges of bits in a u64 --- src/librustc/mir/interpret/allocation.rs | 49 ++++++++++++++++-------- src/librustc_mir/interpret/memory.rs | 2 +- src/test/run-pass-fulldeps/undef_mask.rs | 2 +- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 18880c551ed55..004804f7c211e 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -100,8 +100,7 @@ impl AllocationExtra<(), ()> for () { impl Allocation { /// Creates a read-only allocation initialized by the given bytes pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self { - let mut undef_mask = UndefMask::new(Size::ZERO); - undef_mask.grow(Size::from_bytes(slice.len() as u64), true); + let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true); Self { bytes: slice.to_owned(), relocations: Relocations::new(), @@ -121,7 +120,7 @@ impl Allocation { Allocation { bytes: vec![0; size.bytes() as usize], relocations: Relocations::new(), - undef_mask: UndefMask::new(size), + undef_mask: UndefMask::new(size, false), align, mutability: Mutability::Mutable, extra, @@ -625,12 +624,12 @@ impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len}); impl UndefMask { pub const BLOCK_SIZE: u64 = 64; - pub fn new(size: Size) -> Self { + pub fn new(size: Size, state: bool) -> Self { let mut m = UndefMask { blocks: vec![], len: Size::ZERO, }; - m.grow(size, false); + m.grow(size, state); m } @@ -667,25 +666,40 @@ impl UndefMask { let (blocka, bita) = bit_index(start); let (blockb, bitb) = bit_index(end); if blocka == blockb { - // within a single block - for i in bita .. bitb { - self.set_bit(blocka, i, new_state); + // first set all bits but the first `bita` + // then unset the last `64 - bitb` bits + let range = if bitb == 0 { + u64::max_value() << bita + } else { + (u64::max_value() << bita) & (u64::max_value() >> (64 - bitb)) + }; + if new_state { + self.blocks[blocka] |= range; + } else { + self.blocks[blocka] &= !range; } return; } // across block boundaries - for i in bita .. Self::BLOCK_SIZE as usize { - self.set_bit(blocka, i, new_state); - } - for i in 0 .. bitb { - self.set_bit(blockb, i, new_state); - } - // fill in all the other blocks (much faster than one bit at a time) if new_state { + // set bita..64 to 1 + self.blocks[blocka] |= u64::max_value() << bita; + // set 0..bitb to 1 + if bitb != 0 { + self.blocks[blockb] |= u64::max_value() >> (64 - bitb); + } + // fill in all the other blocks (much faster than one bit at a time) for block in (blocka + 1) .. blockb { self.blocks[block] = u64::max_value(); } } else { + // set bita..64 to 0 + self.blocks[blocka] &= !(u64::max_value() << bita); + // set 0..bitb to 0 + if bitb != 0 { + self.blocks[blockb] &= !(u64::max_value() >> (64 - bitb)); + } + // fill in all the other blocks (much faster than one bit at a time) for block in (blocka + 1) .. blockb { self.blocks[block] = 0; } @@ -695,7 +709,7 @@ impl UndefMask { #[inline] pub fn get(&self, i: Size) -> bool { let (block, bit) = bit_index(i); - (self.blocks[block] & 1 << bit) != 0 + (self.blocks[block] & (1 << bit)) != 0 } #[inline] @@ -714,6 +728,9 @@ impl UndefMask { } pub fn grow(&mut self, amount: Size, new_state: bool) { + if amount.bytes() == 0 { + return; + } let unused_trailing_bits = self.blocks.len() as u64 * Self::BLOCK_SIZE - self.len.bytes(); if amount.bytes() > unused_trailing_bits { let additional_blocks = amount.bytes() / Self::BLOCK_SIZE + 1; diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 6cbb611c1a3ec..fba0a9af21392 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -815,7 +815,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // an optimization where we can just overwrite an entire range of definedness bits if // they are going to be uniformly `1` or `0`. if ranges.is_empty() { - dest_allocation.undef_mask.set_range( + dest_allocation.undef_mask.set_range_inbounds( dest.offset, dest.offset + size * repeat, first, diff --git a/src/test/run-pass-fulldeps/undef_mask.rs b/src/test/run-pass-fulldeps/undef_mask.rs index 37c44e2df6c5e..cf6e6f7231638 100644 --- a/src/test/run-pass-fulldeps/undef_mask.rs +++ b/src/test/run-pass-fulldeps/undef_mask.rs @@ -9,7 +9,7 @@ use rustc::mir::interpret::UndefMask; use rustc::ty::layout::Size; fn main() { - let mut mask = UndefMask::new(Size::from_bytes(500)); + let mut mask = UndefMask::new(Size::from_bytes(500), false); assert!(!mask.get(Size::from_bytes(499))); mask.set(Size::from_bytes(499), true); assert!(mask.get(Size::from_bytes(499))); From 876258b0fa31fc1d1a79ddc0e5a0c9c5f0e8f85b Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 6 Mar 2019 19:46:33 +0100 Subject: [PATCH 07/37] Default to integrated `rust-lld` linker for UEFI targets --- src/librustc_target/spec/uefi_base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_target/spec/uefi_base.rs b/src/librustc_target/spec/uefi_base.rs index 631966c09a498..956767a22a0e1 100644 --- a/src/librustc_target/spec/uefi_base.rs +++ b/src/librustc_target/spec/uefi_base.rs @@ -59,7 +59,7 @@ pub fn opts() -> TargetOptions { singlethread: true, emit_debug_gdb_scripts: false, - linker: Some("lld-link".to_string()), + linker: Some("rust-lld".to_string()), lld_flavor: LldFlavor::Link, pre_link_args, From 94a6936a692ed5e6f6c6a64d622d21ea4083e051 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 9 Mar 2019 14:28:25 +0800 Subject: [PATCH 08/37] Track embedded-book in the toolstate --- src/ci/docker/x86_64-gnu-tools/checktools.sh | 1 + src/tools/publish_toolstate.py | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 3343716419ff4..97e6ee25ec7a0 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -78,6 +78,7 @@ status_check() { check_dispatch $1 beta clippy-driver src/tools/clippy # these tools are not required for beta to successfully branch check_dispatch $1 nightly miri src/tools/miri + check_dispatch $1 nightly embedded-book src/doc/embedded-book } # If this PR is intended to update one of these tools, do not let the build pass diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index fb6132a5358ef..430db48954826 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -12,7 +12,7 @@ except ImportError: import urllib.request as urllib2 -# List of people to ping when the status of a tool changed. +# List of people to ping when the status of a tool or a book changed. MAINTAINERS = { 'miri': '@oli-obk @RalfJung @eddyb', 'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch', @@ -22,6 +22,7 @@ 'nomicon': '@frewsxcv @Gankro', 'reference': '@steveklabnik @Havvy @matthewjasper @alercah', 'rust-by-example': '@steveklabnik @marioidival @projektir', + 'embedded-book': '', } REPOS = { @@ -33,6 +34,7 @@ 'nomicon': 'https://github.com/rust-lang-nursery/nomicon', 'reference': 'https://github.com/rust-lang-nursery/reference', 'rust-by-example': 'https://github.com/rust-lang/rust-by-example', + 'embedded-book': 'https://github.com/rust-embedded/book', } @@ -70,7 +72,7 @@ def issue( cc @{}, the PR reviewer, and @rust-lang/compiler -- nominating for prioritization. - ''').format(relevant_pr_number, tool, REPOS[tool], relevant_pr_user, pr_reviewer), + ''').format(relevant_pr_number, tool, REPOS.get(tool), relevant_pr_user, pr_reviewer), 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number), 'assignees': assignees, 'labels': ['T-compiler', 'I-nominated'], @@ -137,7 +139,7 @@ def update_latest( if build_failed: try: issue( - tool, MAINTAINERS.get(tool), + tool, MAINTAINERS.get(tool, ''), relevant_pr_number, relevant_pr_user, pr_reviewer, ) except IOError as e: From bd2e12609f190e7bf206dac2de2d68dbb4b1b5e6 Mon Sep 17 00:00:00 2001 From: Dirk Leifeld Date: Sat, 9 Mar 2019 19:16:54 +0100 Subject: [PATCH 09/37] Revert "Revert "Add clamp functions"" --- src/libcore/cmp.rs | 26 ++++++++++++++++++++++++++ src/libstd/f32.rs | 20 ++++++++++++++++++++ src/libstd/f64.rs | 20 ++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 81fcdeee12d29..259135b9ca0ab 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -567,6 +567,32 @@ pub trait Ord: Eq + PartialOrd { where Self: Sized { if self <= other { self } else { other } } + + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this will return self. Panics if min > max. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where Self: Sized { + assert!(min <= max); + if self < min { + min + } + else if self > max { + max + } else { + self + } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index cb1f93581775c..df4dc2c779125 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -956,6 +956,26 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this returns self. Panics if min > max, min equals NaN, or max equals NaN. + /// + /// # Examples + /// + /// ``` + /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32); + /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32); + /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f32, max: f32) -> f32 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + } #[cfg(test)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 7fa7b80751938..00e7f27912817 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -878,6 +878,26 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this returns self. Panics if min > max, min equals NaN, or max equals NaN. + /// + /// # Examples + /// + /// ``` + /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64); + /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64); + /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64); + /// ``` + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f64, max: f64) -> f64 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g., log(-n) returns -Inf instead // of expected NaN). From 6041ec3b788a519ab740925c6b1c2f0ac19ad17d Mon Sep 17 00:00:00 2001 From: Dirk Leifeld Date: Sat, 9 Mar 2019 20:10:48 +0100 Subject: [PATCH 10/37] add feature clamp --- src/libstd/f32.rs | 1 + src/libstd/f64.rs | 1 + src/libstd/lib.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index df4dc2c779125..d158a6a5bccc8 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -962,6 +962,7 @@ impl f32 { /// # Examples /// /// ``` + /// #![feature(clamp)] /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32); /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32); /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32); diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 00e7f27912817..5be0cfa9b8f0a 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -884,6 +884,7 @@ impl f64 { /// # Examples /// /// ``` + /// #![feature(clamp)] /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64); /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64); /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 6dd3a6cc0fdbd..1c4918de42882 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -240,6 +240,7 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(checked_duration_since)] +#![feature(clamp)] #![feature(compiler_builtins_lib)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] From 135b686db41f67c4241144e25277a90092b014f4 Mon Sep 17 00:00:00 2001 From: James Munns Date: Sun, 10 Mar 2019 17:38:16 +0800 Subject: [PATCH 11/37] Update src/tools/publish_toolstate.py Co-Authored-By: kennytm --- src/tools/publish_toolstate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 430db48954826..6e06034db599a 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -22,7 +22,7 @@ 'nomicon': '@frewsxcv @Gankro', 'reference': '@steveklabnik @Havvy @matthewjasper @alercah', 'rust-by-example': '@steveklabnik @marioidival @projektir', - 'embedded-book': '', + 'embedded-book': '@adamgreig @andre-richter @jamesmunns @korken89 @ryankurte @thejpster @therealprof', } REPOS = { From d6f51006cd47ca3f1ccacc4e0faa345877653b81 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 10 Mar 2019 18:02:40 +0800 Subject: [PATCH 12/37] Fix tidy --- src/tools/publish_toolstate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 6e06034db599a..f2a585e627307 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -22,7 +22,10 @@ 'nomicon': '@frewsxcv @Gankro', 'reference': '@steveklabnik @Havvy @matthewjasper @alercah', 'rust-by-example': '@steveklabnik @marioidival @projektir', - 'embedded-book': '@adamgreig @andre-richter @jamesmunns @korken89 @ryankurte @thejpster @therealprof', + 'embedded-book': ( + '@adamgreig @andre-richter @jamesmunns @korken89 ' + '@ryankurte @thejpster @therealprof' + ), } REPOS = { From 8371377d16d12bff9d8a219ae85849c686917125 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 9 Mar 2019 15:48:58 -0800 Subject: [PATCH 13/37] CI: Set job names. This should make it easier to identify what each job is doing when looking at the Travis or Appveyor UI. - Set `name` for each job in Travis. - Move `CI_JOB_NAME` to the front in Appveyor so that it appears first in the UI. --- .travis.yml | 54 ++++++++++++++++++++++++++++++++++++++++++++------ appveyor.yml | 56 ++++++++++++++++++++++++++-------------------------- 2 files changed, 76 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7985b6c0e191f..7a8772d7abd63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,20 +12,27 @@ git: depth: 2 submodules: false +env: + global: + - CI_JOB_NAME=$TRAVIS_JOB_NAME + matrix: fast_finish: true include: # Images used in testing PR and try-build should be run first. - env: IMAGE=x86_64-gnu-llvm-6.0 RUST_BACKTRACE=1 + name: x86_64-gnu-llvm-6.0 if: type = pull_request OR branch = auto - env: IMAGE=dist-x86_64-linux DEPLOY=1 + name: dist-x86_64-linux if: branch = try OR branch = auto # "alternate" deployments, these are "nightlies" but have LLVM assertions # turned on, they're deployed to a different location primarily for # additional testing. - - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 CI_JOB_NAME=dist-x86_64-linux-alt + - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 + name: dist-x86_64-linux-alt if: branch = try OR branch = auto - env: > @@ -37,9 +44,9 @@ matrix: MACOSX_DEPLOYMENT_TARGET=10.7 NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=dist-x86_64-apple-alt os: osx osx_image: xcode9.3-moar + name: dist-x86_64-apple-alt if: branch = auto # macOS builders. These are placed near the beginning because they are very @@ -60,9 +67,9 @@ matrix: MACOSX_STD_DEPLOYMENT_TARGET=10.7 NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=x86_64-apple os: osx osx_image: xcode9.3-moar + name: x86_64-apple if: branch = auto - env: > @@ -74,9 +81,9 @@ matrix: MACOSX_STD_DEPLOYMENT_TARGET=10.7 NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 - CI_JOB_NAME=i686-apple os: osx osx_image: xcode9.3-moar + name: i686-apple if: branch = auto # OSX builders producing releases. These do not run the full test suite and @@ -95,9 +102,9 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 DIST_REQUIRE_ALL_TOOLS=1 - CI_JOB_NAME=dist-i686-apple os: osx osx_image: xcode9.3-moar + name: dist-i686-apple if: branch = auto - env: > @@ -110,81 +117,116 @@ matrix: NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1 DIST_REQUIRE_ALL_TOOLS=1 - CI_JOB_NAME=dist-x86_64-apple os: osx osx_image: xcode9.3-moar + name: dist-x86_64-apple if: branch = auto # Linux builders, remaining docker images - env: IMAGE=arm-android + name: arm-android if: branch = auto - env: IMAGE=armhf-gnu + name: armhf-gnu if: branch = auto - env: IMAGE=dist-various-1 DEPLOY=1 + name: dist-various-1 if: branch = auto - env: IMAGE=dist-various-2 DEPLOY=1 + name: dist-various-2 if: branch = auto - env: IMAGE=dist-aarch64-linux DEPLOY=1 + name: dist-aarch64-linux if: branch = auto - env: IMAGE=dist-android DEPLOY=1 + name: dist-android if: branch = auto - env: IMAGE=dist-arm-linux DEPLOY=1 + name: dist-arm-linux if: branch = auto - env: IMAGE=dist-armhf-linux DEPLOY=1 + name: dist-armhf-linux if: branch = auto - env: IMAGE=dist-armv7-linux DEPLOY=1 + name: dist-armv7-linux if: branch = auto - env: IMAGE=dist-i586-gnu-i586-i686-musl DEPLOY=1 + name: dist-i586-gnu-i586-i686-musl if: branch = auto - env: IMAGE=dist-i686-freebsd DEPLOY=1 + name: dist-i686-freebsd if: branch = auto - env: IMAGE=dist-i686-linux DEPLOY=1 + name: dist-i686-linux if: branch = auto - env: IMAGE=dist-mips-linux DEPLOY=1 + name: dist-mips-linux if: branch = auto - env: IMAGE=dist-mips64-linux DEPLOY=1 + name: dist-mips64-linux if: branch = auto - env: IMAGE=dist-mips64el-linux DEPLOY=1 + name: dist-mips64el-linux if: branch = auto - env: IMAGE=dist-mipsel-linux DEPLOY=1 + name: dist-mipsel-linux if: branch = auto - env: IMAGE=dist-powerpc-linux DEPLOY=1 + name: dist-powerpc-linux if: branch = auto - env: IMAGE=dist-powerpc64-linux DEPLOY=1 + name: dist-powerpc64-linux if: branch = auto - env: IMAGE=dist-powerpc64le-linux DEPLOY=1 + name: dist-powerpc64le-linux if: branch = auto - env: IMAGE=dist-s390x-linux DEPLOY=1 + name: dist-s390x-linux if: branch = auto - env: IMAGE=dist-x86_64-freebsd DEPLOY=1 + name: dist-x86_64-freebsd if: branch = auto - env: IMAGE=dist-x86_64-musl DEPLOY=1 + name: dist-x86_64-musl if: branch = auto - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 + name: dist-x86_64-netbsd if: branch = auto - env: IMAGE=asmjs + name: asmjs if: branch = auto - env: IMAGE=i686-gnu + name: i686-gnu if: branch = auto - env: IMAGE=i686-gnu-nopt + name: i686-gnu-nopt if: branch = auto - env: IMAGE=test-various + name: test-various if: branch = auto - env: IMAGE=x86_64-gnu + name: x86_64-gnu if: branch = auto - env: IMAGE=x86_64-gnu-full-bootstrap + name: x86_64-gnu-full-bootstrap if: branch = auto - env: IMAGE=x86_64-gnu-aux + name: x86_64-gnu-aux if: branch = auto - env: IMAGE=x86_64-gnu-tools + name: x86_64-gnu-tools if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri|cargo)\b)/) - env: IMAGE=x86_64-gnu-debug + name: x86_64-gnu-debug if: branch = auto - env: IMAGE=x86_64-gnu-nopt + name: x86_64-gnu-nopt if: branch = auto - env: IMAGE=x86_64-gnu-distcheck + name: x86_64-gnu-distcheck if: branch = auto - env: IMAGE=mingw-check + name: mingw-check if: type = pull_request OR branch = auto - stage: publish toolstate diff --git a/appveyor.yml b/appveyor.yml index d70ad54b1c812..040e21cba9682 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,34 +7,34 @@ environment: matrix: # 32/64 bit MSVC tests - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc + MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: python x.py test - CI_JOB_NAME: x86_64-msvc - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-msvc-1 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make appveyor-subset-1 - CI_JOB_NAME: i686-msvc-1 - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-msvc-2 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make appveyor-subset-2 - CI_JOB_NAME: i686-msvc-2 # MSVC aux tests - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc-aux + MSYS_BITS: 64 RUST_CHECK_TARGET: check-aux EXCLUDE_CARGO=1 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc - CI_JOB_NAME: x86_64-msvc-aux - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc-cargo + MSYS_BITS: 64 SCRIPT: python x.py test src/tools/cargotest src/tools/cargo RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc - CI_JOB_NAME: x86_64-msvc-cargo # MSVC tools tests - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-msvc-tools + MSYS_BITS: 64 SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json --enable-test-miri - CI_JOB_NAME: x86_64-msvc-tools # 32/64-bit MinGW builds. # @@ -49,30 +49,31 @@ environment: # bucket, but they cleraly didn't originate there! The downloads originally # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-mingw-1 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make appveyor-subset-1 MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 - CI_JOB_NAME: i686-mingw-1 - - MSYS_BITS: 32 + - CI_JOB_NAME: i686-mingw-2 + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make appveyor-subset-2 MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 - CI_JOB_NAME: i686-mingw-2 - - MSYS_BITS: 64 + - CI_JOB_NAME: x86_64-mingw + MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 - CI_JOB_NAME: x86_64-mingw # 32/64 bit MSVC and GNU deployment - - RUST_CONFIGURE_ARGS: > + - CI_JOB_NAME: dist-x86_64-msvc + RUST_CONFIGURE_ARGS: > --build=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools @@ -80,9 +81,9 @@ environment: SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 - CI_JOB_NAME: dist-x86_64-msvc APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 Preview - - RUST_CONFIGURE_ARGS: > + - CI_JOB_NAME: dist-i686-msvc + RUST_CONFIGURE_ARGS: > --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-full-tools @@ -90,8 +91,8 @@ environment: SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 - CI_JOB_NAME: dist-i686-msvc - - MSYS_BITS: 32 + - CI_JOB_NAME: dist-i686-mingw + MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools SCRIPT: python x.py dist MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror @@ -99,8 +100,8 @@ environment: MINGW_DIR: mingw32 DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 - CI_JOB_NAME: dist-i686-mingw - - MSYS_BITS: 64 + - CI_JOB_NAME: dist-x86_64-mingw + MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror @@ -108,14 +109,13 @@ environment: MINGW_DIR: mingw64 DIST_REQUIRE_ALL_TOOLS: 1 DEPLOY: 1 - CI_JOB_NAME: dist-x86_64-mingw # "alternate" deployment, see .travis.yml for more info - - MSYS_BITS: 64 + - CI_JOB_NAME: dist-x86_64-msvc-alt + MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler SCRIPT: python x.py dist DEPLOY_ALT: 1 - CI_JOB_NAME: dist-x86_64-msvc-alt matrix: fast_finish: true From 4888b1fb99f1bf6a58bebaededdfbf4477383634 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Mar 2019 17:45:45 +0100 Subject: [PATCH 14/37] we can now skip should_panic tests with the libtest harness --- src/liballoc/tests/binary_heap.rs | 2 +- src/liballoc/tests/btree/map.rs | 5 ----- src/liballoc/tests/slice.rs | 18 ------------------ src/liballoc/tests/str.rs | 11 ----------- src/liballoc/tests/string.rs | 9 --------- src/liballoc/tests/vec.rs | 12 ------------ src/liballoc/tests/vec_deque.rs | 1 - src/libcore/tests/cell.rs | 3 --- src/libcore/tests/iter.rs | 2 -- src/libcore/tests/num/bignum.rs | 14 -------------- src/libcore/tests/option.rs | 3 --- src/libcore/tests/result.rs | 3 --- src/libcore/tests/slice.rs | 7 ------- src/libcore/tests/time.rs | 2 -- 14 files changed, 1 insertion(+), 91 deletions(-) diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 1d4a3edc1ac42..a97a790f5a2d8 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -282,7 +282,7 @@ fn assert_covariance() { // // Destructors must be called exactly once per element. #[test] -#[cfg(not(miri))] // Miri does not support panics +#[cfg(not(miri))] // Miri does not support entropy fn panic_safe() { static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index f14750089c956..844afe870766b 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -226,7 +226,6 @@ fn test_range_equal_empty_cases() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_equal_excluded() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Excluded(2), Excluded(2))); @@ -234,7 +233,6 @@ fn test_range_equal_excluded() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_1() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Included(3), Included(2))); @@ -242,7 +240,6 @@ fn test_range_backwards_1() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_2() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Included(3), Excluded(2))); @@ -250,7 +247,6 @@ fn test_range_backwards_2() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_3() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Excluded(3), Included(2))); @@ -258,7 +254,6 @@ fn test_range_backwards_3() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_range_backwards_4() { let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect(); map.range((Excluded(3), Excluded(2))); diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index feba46b0fad78..fb99c95fc6842 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -258,7 +258,6 @@ fn test_swap_remove() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_swap_remove_fail() { let mut v = vec![1]; let _ = v.swap_remove(0); @@ -632,7 +631,6 @@ fn test_insert() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_insert_oob() { let mut a = vec![1, 2, 3]; a.insert(4, 5); @@ -657,7 +655,6 @@ fn test_remove() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_remove_fail() { let mut a = vec![1]; let _ = a.remove(0); @@ -939,7 +936,6 @@ fn test_windowsator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_windowsator_0() { let v = &[1, 2, 3, 4]; let _it = v.windows(0); @@ -964,7 +960,6 @@ fn test_chunksator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_chunksator_0() { let v = &[1, 2, 3, 4]; let _it = v.chunks(0); @@ -989,7 +984,6 @@ fn test_chunks_exactator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_chunks_exactator_0() { let v = &[1, 2, 3, 4]; let _it = v.chunks_exact(0); @@ -1014,7 +1008,6 @@ fn test_rchunksator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_rchunksator_0() { let v = &[1, 2, 3, 4]; let _it = v.rchunks(0); @@ -1039,7 +1032,6 @@ fn test_rchunks_exactator() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_rchunks_exactator_0() { let v = &[1, 2, 3, 4]; let _it = v.rchunks_exact(0); @@ -1092,7 +1084,6 @@ fn test_vec_default() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_overflow_does_not_cause_segfault() { let mut v = vec![]; v.reserve_exact(!0); @@ -1102,7 +1093,6 @@ fn test_overflow_does_not_cause_segfault() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_overflow_does_not_cause_segfault_managed() { let mut v = vec![Rc::new(1)]; v.reserve_exact(!0); @@ -1278,7 +1268,6 @@ fn test_mut_chunks_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_chunks_0() { let mut v = [1, 2, 3, 4]; let _it = v.chunks_mut(0); @@ -1311,7 +1300,6 @@ fn test_mut_chunks_exact_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_chunks_exact_0() { let mut v = [1, 2, 3, 4]; let _it = v.chunks_exact_mut(0); @@ -1344,7 +1332,6 @@ fn test_mut_rchunks_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_rchunks_0() { let mut v = [1, 2, 3, 4]; let _it = v.rchunks_mut(0); @@ -1377,7 +1364,6 @@ fn test_mut_rchunks_exact_rev() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mut_rchunks_exact_0() { let mut v = [1, 2, 3, 4]; let _it = v.rchunks_exact_mut(0); @@ -1411,7 +1397,6 @@ fn test_box_slice_clone() { #[test] #[allow(unused_must_use)] // here, we care about the side effects of `.clone()` #[cfg_attr(target_os = "emscripten", ignore)] -#[cfg(not(miri))] // Miri does not support panics fn test_box_slice_clone_panics() { use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -1476,7 +1461,6 @@ fn test_copy_from_slice() { #[test] #[should_panic(expected = "destination and source slices have different lengths")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_from_slice_dst_longer() { let src = [0, 1, 2, 3]; let mut dst = [0; 5]; @@ -1485,7 +1469,6 @@ fn test_copy_from_slice_dst_longer() { #[test] #[should_panic(expected = "destination and source slices have different lengths")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_from_slice_dst_shorter() { let src = [0, 1, 2, 3]; let mut dst = [0; 3]; @@ -1605,7 +1588,6 @@ thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); #[test] #[cfg_attr(target_os = "emscripten", ignore)] // no threads -#[cfg(not(miri))] // Miri does not support panics fn panic_safe() { let prev = panic::take_hook(); panic::set_hook(Box::new(move |info| { diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index b33a564218888..f2dc19a42296a 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -351,7 +351,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "out of bounds")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_panic() { assert_range_eq!("abc", 0..5, "abc"); } @@ -361,7 +360,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "==")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_inequality() { assert_range_eq!("abc", 0..2, "abc"); } @@ -409,7 +407,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_fail() { let v: String = $data.into(); let v: &str = &v; @@ -418,7 +415,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_mut_fail() { let mut v: String = $data.into(); let v: &mut str = &mut v; @@ -514,7 +510,6 @@ mod slice_index { #[test] #[should_panic] - #[cfg(not(miri))] // Miri does not support panics fn test_slice_fail() { &"中华Việt Nam"[0..2]; } @@ -666,14 +661,12 @@ mod slice_index { // check the panic includes the prefix of the sliced string #[test] #[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] - #[cfg(not(miri))] // Miri does not support panics fn test_slice_fail_truncated_1() { &LOREM_PARAGRAPH[..1024]; } // check the truncation in the panic message #[test] #[should_panic(expected="luctus, im`[...]")] - #[cfg(not(miri))] // Miri does not support panics fn test_slice_fail_truncated_2() { &LOREM_PARAGRAPH[..1024]; } @@ -688,7 +681,6 @@ fn test_str_slice_rangetoinclusive_ok() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_str_slice_rangetoinclusive_notok() { let s = "abcαβγ"; &s[..=3]; @@ -704,7 +696,6 @@ fn test_str_slicemut_rangetoinclusive_ok() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_str_slicemut_rangetoinclusive_notok() { let mut s = "abcαβγ".to_owned(); let s: &mut str = &mut s; @@ -894,7 +885,6 @@ fn test_as_bytes() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_as_bytes_fail() { // Don't double free. (I'm not sure if this exercises the // original problem code path anymore.) @@ -984,7 +974,6 @@ fn test_split_at_mut() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_split_at_boundscheck() { let s = "ศไทย中华Việt Nam"; s.split_at(1); diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 7e93d84fe3b97..7e75b8c4f28c8 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -231,7 +231,6 @@ fn test_split_off_empty() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_split_off_past_end() { let orig = "Hello, world!"; let mut split = String::from(orig); @@ -240,7 +239,6 @@ fn test_split_off_past_end() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_split_off_mid_char() { let mut orig = String::from("山"); orig.split_off(1); @@ -289,7 +287,6 @@ fn test_str_truncate_invalid_len() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_str_truncate_split_codepoint() { let mut s = String::from("\u{FC}"); // ü s.truncate(1); @@ -324,7 +321,6 @@ fn remove() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn remove_bad() { "ศ".to_string().remove(1); } @@ -360,13 +356,11 @@ fn insert() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn insert_bad1() { "".to_string().insert(1, 't'); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn insert_bad2() { "ệ".to_string().insert(1, 't'); } @@ -447,7 +441,6 @@ fn test_replace_range() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_replace_range_char_boundary() { let mut s = "Hello, 世界!".to_owned(); s.replace_range(..8, ""); @@ -464,7 +457,6 @@ fn test_replace_range_inclusive_range() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_replace_range_out_of_bounds() { let mut s = String::from("12345"); s.replace_range(5..6, "789"); @@ -472,7 +464,6 @@ fn test_replace_range_out_of_bounds() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_replace_range_inclusive_out_of_bounds() { let mut s = String::from("12345"); s.replace_range(5..=5, "789"); diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 6e4ca1d90e642..545332bcd6a2f 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -368,7 +368,6 @@ fn test_vec_truncate_drop() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_vec_truncate_fail() { struct BadElem(i32); impl Drop for BadElem { @@ -392,7 +391,6 @@ fn test_index() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_index_out_of_bounds() { let vec = vec![1, 2, 3]; let _ = vec[3]; @@ -400,7 +398,6 @@ fn test_index_out_of_bounds() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_1() { let x = vec![1, 2, 3, 4, 5]; &x[!0..]; @@ -408,7 +405,6 @@ fn test_slice_out_of_bounds_1() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_2() { let x = vec![1, 2, 3, 4, 5]; &x[..6]; @@ -416,7 +412,6 @@ fn test_slice_out_of_bounds_2() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_3() { let x = vec![1, 2, 3, 4, 5]; &x[!0..4]; @@ -424,7 +419,6 @@ fn test_slice_out_of_bounds_3() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_4() { let x = vec![1, 2, 3, 4, 5]; &x[1..6]; @@ -432,7 +426,6 @@ fn test_slice_out_of_bounds_4() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_slice_out_of_bounds_5() { let x = vec![1, 2, 3, 4, 5]; &x[3..2]; @@ -440,7 +433,6 @@ fn test_slice_out_of_bounds_5() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_swap_remove_empty() { let mut vec = Vec::::new(); vec.swap_remove(0); @@ -511,7 +503,6 @@ fn test_drain_items_zero_sized() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_drain_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; v.drain(5..6); @@ -585,7 +576,6 @@ fn test_drain_max_vec_size() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_drain_inclusive_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; v.drain(5..=5); @@ -615,7 +605,6 @@ fn test_splice_inclusive_range() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_splice_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; @@ -624,7 +613,6 @@ fn test_splice_out_of_bounds() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_splice_inclusive_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 16ddc1444fcf9..e0fe10a55f55c 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -108,7 +108,6 @@ fn test_index() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_index_out_of_bounds() { let mut deq = VecDeque::new(); for i in 1..4 { diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index b16416022c04e..56f295dff8e43 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -109,7 +109,6 @@ fn double_borrow_single_release_no_borrow_mut() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn discard_doesnt_unborrow() { let x = RefCell::new(0); let _b = x.borrow(); @@ -350,7 +349,6 @@ fn refcell_ref_coercion() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn refcell_swap_borrows() { let x = RefCell::new(0); let _b = x.borrow(); @@ -360,7 +358,6 @@ fn refcell_swap_borrows() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn refcell_replace_borrows() { let x = RefCell::new(0); let _b = x.borrow(); diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index d880abb181c20..4652fc329dc02 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -253,7 +253,6 @@ fn test_iterator_step_by_nth_overflow() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_iterator_step_by_zero() { let mut it = (0..).step_by(0); it.next(); @@ -1414,7 +1413,6 @@ fn test_rposition() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_rposition_panic() { let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), diff --git a/src/libcore/tests/num/bignum.rs b/src/libcore/tests/num/bignum.rs index 956c22c998219..b873f1dd0652f 100644 --- a/src/libcore/tests/num/bignum.rs +++ b/src/libcore/tests/num/bignum.rs @@ -3,7 +3,6 @@ use core::num::bignum::tests::Big8x3 as Big; #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_from_u64_overflow() { Big::from_u64(0x1000000); } @@ -20,14 +19,12 @@ fn test_add() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_add_overflow_1() { Big::from_small(1).add(&Big::from_u64(0xffffff)); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_add_overflow_2() { Big::from_u64(0xffffff).add(&Big::from_small(1)); } @@ -45,7 +42,6 @@ fn test_add_small() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_add_small_overflow() { Big::from_u64(0xffffff).add_small(1); } @@ -61,14 +57,12 @@ fn test_sub() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_sub_underflow_1() { Big::from_u64(0x10665).sub(&Big::from_u64(0x10666)); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_sub_underflow_2() { Big::from_small(0).sub(&Big::from_u64(0x123456)); } @@ -82,7 +76,6 @@ fn test_mul_small() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_small_overflow() { Big::from_u64(0x800000).mul_small(2); } @@ -101,14 +94,12 @@ fn test_mul_pow2() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow2_overflow_1() { Big::from_u64(0x1).mul_pow2(24); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow2_overflow_2() { Big::from_u64(0x123).mul_pow2(16); } @@ -127,14 +118,12 @@ fn test_mul_pow5() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow5_overflow_1() { Big::from_small(1).mul_pow5(12); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_pow5_overflow_2() { Big::from_small(230).mul_pow5(8); } @@ -152,14 +141,12 @@ fn test_mul_digits() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_digits_overflow_1() { Big::from_u64(0x800000).mul_digits(&[2]); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_mul_digits_overflow_2() { Big::from_u64(0x1000).mul_digits(&[0, 0x10]); } @@ -219,7 +206,6 @@ fn test_get_bit() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_get_bit_out_of_range() { Big::from_small(42).get_bit(24); } diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 87ce2720c5918..b059b134868d9 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -69,7 +69,6 @@ fn test_option_dance() { } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_option_too_much_dance() { struct A; let mut y = Some(A); @@ -130,7 +129,6 @@ fn test_unwrap() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_unwrap_panic1() { let x: Option = None; x.unwrap(); @@ -138,7 +136,6 @@ fn test_unwrap_panic1() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn test_unwrap_panic2() { let x: Option = None; x.unwrap(); diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index bbc8568517667..1fab07526a07f 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -117,7 +117,6 @@ fn test_unwrap_or_else() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics pub fn test_unwrap_or_else_panic() { fn handler(msg: &'static str) -> isize { if msg == "I got this." { @@ -139,7 +138,6 @@ pub fn test_expect_ok() { } #[test] #[should_panic(expected="Got expected error: \"All good\"")] -#[cfg(not(miri))] // Miri does not support panics pub fn test_expect_err() { let err: Result = Err("All good"); err.expect("Got expected error"); @@ -153,7 +151,6 @@ pub fn test_expect_err_err() { } #[test] #[should_panic(expected="Got expected ok: \"All good\"")] -#[cfg(not(miri))] // Miri does not support panics pub fn test_expect_err_ok() { let err: Result<&'static str, isize> = Ok("All good"); err.expect_err("Got expected ok"); diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 31d16e0e32057..ac9c17a0f7c35 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -782,7 +782,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "out of range")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_panic() { assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]); } @@ -792,7 +791,6 @@ mod slice_index { // to be used in `should_panic`) #[test] #[should_panic(expected = "==")] - #[cfg(not(miri))] // Miri does not support panics fn assert_range_eq_can_fail_by_inequality() { assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]); } @@ -842,7 +840,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_fail() { let v = $data; let v: &[_] = &v; @@ -851,7 +848,6 @@ mod slice_index { #[test] #[should_panic(expected = $expect_msg)] - #[cfg(not(miri))] // Miri does not support panics fn index_mut_fail() { let mut v = $data; let v: &mut [_] = &mut v; @@ -1304,7 +1300,6 @@ fn test_copy_within() { #[test] #[should_panic(expected = "src is out of bounds")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_within_panics_src_too_long() { let mut bytes = *b"Hello, World!"; // The length is only 13, so 14 is out of bounds. @@ -1313,7 +1308,6 @@ fn test_copy_within_panics_src_too_long() { #[test] #[should_panic(expected = "dest is out of bounds")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_within_panics_dest_too_long() { let mut bytes = *b"Hello, World!"; // The length is only 13, so a slice of length 4 starting at index 10 is out of bounds. @@ -1321,7 +1315,6 @@ fn test_copy_within_panics_dest_too_long() { } #[test] #[should_panic(expected = "src end is before src start")] -#[cfg(not(miri))] // Miri does not support panics fn test_copy_within_panics_src_inverted() { let mut bytes = *b"Hello, World!"; // 2 is greater than 1, so this range is invalid. diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 09aae4583482f..6efd22572dc18 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -107,14 +107,12 @@ fn checked_sub() { #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn sub_bad1() { let _ = Duration::new(0, 0) - Duration::new(0, 1); } #[test] #[should_panic] -#[cfg(not(miri))] // Miri does not support panics fn sub_bad2() { let _ = Duration::new(0, 0) - Duration::new(1, 0); } From 52d9fa827d3cf5ef5fc0e2042ca1fc7f6dc391ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Mar 2019 17:52:45 +0100 Subject: [PATCH 15/37] enabled too many tests --- src/liballoc/tests/binary_heap.rs | 2 +- src/liballoc/tests/slice.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index a97a790f5a2d8..0930f8dacd494 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -282,7 +282,7 @@ fn assert_covariance() { // // Destructors must be called exactly once per element. #[test] -#[cfg(not(miri))] // Miri does not support entropy +#[cfg(not(miri))] // Miri does not support panics nor entropy fn panic_safe() { static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index fb99c95fc6842..b54c128a0249a 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -1397,6 +1397,7 @@ fn test_box_slice_clone() { #[test] #[allow(unused_must_use)] // here, we care about the side effects of `.clone()` #[cfg_attr(target_os = "emscripten", ignore)] +#[cfg(not(miri))] // Miri does not support threads nor entropy fn test_box_slice_clone_panics() { use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -1588,6 +1589,7 @@ thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); #[test] #[cfg_attr(target_os = "emscripten", ignore)] // no threads +#[cfg(not(miri))] // Miri does not support threads nor entropy fn panic_safe() { let prev = panic::take_hook(); panic::set_hook(Box::new(move |info| { From 537d4dd98a647905434ddd449b490133c65e0ab2 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 28 Feb 2019 13:54:19 -0500 Subject: [PATCH 16/37] overhaul intra-doc-link ambiguity warning - Makes the warning part of the `intra_doc_link_resolution_failure` lint. - Tightens the span to just the ambiguous link. - Reports ambiguities across all three namespaces. - Uses structured suggestions for disambiguation. - Adds a test for the warnings. --- .../passes/collect_intra_doc_links.rs | 240 +++++++++++------- src/test/rustdoc-ui/intra-links-ambiguity.rs | 36 +++ .../rustdoc-ui/intra-links-ambiguity.stderr | 82 ++++++ src/test/rustdoc/intra-links.rs | 3 +- 4 files changed, 266 insertions(+), 95 deletions(-) create mode 100644 src/test/rustdoc-ui/intra-links-ambiguity.rs create mode 100644 src/test/rustdoc-ui/intra-links-ambiguity.stderr diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fefff1f3a7593..36bfe2fb2c3da 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,7 +1,8 @@ -use rustc::lint as lint; -use rustc::hir; +use errors::Applicability; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; +use rustc::hir; +use rustc::lint as lint; use rustc::ty; use syntax; use syntax::ast::{self, Ident}; @@ -53,6 +54,13 @@ struct LinkCollector<'a, 'tcx> { is_nightly_build: bool, } +#[derive(Debug, Copy, Clone)] +enum Namespace { + Type, + Value, + Macro, +} + impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn new(cx: &'a DocContext<'tcx>) -> Self { LinkCollector { @@ -345,57 +353,52 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } PathKind::Unknown => { // Try everything! + let mut candidates = vec![]; + if let Some(macro_def) = macro_resolve(cx, path_str) { - if let Ok(type_def) = - self.resolve(path_str, false, ¤t_item, parent_node) - { - let (type_kind, article, type_disambig) - = type_ns_kind(type_def.0, path_str); - ambiguity_error(cx, &item.attrs, path_str, - article, type_kind, &type_disambig, - "a", "macro", &format!("macro@{}", path_str)); - continue; - } else if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - let (value_kind, value_disambig) - = value_ns_kind(value_def.0, path_str) - .expect("struct and mod cases should have been \ - caught in previous branch"); - ambiguity_error(cx, &item.attrs, path_str, - "a", value_kind, &value_disambig, - "a", "macro", &format!("macro@{}", path_str)); - } - (macro_def, None) - } else if let Ok(type_def) = + candidates.push(((macro_def, None), Namespace::Macro)); + } + + if let Ok(type_def) = self.resolve(path_str, false, ¤t_item, parent_node) { - // It is imperative we search for not-a-value first - // Otherwise we will find struct ctors for when we are looking - // for structs, and the link won't work if there is something in - // both namespaces. - if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - let kind = value_ns_kind(value_def.0, path_str); - if let Some((value_kind, value_disambig)) = kind { - let (type_kind, article, type_disambig) - = type_ns_kind(type_def.0, path_str); - ambiguity_error(cx, &item.attrs, path_str, - article, type_kind, &type_disambig, - "a", value_kind, &value_disambig); - continue; - } - } - type_def - } else if let Ok(value_def) = + candidates.push((type_def, Namespace::Type)); + } + + if let Ok(value_def) = self.resolve(path_str, true, ¤t_item, parent_node) { - value_def - } else { + // Structs, variants, and mods exist in both namespaces, skip them. + match value_def.0 { + Def::StructCtor(..) + | Def::Mod(..) + | Def::Variant(..) + | Def::VariantCtor(..) + | Def::SelfCtor(..) => (), + _ => candidates.push((value_def, Namespace::Value)), + } + } + + if candidates.len() == 1 { + candidates.remove(0).0 + } else if candidates.is_empty() { resolution_failure(cx, &item.attrs, path_str, &dox, link_range); // this could just be a normal link continue; + } else { + let candidates = candidates.into_iter().map(|((def, _), ns)| { + (def, ns) + }).collect::>(); + + ambiguity_error( + cx, + &item.attrs, + path_str, + &dox, + link_range, + &candidates, + ); + continue; } } PathKind::Macro => { @@ -505,59 +508,108 @@ fn resolution_failure( diag.emit(); } -fn ambiguity_error(cx: &DocContext<'_>, attrs: &Attributes, - path_str: &str, - article1: &str, kind1: &str, disambig1: &str, - article2: &str, kind2: &str, disambig2: &str) { +fn ambiguity_error( + cx: &DocContext<'_>, + attrs: &Attributes, + path_str: &str, + dox: &str, + link_range: Option>, + candidates: &[(Def, Namespace)], +) { let sp = span_of_attrs(attrs); - cx.sess() - .struct_span_warn(sp, - &format!("`{}` is both {} {} and {} {}", - path_str, article1, kind1, - article2, kind2)) - .help(&format!("try `{}` if you want to select the {}, \ - or `{}` if you want to \ - select the {}", - disambig1, kind1, disambig2, - kind2)) - .emit(); -} -/// Given a def, returns its name and disambiguator -/// for a value namespace. -/// -/// Returns `None` for things which cannot be ambiguous since -/// they exist in both namespaces (structs and modules). -fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> { - match def { - // Structs, variants, and mods exist in both namespaces; skip them. - Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | - Def::VariantCtor(..) | Def::SelfCtor(..) - => None, - Def::Fn(..) - => Some(("function", format!("{}()", path_str))), - Def::Method(..) - => Some(("method", format!("{}()", path_str))), - Def::Const(..) - => Some(("const", format!("const@{}", path_str))), - Def::Static(..) - => Some(("static", format!("static@{}", path_str))), - _ => Some(("value", format!("value@{}", path_str))), + let mut msg = format!("`{}` is ", path_str); + + match candidates { + [(first_def, _), (second_def, _)] => { + msg += &format!( + "both {} {} and {} {}", + first_def.article(), + first_def.kind_name(), + second_def.article(), + second_def.kind_name(), + ); + } + _ => { + let mut candidates = candidates.iter().peekable(); + while let Some((def, _)) = candidates.next() { + if candidates.peek().is_some() { + msg += &format!("{} {}, ", def.article(), def.kind_name()); + } else { + msg += &format!("and {} {}", def.article(), def.kind_name()); + } + } + } } -} -/// Given a def, returns its name, the article to be used, and a disambiguator -/// for the type namespace. -fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) { - let (kind, article) = match def { - // We can still have non-tuple structs. - Def::Struct(..) => ("struct", "a"), - Def::Enum(..) => ("enum", "an"), - Def::Trait(..) => ("trait", "a"), - Def::Union(..) => ("union", "a"), - _ => ("type", "a"), - }; - (kind, article, format!("{}@{}", kind, path_str)) + let mut diag = cx.tcx.struct_span_lint_hir( + lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, + hir::CRATE_HIR_ID, + sp, + &msg, + ); + + if let Some(link_range) = link_range { + if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) { + diag.set_span(sp); + diag.span_label(sp, "ambiguous link"); + + for (def, ns) in candidates { + let (action, mut suggestion) = match def { + Def::Method(..) | Def::Fn(..) => { + ("add parentheses", format!("{}()", path_str)) + } + _ => { + let type_ = match (def, ns) { + (Def::Const(..), _) => "const", + (Def::Static(..), _) => "static", + (Def::Struct(..), _) => "struct", + (Def::Enum(..), _) => "enum", + (Def::Union(..), _) => "union", + (Def::Trait(..), _) => "trait", + (Def::Mod(..), _) => "module", + (_, Namespace::Type) => "type", + (_, Namespace::Value) => "value", + (_, Namespace::Macro) => "macro", + }; + + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + ("prefix with the item type", format!("{}@{}", type_, path_str)) + } + }; + + if dox.bytes().nth(link_range.start) == Some(b'`') { + suggestion = format!("`{}`", suggestion); + } + + diag.span_suggestion( + sp, + &format!("to link to the {}, {}", def.kind_name(), action), + suggestion, + Applicability::MaybeIncorrect, + ); + } + } else { + // blah blah blah\nblah\nblah [blah] blah blah\nblah blah + // ^ ~~~~ + // | link_range + // last_new_line_offset + let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1); + let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); + + // Print the line containing the `link_range` and manually mark it with '^'s. + diag.note(&format!( + "the link appears in this line:\n\n{line}\n\ + {indicator: {} } + +#[allow(non_camel_case_types)] +pub struct multi_conflict {} + +pub fn multi_conflict() {} + +pub mod type_and_value {} + +pub const type_and_value: i32 = 0; + +pub mod foo { + pub enum bar {} + + pub fn bar() {} +} + +/// [`ambiguous`] is ambiguous. //~ERROR `ambiguous` +/// +/// [ambiguous] is ambiguous. //~ERROR ambiguous +/// +/// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` +/// +/// Ambiguous [type_and_value]. //~ERROR type_and_value +/// +/// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` +pub struct Docs {} diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr new file mode 100644 index 0000000000000..5b8978e3053b6 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -0,0 +1,82 @@ +error: `ambiguous` is both a struct and a function + --> $DIR/intra-links-ambiguity.rs:27:6 + | +LL | /// [`ambiguous`] is ambiguous. //~ERROR `ambiguous` + | ^^^^^^^^^^^ ambiguous link + | +note: lint level defined here + --> $DIR/intra-links-ambiguity.rs:1:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the struct, prefix with the item type + | +LL | /// [`struct@ambiguous`] is ambiguous. //~ERROR `ambiguous` + | ^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [`ambiguous()`] is ambiguous. //~ERROR `ambiguous` + | ^^^^^^^^^^^^^ + +error: `ambiguous` is both a struct and a function + --> $DIR/intra-links-ambiguity.rs:29:6 + | +LL | /// [ambiguous] is ambiguous. //~ERROR ambiguous + | ^^^^^^^^^ ambiguous link +help: to link to the struct, prefix with the item type + | +LL | /// [struct@ambiguous] is ambiguous. //~ERROR ambiguous + | ^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [ambiguous()] is ambiguous. //~ERROR ambiguous + | ^^^^^^^^^^^ + +error: `multi_conflict` is a macro, a struct, and a function + --> $DIR/intra-links-ambiguity.rs:31:6 + | +LL | /// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^ ambiguous link +help: to link to the macro, prefix with the item type + | +LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the struct, prefix with the item type + | +LL | /// [`struct@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^^ + +error: `type_and_value` is both a module and a constant + --> $DIR/intra-links-ambiguity.rs:33:16 + | +LL | /// Ambiguous [type_and_value]. //~ERROR type_and_value + | ^^^^^^^^^^^^^^ ambiguous link +help: to link to the module, prefix with the item type + | +LL | /// Ambiguous [module@type_and_value]. //~ERROR type_and_value + | ^^^^^^^^^^^^^^^^^^^^^ +help: to link to the constant, prefix with the item type + | +LL | /// Ambiguous [const@type_and_value]. //~ERROR type_and_value + | ^^^^^^^^^^^^^^^^^^^^ + +error: `foo::bar` is both an enum and a function + --> $DIR/intra-links-ambiguity.rs:35:42 + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` + | ^^^^^^^^^^ ambiguous link +help: to link to the enum, prefix with the item type + | +LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. //~ERROR `foo::bar` + | ^^^^^^^^^^^^^^^ +help: to link to the function, add parentheses + | +LL | /// Ambiguous non-implied shortcut link [`foo::bar()`]. //~ERROR `foo::bar` + | ^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-links.rs index 9139fc51b092e..c356ab3a8ac52 100644 --- a/src/test/rustdoc/intra-links.rs +++ b/src/test/rustdoc/intra-links.rs @@ -22,6 +22,7 @@ //! * [`ThisType::this_method`](ThisType::this_method) //! * [`ThisEnum`](ThisEnum) //! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant) +//! * [`ThisEnum::ThisVariantCtor`](ThisEnum::ThisVariantCtor) //! * [`ThisTrait`](ThisTrait) //! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method) //! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType) @@ -50,7 +51,7 @@ pub struct ThisType; impl ThisType { pub fn this_method() {} } -pub enum ThisEnum { ThisVariant, } +pub enum ThisEnum { ThisVariant, ThisVariantCtor(u32), } pub trait ThisTrait { type ThisAssociatedType; const THIS_ASSOCIATED_CONST: u8; From d70d79ffb4bc60fb98e45aaf9442ea8e6cb15d01 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 9 Mar 2019 16:25:12 -0500 Subject: [PATCH 17/37] replace ad-hoc namespace enums --- .../passes/collect_intra_doc_links.rs | 165 +++++++----------- .../rustdoc-ui/intra-links-ambiguity.stderr | 10 +- 2 files changed, 72 insertions(+), 103 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 36bfe2fb2c3da..b105e0a0b6fcc 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,5 +1,5 @@ use errors::Applicability; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, Namespace::{self, *}, PerNS}; use rustc::hir::def_id::DefId; use rustc::hir; use rustc::lint as lint; @@ -36,29 +36,9 @@ pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { } } -#[derive(Debug)] -enum PathKind { - /// Either a value or type, but not a macro - Unknown, - /// Macro - Macro, - /// Values, functions, consts, statics (everything in the value namespace) - Value, - /// Types, traits (everything in the type namespace) - Type, -} - struct LinkCollector<'a, 'tcx> { cx: &'a DocContext<'tcx>, mod_ids: Vec, - is_nightly_build: bool, -} - -#[derive(Debug, Copy, Clone)] -enum Namespace { - Type, - Value, - Macro, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -66,16 +46,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { LinkCollector { cx, mod_ids: Vec::new(), - is_nightly_build: UnstableFeatures::from_environment().is_nightly_build(), } } - /// Resolves a given string as a path, along with whether or not it is - /// in the value namespace. Also returns an optional URL fragment in the case - /// of variants and methods. + /// Resolves a string as a path within a particular namespace. Also returns an optional + /// URL fragment in the case of variants and methods. fn resolve(&self, path_str: &str, - is_val: bool, + ns: Namespace, current_item: &Option, parent_id: Option) -> Result<(Def, Option), ()> @@ -86,11 +64,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // path. if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) { // FIXME: `with_scope` requires the `NodeId` of a module. - let result = cx.enter_resolver(|resolver| resolver.with_scope(id, - |resolver| { - resolver.resolve_str_path_error(DUMMY_SP, - &path_str, is_val) - })); + let result = cx.enter_resolver(|resolver| { + resolver.with_scope(id, |resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS) + }) + }); if let Ok(result) = result { // In case this is a trait item, skip the @@ -103,16 +81,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => return Ok((result.def, None)) }; - if value != is_val { + if value != (ns == ValueNS) { return Err(()) } - } else if let Some(prim) = is_primitive(path_str, is_val) { + } else if let Some(prim) = is_primitive(path_str, ns) { return Ok((prim, Some(path_str.to_owned()))) } else { // If resolution failed, it may still be a method // because methods are not handled by the resolver // If so, bail when we're not looking for a value. - if !is_val { + if ns != ValueNS { return Err(()) } } @@ -136,7 +114,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { path = name.clone(); } } - if let Some(prim) = is_primitive(&path, false) { + if let Some(prim) = is_primitive(&path, TypeNS) { let did = primitive_impl(cx, &path).ok_or(())?; return cx.tcx.associated_items(did) .find(|item| item.ident.name == item_name) @@ -160,8 +138,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .find(|item| item.ident.name == item_name); if let Some(item) = item { let out = match item.kind { - ty::AssociatedKind::Method if is_val => "method", - ty::AssociatedKind::Const if is_val => "associatedconstant", + ty::AssociatedKind::Method if ns == ValueNS => "method", + ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant", _ => return Err(()) }; Ok((ty.def, Some(format!("{}.{}", out, item_name)))) @@ -198,9 +176,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .find(|item| item.ident.name == item_name); if let Some(item) = item { let kind = match item.kind { - ty::AssociatedKind::Const if is_val => "associatedconstant", - ty::AssociatedKind::Type if !is_val => "associatedtype", - ty::AssociatedKind::Method if is_val => { + ty::AssociatedKind::Const if ns == ValueNS => "associatedconstant", + ty::AssociatedKind::Type if ns == TypeNS => "associatedtype", + ty::AssociatedKind::Method if ns == ValueNS => { if item.defaultness.has_value() { "method" } else { @@ -287,10 +265,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { look_for_tests(&cx, &dox, &item, true); - if !self.is_nightly_build { - return None; - } - for (ori_link, link_range) in markdown_links(&dox) { // Bail early for real links. if ori_link.contains('/') { @@ -298,28 +272,28 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } let link = ori_link.replace("`", ""); let (def, fragment) = { - let mut kind = PathKind::Unknown; + let mut kind = None; let path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"].iter() .find(|p| link.starts_with(**p)) { - kind = PathKind::Type; + kind = Some(TypeNS); link.trim_start_matches(prefix) } else if let Some(prefix) = ["const@", "static@", "value@", "function@", "mod@", "fn@", "module@", "method@"] .iter().find(|p| link.starts_with(**p)) { - kind = PathKind::Value; + kind = Some(ValueNS); link.trim_start_matches(prefix) } else if link.ends_with("()") { - kind = PathKind::Value; + kind = Some(ValueNS); link.trim_end_matches("()") } else if link.starts_with("macro@") { - kind = PathKind::Macro; + kind = Some(MacroNS); link.trim_start_matches("macro@") } else if link.ends_with('!') { - kind = PathKind::Macro; + kind = Some(MacroNS); link.trim_end_matches('!') } else { &link[..] @@ -331,8 +305,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } match kind { - PathKind::Value => { - if let Ok(def) = self.resolve(path_str, true, ¤t_item, parent_node) { + Some(ns @ ValueNS) => { + if let Ok(def) = self.resolve(path_str, ns, ¤t_item, parent_node) { def } else { resolution_failure(cx, &item.attrs, path_str, &dox, link_range); @@ -342,8 +316,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } } - PathKind::Type => { - if let Ok(def) = self.resolve(path_str, false, ¤t_item, parent_node) { + Some(ns @ TypeNS) => { + if let Ok(def) = self.resolve(path_str, ns, ¤t_item, parent_node) { def } else { resolution_failure(cx, &item.attrs, path_str, &dox, link_range); @@ -351,57 +325,49 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { continue; } } - PathKind::Unknown => { + None => { // Try everything! - let mut candidates = vec![]; - - if let Some(macro_def) = macro_resolve(cx, path_str) { - candidates.push(((macro_def, None), Namespace::Macro)); - } - - if let Ok(type_def) = - self.resolve(path_str, false, ¤t_item, parent_node) - { - candidates.push((type_def, Namespace::Type)); - } - - if let Ok(value_def) = - self.resolve(path_str, true, ¤t_item, parent_node) - { - // Structs, variants, and mods exist in both namespaces, skip them. - match value_def.0 { - Def::StructCtor(..) - | Def::Mod(..) - | Def::Variant(..) - | Def::VariantCtor(..) - | Def::SelfCtor(..) => (), - _ => candidates.push((value_def, Namespace::Value)), - } - } + let candidates = PerNS { + macro_ns: macro_resolve(cx, path_str).map(|def| (def, None)), + type_ns: self + .resolve(path_str, TypeNS, ¤t_item, parent_node) + .ok(), + value_ns: self + .resolve(path_str, ValueNS, ¤t_item, parent_node) + .ok() + .and_then(|(def, fragment)| { + // Constructors are picked up in the type namespace. + match def { + Def::StructCtor(..) + | Def::VariantCtor(..) + | Def::SelfCtor(..) => None, + _ => Some((def, fragment)) + } + }), + }; - if candidates.len() == 1 { - candidates.remove(0).0 - } else if candidates.is_empty() { + if candidates.is_empty() { resolution_failure(cx, &item.attrs, path_str, &dox, link_range); // this could just be a normal link continue; - } else { - let candidates = candidates.into_iter().map(|((def, _), ns)| { - (def, ns) - }).collect::>(); + } + let is_unambiguous = candidates.clone().present_items().count() == 1; + if is_unambiguous { + candidates.present_items().next().unwrap() + } else { ambiguity_error( cx, &item.attrs, path_str, &dox, link_range, - &candidates, + candidates.map(|candidate| candidate.map(|(def, _)| def)), ); continue; } } - PathKind::Macro => { + Some(MacroNS) => { if let Some(def) = macro_resolve(cx, path_str) { (def, None) } else { @@ -514,13 +480,16 @@ fn ambiguity_error( path_str: &str, dox: &str, link_range: Option>, - candidates: &[(Def, Namespace)], + candidates: PerNS>, ) { let sp = span_of_attrs(attrs); let mut msg = format!("`{}` is ", path_str); - match candidates { + let candidates = [TypeNS, ValueNS, MacroNS].iter().filter_map(|&ns| { + candidates[ns].map(|def| (def, ns)) + }).collect::>(); + match candidates.as_slice() { [(first_def, _), (second_def, _)] => { msg += &format!( "both {} {} and {} {}", @@ -568,9 +537,9 @@ fn ambiguity_error( (Def::Union(..), _) => "union", (Def::Trait(..), _) => "trait", (Def::Mod(..), _) => "module", - (_, Namespace::Type) => "type", - (_, Namespace::Value) => "value", - (_, Namespace::Macro) => "macro", + (_, TypeNS) => "type", + (_, ValueNS) => "value", + (_, MacroNS) => "macro", }; // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` @@ -646,11 +615,11 @@ const PRIMITIVES: &[(&str, Def)] = &[ ("char", Def::PrimTy(hir::PrimTy::Char)), ]; -fn is_primitive(path_str: &str, is_val: bool) -> Option { - if is_val { - None - } else { +fn is_primitive(path_str: &str, ns: Namespace) -> Option { + if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) + } else { + None } } diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr index 5b8978e3053b6..b85161dc1469e 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -32,15 +32,11 @@ help: to link to the function, add parentheses LL | /// [ambiguous()] is ambiguous. //~ERROR ambiguous | ^^^^^^^^^^^ -error: `multi_conflict` is a macro, a struct, and a function +error: `multi_conflict` is a struct, a function, and a macro --> $DIR/intra-links-ambiguity.rs:31:6 | LL | /// [`multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` | ^^^^^^^^^^^^^^^^ ambiguous link -help: to link to the macro, prefix with the item type - | -LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` - | ^^^^^^^^^^^^^^^^^^^^^^ help: to link to the struct, prefix with the item type | LL | /// [`struct@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` @@ -49,6 +45,10 @@ help: to link to the function, add parentheses | LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict` | ^^^^^^^^^^^^^^^^^^ +help: to link to the macro, prefix with the item type + | +LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^^^^^^ error: `type_and_value` is both a module and a constant --> $DIR/intra-links-ambiguity.rs:33:16 From 3bb2275e164ff343c1c42998aaed65ed69723818 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 9 Mar 2019 16:32:07 -0500 Subject: [PATCH 18/37] use `!` in macro disambiguation suggestion --- src/librustdoc/passes/collect_intra_doc_links.rs | 3 +++ src/test/rustdoc-ui/intra-links-ambiguity.stderr | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index b105e0a0b6fcc..0fa6b6baec79d 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -528,6 +528,9 @@ fn ambiguity_error( Def::Method(..) | Def::Fn(..) => { ("add parentheses", format!("{}()", path_str)) } + Def::Macro(..) => { + ("add an exclamation mark", format!("{}!", path_str)) + } _ => { let type_ = match (def, ns) { (Def::Const(..), _) => "const", diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr index b85161dc1469e..ad63f13493ddb 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -45,10 +45,10 @@ help: to link to the function, add parentheses | LL | /// [`multi_conflict()`] is a three-way conflict. //~ERROR `multi_conflict` | ^^^^^^^^^^^^^^^^^^ -help: to link to the macro, prefix with the item type +help: to link to the macro, add an exclamation mark | -LL | /// [`macro@multi_conflict`] is a three-way conflict. //~ERROR `multi_conflict` - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | /// [`multi_conflict!`] is a three-way conflict. //~ERROR `multi_conflict` + | ^^^^^^^^^^^^^^^^^ error: `type_and_value` is both a module and a constant --> $DIR/intra-links-ambiguity.rs:33:16 From e25df326caf38c1a8559fc6fa633ad60ab401e12 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Mon, 11 Mar 2019 17:53:22 +0300 Subject: [PATCH 19/37] consistent naming for duration_float methods and additional f32 methods --- src/libcore/time.rs | 130 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 9 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 91161ca477e39..c8f23fd90bd7a 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -22,6 +22,7 @@ const NANOS_PER_MICRO: u32 = 1_000; const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64; +const MAX_NANOS_F32: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32; /// A `Duration` type to represent a span of time, typically used for system /// timeouts. @@ -510,15 +511,34 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); - /// assert_eq!(dur.as_float_secs(), 2.7); + /// assert_eq!(dur.as_secs_f64(), 2.7); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] - pub const fn as_float_secs(&self) -> f64 { + pub const fn as_secs_f64(&self) -> f64 { (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64) } - /// Creates a new `Duration` from the specified number of seconds. + /// Returns the number of seconds contained by this `Duration` as `f32`. + /// + /// The returned value does include the fractional (nanosecond) part of the duration. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 700_000_000); + /// assert_eq!(dur.as_secs_f32(), 2.7); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub const fn as_secs_f32(&self) -> f32 { + (self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32) + } + + /// Creates a new `Duration` from the specified number of seconds represented + /// as `f64`. /// /// # Panics /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`. @@ -528,12 +548,12 @@ impl Duration { /// #![feature(duration_float)] /// use std::time::Duration; /// - /// let dur = Duration::from_float_secs(2.7); + /// let dur = Duration::from_secs_f64(2.7); /// assert_eq!(dur, Duration::new(2, 700_000_000)); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] - pub fn from_float_secs(secs: f64) -> Duration { + pub fn from_secs_f64(secs: f64) -> Duration { let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { panic!("got non-finite value when converting float to duration"); @@ -551,6 +571,40 @@ impl Duration { } } + /// Creates a new `Duration` from the specified number of seconds represented + /// as `f32`. + /// + /// # Panics + /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::from_secs_f32(2.7); + /// assert_eq!(dur, Duration::new(2, 700_000_000)); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn from_secs_f32(secs: f32) -> Duration { + let nanos = secs * (NANOS_PER_SEC as f32); + if !nanos.is_finite() { + panic!("got non-finite value when converting float to duration"); + } + if nanos >= MAX_NANOS_F32 { + panic!("overflow when converting float to duration"); + } + if nanos < 0.0 { + panic!("underflow when converting float to duration"); + } + let nanos = nanos as u128; + Duration { + secs: (nanos / (NANOS_PER_SEC as u128)) as u64, + nanos: (nanos % (NANOS_PER_SEC as u128)) as u32, + } + } + /// Multiplies `Duration` by `f64`. /// /// # Panics @@ -568,7 +622,27 @@ impl Duration { #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn mul_f64(self, rhs: f64) -> Duration { - Duration::from_float_secs(rhs * self.as_float_secs()) + Duration::from_secs_f64(rhs * self.as_secs_f64()) + } + + /// Multiplies `Duration` by `f32`. + /// + /// # Panics + /// This method will panic if result is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 700_000_000); + /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_000)); + /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0)); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn mul_f32(self, rhs: f32) -> Duration { + Duration::from_secs_f32(rhs * self.as_secs_f32()) } /// Divide `Duration` by `f64`. @@ -589,7 +663,28 @@ impl Duration { #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn div_f64(self, rhs: f64) -> Duration { - Duration::from_float_secs(self.as_float_secs() / rhs) + Duration::from_secs_f64(self.as_secs_f64() / rhs) + } + + /// Divide `Duration` by `f32`. + /// + /// # Panics + /// This method will panic if result is not finite, negative or overflows `Duration`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur = Duration::new(2, 700_000_000); + /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_611)); + /// // note that truncation is used, not rounding + /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598)); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn div_f32(self, rhs: f32) -> Duration { + Duration::from_secs_f32(self.as_secs_f32() / rhs) } /// Divide `Duration` by `Duration` and return `f64`. @@ -605,8 +700,25 @@ impl Duration { /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] - pub fn div_duration(self, rhs: Duration) -> f64 { - self.as_float_secs() / rhs.as_float_secs() + pub fn div_duration_f64(self, rhs: Duration) -> f64 { + self.as_secs_f64() / rhs.as_secs_f64() + } + + /// Divide `Duration` by `Duration` and return `f32`. + /// + /// # Examples + /// ``` + /// #![feature(duration_float)] + /// use std::time::Duration; + /// + /// let dur1 = Duration::new(2, 700_000_000); + /// let dur2 = Duration::new(5, 400_000_000); + /// assert_eq!(dur1.div_duration(dur2), 0.5); + /// ``` + #[unstable(feature = "duration_float", issue = "54361")] + #[inline] + pub fn div_duration_f32(self, rhs: Duration) -> f32 { + self.as_secs_f32() / rhs.as_secs_f32() } } From 35c19c5b3d1fe8675132ea96e014e37455653ce8 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Mon, 11 Mar 2019 18:06:13 +0300 Subject: [PATCH 20/37] move MAX_NANOS_F64/32 to methods --- src/libcore/time.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index c8f23fd90bd7a..d3f80835c0175 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -21,8 +21,6 @@ const NANOS_PER_MILLI: u32 = 1_000_000; const NANOS_PER_MICRO: u32 = 1_000; const MILLIS_PER_SEC: u64 = 1_000; const MICROS_PER_SEC: u64 = 1_000_000; -const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64; -const MAX_NANOS_F32: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32; /// A `Duration` type to represent a span of time, typically used for system /// timeouts. @@ -554,6 +552,8 @@ impl Duration { #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn from_secs_f64(secs: f64) -> Duration { + const MAX_NANOS_F64: f64 = + ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64; let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { panic!("got non-finite value when converting float to duration"); @@ -588,6 +588,8 @@ impl Duration { #[unstable(feature = "duration_float", issue = "54361")] #[inline] pub fn from_secs_f32(secs: f32) -> Duration { + const MAX_NANOS_F32: f32 = + ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f32; let nanos = secs * (NANOS_PER_SEC as f32); if !nanos.is_finite() { panic!("got non-finite value when converting float to duration"); From 980871af270314d1e4dd42828d9a7c76d6e0c89a Mon Sep 17 00:00:00 2001 From: newpavlov Date: Mon, 11 Mar 2019 19:57:53 +0300 Subject: [PATCH 21/37] fix tests --- src/libcore/time.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index d3f80835c0175..c4d4c4622f3a4 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -638,8 +638,10 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); - /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_000)); - /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0)); + /// // note that due to rounding errors result is slightly different + /// // from 8.478 + /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640)); + /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 64_000_000)); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] @@ -679,7 +681,9 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); - /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_611)); + /// // note that due to rounding errors result is slightly + /// // different from 0.859_872_611 + /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576)); /// // note that truncation is used, not rounding /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598)); /// ``` @@ -698,7 +702,7 @@ impl Duration { /// /// let dur1 = Duration::new(2, 700_000_000); /// let dur2 = Duration::new(5, 400_000_000); - /// assert_eq!(dur1.div_duration(dur2), 0.5); + /// assert_eq!(dur1.div_duration_f64(dur2), 0.5); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] @@ -715,7 +719,7 @@ impl Duration { /// /// let dur1 = Duration::new(2, 700_000_000); /// let dur2 = Duration::new(5, 400_000_000); - /// assert_eq!(dur1.div_duration(dur2), 0.5); + /// assert_eq!(dur1.div_duration_f32(dur2), 0.5); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] From 197efb05243976a631107f1d6ad88bff65fd43e9 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 11 Mar 2019 18:59:41 +0000 Subject: [PATCH 22/37] fix test --- src/libcore/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index c4d4c4622f3a4..f106d06d2ffc1 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -639,9 +639,9 @@ impl Duration { /// /// let dur = Duration::new(2, 700_000_000); /// // note that due to rounding errors result is slightly different - /// // from 8.478 + /// // from 8.478 anf 847800.0 /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640)); - /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 64_000_000)); + /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256)); /// ``` #[unstable(feature = "duration_float", issue = "54361")] #[inline] From b9d12edd6ce7b364fb1a4de53f7541d536df0940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 11 Mar 2019 15:07:07 -0700 Subject: [PATCH 23/37] Be more discerning on when to attempt suggesting a comma in a macro invocation --- src/libsyntax/tokenstream.rs | 8 +++++--- src/test/ui/macros/missing-comma.rs | 7 +++++++ src/test/ui/macros/missing-comma.stderr | 21 +++++++++++++++------ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 4ce308d015c00..5caa59a53f92b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -178,9 +178,11 @@ impl TokenStream { while let Some((pos, ts)) = iter.next() { if let Some((_, next)) = iter.peek() { let sp = match (&ts, &next) { - ((TokenTree::Token(_, token::Token::Comma), NonJoint), _) | - (_, (TokenTree::Token(_, token::Token::Comma), NonJoint)) => continue, - ((TokenTree::Token(sp, _), NonJoint), _) => *sp, + (_, (TokenTree::Token(_, token::Token::Comma), _)) => continue, + ((TokenTree::Token(sp, token_left), NonJoint), + (TokenTree::Token(_, token_right), _)) + if token_left.is_ident() || token_left.is_lit() && + token_right.is_ident() || token_right.is_lit() => *sp, ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), _ => continue, }; diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs index 1e146875bcc76..2b411aba8a2ee 100644 --- a/src/test/ui/macros/missing-comma.rs +++ b/src/test/ui/macros/missing-comma.rs @@ -6,6 +6,11 @@ macro_rules! foo { ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => (); } +macro_rules! bar { + ($lvl:expr, $($arg:tt)+) => {} +} + + fn main() { println!("{}" a); //~^ ERROR expected token: `,` @@ -17,4 +22,6 @@ fn main() { //~^ ERROR no rules expected the token `d` foo!(a, b, c d e); //~^ ERROR no rules expected the token `d` + bar!(Level::Error, ); + //~^ ERROR unexpected end of macro invocation } diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr index 5881e0b7b68c6..424fefd00f873 100644 --- a/src/test/ui/macros/missing-comma.stderr +++ b/src/test/ui/macros/missing-comma.stderr @@ -1,11 +1,11 @@ error: expected token: `,` - --> $DIR/missing-comma.rs:10:19 + --> $DIR/missing-comma.rs:15:19 | LL | println!("{}" a); | ^ error: no rules expected the token `b` - --> $DIR/missing-comma.rs:12:12 + --> $DIR/missing-comma.rs:17:12 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -16,7 +16,7 @@ LL | foo!(a b); | help: missing comma here error: no rules expected the token `e` - --> $DIR/missing-comma.rs:14:21 + --> $DIR/missing-comma.rs:19:21 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -27,7 +27,7 @@ LL | foo!(a, b, c, d e); | help: missing comma here error: no rules expected the token `d` - --> $DIR/missing-comma.rs:16:18 + --> $DIR/missing-comma.rs:21:18 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -38,7 +38,7 @@ LL | foo!(a, b, c d, e); | help: missing comma here error: no rules expected the token `d` - --> $DIR/missing-comma.rs:18:18 + --> $DIR/missing-comma.rs:23:18 | LL | macro_rules! foo { | ---------------- when calling this macro @@ -46,5 +46,14 @@ LL | macro_rules! foo { LL | foo!(a, b, c d e); | ^ no rules expected this token in macro call -error: aborting due to 5 previous errors +error: unexpected end of macro invocation + --> $DIR/missing-comma.rs:25:23 + | +LL | macro_rules! bar { + | ---------------- when calling this macro +... +LL | bar!(Level::Error, ); + | ^ missing tokens in macro arguments + +error: aborting due to 6 previous errors From 78b248dc4c17581211aaed5c3a449e5b07ebdb52 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Tue, 12 Mar 2019 16:42:18 +0300 Subject: [PATCH 24/37] fix typo --- src/libcore/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index f106d06d2ffc1..ae6d8078fd236 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -639,7 +639,7 @@ impl Duration { /// /// let dur = Duration::new(2, 700_000_000); /// // note that due to rounding errors result is slightly different - /// // from 8.478 anf 847800.0 + /// // from 8.478 and 847800.0 /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640)); /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256)); /// ``` From 1ae131211be24a337877e6dbcd9b6c52a86b9511 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 12 Mar 2019 14:43:49 +0100 Subject: [PATCH 25/37] Explain the bits of `UndefMask` --- src/librustc/mir/interpret/allocation.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 004804f7c211e..2ce9a4a0f204d 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -613,6 +613,8 @@ impl DerefMut for Relocations { type Block = u64; +/// A bitmask where each bit refers to the byte with the same index. If the bit is `true`, the byte +/// is defined. If it is `false` the byte is undefined. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct UndefMask { blocks: Vec, From 2a1eb1cef1a36c6f0a9d2e347529561c1293044e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 12 Mar 2019 15:00:12 +0100 Subject: [PATCH 26/37] Document the precomputation algorithm's purpose --- src/librustc_mir/interpret/memory.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index fba0a9af21392..6ea200d4e4fad 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -791,6 +791,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { let undef_mask = &self.get(src.alloc_id)?.undef_mask; + // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), + // a naive undef mask copying algorithm would repeatedly have to read the undef mask from + // the source and write it to the destination. Even if we optimized the memory accesses, + // we'd be doing all of this `repeat` times. + // Therefor we precompute a compressed version of the undef mask of the source value and + // then write it back `repeat` times without computing any more information from the source. + // a precomputed cache for ranges of defined/undefined bits // 0000010010001110 will become // [5, 1, 2, 1, 3, 3, 1] From 795d307f10ec0fd3851b18a3365755d76b7403e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 Mar 2019 14:57:13 -0700 Subject: [PATCH 27/37] Suggest return lifetime when there's only one named lifetime --- src/librustc/middle/resolve_lifetime.rs | 37 +++++++++++++++++-- .../ui/suggestions/return-without-lifetime.rs | 8 ++++ .../return-without-lifetime.stderr | 19 ++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/suggestions/return-without-lifetime.rs create mode 100644 src/test/ui/suggestions/return-without-lifetime.stderr diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index f862b690f8806..35bca04d1e623 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2298,6 +2298,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let span = lifetime_refs[0].span; let mut late_depth = 0; let mut scope = self.scope; + let mut lifetime_names = FxHashSet::default(); let error = loop { match *scope { // Do not assign any resolution, it will be inferred. @@ -2310,7 +2311,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope = s; } - Scope::Elision { ref elide, .. } => { + Scope::Elision { ref elide, ref s, .. } => { let lifetime = match *elide { Elide::FreshLateAnon(ref counter) => { for lifetime_ref in lifetime_refs { @@ -2320,7 +2321,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } Elide::Exact(l) => l.shifted(late_depth), - Elide::Error(ref e) => break Some(e), + Elide::Error(ref e) => { + if let Scope::Binder { ref lifetimes, .. } = s { + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(*name); + } + } + } + break Some(e); + } }; for lifetime_ref in lifetime_refs { self.insert_lifetime(lifetime_ref, lifetime); @@ -2343,7 +2353,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } if add_label { - add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len()); + add_missing_lifetime_specifiers_label( + &mut err, + span, + lifetime_refs.len(), + &lifetime_names, + self.tcx.sess.source_map().span_to_snippet(span).ok().as_ref().map(|s| s.as_str()), + ); } err.emit(); @@ -2884,10 +2900,23 @@ fn add_missing_lifetime_specifiers_label( err: &mut DiagnosticBuilder<'_>, span: Span, count: usize, + lifetime_names: &FxHashSet, + snippet: Option<&str>, ) { if count > 1 { err.span_label(span, format!("expected {} lifetime parameters", count)); + } else if let (1, Some(name), Some("&")) = ( + lifetime_names.len(), + lifetime_names.iter().next(), + snippet, + ) { + err.span_suggestion( + span, + &format!("consider using the named lifetime `{}`", name), + format!("&{} ", name), + Applicability::MaybeIncorrect, + ); } else { err.span_label(span, "expected lifetime parameter"); - }; + } } diff --git a/src/test/ui/suggestions/return-without-lifetime.rs b/src/test/ui/suggestions/return-without-lifetime.rs new file mode 100644 index 0000000000000..5f19e93013acf --- /dev/null +++ b/src/test/ui/suggestions/return-without-lifetime.rs @@ -0,0 +1,8 @@ +struct Thing<'a>(&'a ()); + +fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } +//~^ ERROR missing lifetime specifier +fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } +//~^ ERROR missing lifetime specifier + +fn main() {} diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr new file mode 100644 index 0000000000000..72f1c142d028f --- /dev/null +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -0,0 +1,19 @@ +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:3:34 + | +LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } + | ^ help: consider using the named lifetime `'a`: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:5:35 + | +LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } + | ^ help: consider using the named lifetime `'a`: `&'a` + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. From f9234767e4ff9b682437464efc9a6ff59db4cff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 Mar 2019 15:34:16 -0700 Subject: [PATCH 28/37] review comments --- src/librustc/middle/resolve_lifetime.rs | 2 +- src/test/ui/suggestions/return-without-lifetime.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 35bca04d1e623..d03268df5e148 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2912,7 +2912,7 @@ fn add_missing_lifetime_specifiers_label( ) { err.span_suggestion( span, - &format!("consider using the named lifetime `{}`", name), + "consider using the named lifetime", format!("&{} ", name), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 72f1c142d028f..1ffe91bce05a5 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -2,7 +2,7 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:3:34 | LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime `'a`: `&'a` + | ^ help: consider using the named lifetime: `&'a` | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from @@ -10,7 +10,7 @@ error[E0106]: missing lifetime specifier --> $DIR/return-without-lifetime.rs:5:35 | LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } - | ^ help: consider using the named lifetime `'a`: `&'a` + | ^ help: consider using the named lifetime: `&'a` | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from From adbd0a66457159ffcdd02ee0b553581298968847 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 12 Mar 2019 16:09:20 -0700 Subject: [PATCH 29/37] Make std time tests more robust for platform differences --- src/libstd/time.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 6d7093ac33ea7..4c86f70ad871d 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -712,13 +712,6 @@ mod tests { assert_almost_eq!(a - second + second, a); assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); - // A difference of 80 and 800 years cannot fit inside a 32-bit time_t - if !(cfg!(unix) && crate::mem::size_of::() <= 4) { - let eighty_years = second * 60 * 60 * 24 * 365 * 80; - assert_almost_eq!(a - eighty_years + eighty_years, a); - assert_almost_eq!(a - (eighty_years * 10) + (eighty_years * 10), a); - } - let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); @@ -747,8 +740,8 @@ mod tests { #[test] fn since_epoch() { let ts = SystemTime::now(); - let a = ts.duration_since(UNIX_EPOCH).unwrap(); - let b = ts.duration_since(UNIX_EPOCH - Duration::new(1, 0)).unwrap(); + let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap(); + let b = ts.duration_since(UNIX_EPOCH).unwrap(); assert!(b > a); assert_eq!(b - a, Duration::new(1, 0)); From 0ea9b58029bc7c3da3f213eb9e39acdefcf12647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 Mar 2019 18:18:24 -0700 Subject: [PATCH 30/37] Suggest adding lifetime to struct field --- src/librustc/middle/resolve_lifetime.rs | 9 ++++++++- src/test/ui/suggestions/return-without-lifetime.rs | 2 ++ .../ui/suggestions/return-without-lifetime.stderr | 12 +++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index d03268df5e148..c9ff84ab2f08a 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2306,7 +2306,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Root => break None, - Scope::Binder { s, .. } => { + Scope::Binder { s, ref lifetimes, .. } => { + // collect named lifetimes for suggestions + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(*name); + } + } late_depth += 1; scope = s; } @@ -2323,6 +2329,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Elide::Exact(l) => l.shifted(late_depth), Elide::Error(ref e) => { if let Scope::Binder { ref lifetimes, .. } = s { + // collect named lifetimes for suggestions for name in lifetimes.keys() { if let hir::ParamName::Plain(name) = name { lifetime_names.insert(*name); diff --git a/src/test/ui/suggestions/return-without-lifetime.rs b/src/test/ui/suggestions/return-without-lifetime.rs index 5f19e93013acf..9bfce11be9ea3 100644 --- a/src/test/ui/suggestions/return-without-lifetime.rs +++ b/src/test/ui/suggestions/return-without-lifetime.rs @@ -1,4 +1,6 @@ struct Thing<'a>(&'a ()); +struct Foo<'a>(&usize); +//~^ ERROR missing lifetime specifier fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } //~^ ERROR missing lifetime specifier diff --git a/src/test/ui/suggestions/return-without-lifetime.stderr b/src/test/ui/suggestions/return-without-lifetime.stderr index 1ffe91bce05a5..7f5ff95938e30 100644 --- a/src/test/ui/suggestions/return-without-lifetime.stderr +++ b/src/test/ui/suggestions/return-without-lifetime.stderr @@ -1,5 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/return-without-lifetime.rs:3:34 + --> $DIR/return-without-lifetime.rs:2:16 + | +LL | struct Foo<'a>(&usize); + | ^ help: consider using the named lifetime: `&'a` + +error[E0106]: missing lifetime specifier + --> $DIR/return-without-lifetime.rs:5:34 | LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } | ^ help: consider using the named lifetime: `&'a` @@ -7,13 +13,13 @@ LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() } = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from error[E0106]: missing lifetime specifier - --> $DIR/return-without-lifetime.rs:5:35 + --> $DIR/return-without-lifetime.rs:7:35 | LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() } | ^ help: consider using the named lifetime: `&'a` | = help: this function's return type contains a borrowed value, but the signature does not say which one of `_arg`'s 2 lifetimes it is borrowed from -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0106`. From 266ca31f74ae343fc773b88f3bb77b601034babf Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Tue, 12 Mar 2019 21:00:37 -0700 Subject: [PATCH 31/37] Stabilize Range*::contains. --- src/libcore/ops/range.rs | 49 +++++++++++++------------------- src/librustc_codegen_llvm/lib.rs | 1 - src/librustc_errors/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/libstd/lib.rs | 2 +- 5 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 998b597d5e113..cb82ad38eb87d 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -67,7 +67,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` #[doc(alias = "..")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct Range { /// The lower bound of the range (inclusive). @@ -91,8 +91,6 @@ impl> Range { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..5).contains(&2)); @@ -108,7 +106,7 @@ impl> Range { /// assert!(!(0.0..f32::NAN).contains(&0.5)); /// assert!(!(f32::NAN..1.0).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -169,7 +167,7 @@ impl> Range { /// /// [`Iterator`]: ../iter/trait.IntoIterator.html #[doc(alias = "..")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom { /// The lower bound of the range (inclusive). @@ -190,8 +188,6 @@ impl> RangeFrom { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..).contains(&2)); @@ -202,7 +198,7 @@ impl> RangeFrom { /// assert!(!(0.0..).contains(&f32::NAN)); /// assert!(!(f32::NAN..).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -272,8 +268,6 @@ impl> RangeTo { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!( (..5).contains(&-1_000_000_000)); @@ -284,7 +278,7 @@ impl> RangeTo { /// assert!(!(..1.0).contains(&f32::NAN)); /// assert!(!(..f32::NAN).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -317,7 +311,7 @@ impl> RangeTo { /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` #[doc(alias = "..=")] -#[derive(Clone)] // not Copy -- see #27186 +#[derive(Clone)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { pub(crate) start: Idx, @@ -353,7 +347,8 @@ impl RangeInclusiveEquality for T { impl PartialEq for RangeInclusive { #[inline] fn eq(&self, other: &Self) -> bool { - self.start == other.start && self.end == other.end + self.start == other.start + && self.end == other.end && RangeInclusiveEquality::canonicalized_is_empty(self) == RangeInclusiveEquality::canonicalized_is_empty(other) } @@ -385,7 +380,11 @@ impl RangeInclusive { #[inline] #[rustc_promotable] pub const fn new(start: Idx, end: Idx) -> Self { - Self { start, end, is_empty: None } + Self { + start, + end, + is_empty: None, + } } /// Returns the lower bound of the range (inclusive). @@ -466,8 +465,6 @@ impl> RangeInclusive { /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!(!(3..=5).contains(&2)); @@ -484,7 +481,7 @@ impl> RangeInclusive { /// assert!(!(0.0..=f32::NAN).contains(&0.0)); /// assert!(!(f32::NAN..=1.0).contains(&1.0)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -593,15 +590,12 @@ impl fmt::Debug for RangeToInclusive { } } -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] impl> RangeToInclusive { /// Returns `true` if `item` is contained in the range. /// /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!( (..=5).contains(&-1_000_000_000)); @@ -612,7 +606,7 @@ impl> RangeToInclusive { /// assert!(!(..=1.0).contains(&f32::NAN)); /// assert!(!(..=f32::NAN).contains(&0.5)); /// ``` - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] pub fn contains(&self, item: &U) -> bool where Idx: PartialOrd, @@ -714,14 +708,11 @@ pub trait RangeBounds { #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; - /// Returns `true` if `item` is contained in the range. /// /// # Examples /// /// ``` - /// #![feature(range_contains)] - /// /// use std::f32; /// /// assert!( (3..5).contains(&4)); @@ -731,7 +722,7 @@ pub trait RangeBounds { /// assert!(!(0.0..1.0).contains(&f32::NAN)); /// assert!(!(0.0..f32::NAN).contains(&0.5)); /// assert!(!(f32::NAN..1.0).contains(&0.5)); - #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] + #[stable(feature = "range_contains", since = "1.35.0")] fn contains(&self, item: &U) -> bool where T: PartialOrd, @@ -741,9 +732,7 @@ pub trait RangeBounds { Included(ref start) => *start <= item, Excluded(ref start) => *start < item, Unbounded => true, - }) - && - (match self.end_bound() { + }) && (match self.end_bound() { Included(ref end) => item <= *end, Excluded(ref end) => item < *end, Unbounded => true, @@ -819,7 +808,7 @@ impl RangeBounds for (Bound, Bound) { match *self { (Included(ref start), _) => Included(start), (Excluded(ref start), _) => Excluded(start), - (Unbounded, _) => Unbounded, + (Unbounded, _) => Unbounded, } } @@ -827,7 +816,7 @@ impl RangeBounds for (Bound, Bound) { match *self { (_, Included(ref end)) => Included(end), (_, Excluded(ref end)) => Excluded(end), - (_, Unbounded) => Unbounded, + (_, Unbounded) => Unbounded, } } } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 7b2b9ec24ea0f..b396c6b54db3f 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -15,7 +15,6 @@ #![allow(unused_attributes)] #![feature(libc)] #![feature(nll)] -#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(optin_builtin_traits)] #![feature(concat_idents)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 7c7698ddd3d73..6b4b437930d26 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -2,7 +2,6 @@ #![feature(custom_attribute)] #![allow(unused_attributes)] -#![feature(range_contains)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 0b735b4b39cf5..c45e694ebf832 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,7 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(decl_macro)] #![feature(exhaustive_patterns)] -#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_attrs)] #![feature(never_type)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index e31680f23f1da..307e0c63f3415 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -221,7 +221,7 @@ #![cfg_attr(test, feature(print_internals, set_stdio, test, update_panic_count))] #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), - feature(global_asm, range_contains, slice_index_methods, + feature(global_asm, slice_index_methods, decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] // std is implemented with unstable features, many of which are internal From 27abd52170b2d2769f5fbed665795bdb9a3facef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Mar 2019 00:10:16 -0700 Subject: [PATCH 32/37] Fix operator precedence --- src/libsyntax/tokenstream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 5caa59a53f92b..80a7bde606afa 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -181,8 +181,8 @@ impl TokenStream { (_, (TokenTree::Token(_, token::Token::Comma), _)) => continue, ((TokenTree::Token(sp, token_left), NonJoint), (TokenTree::Token(_, token_right), _)) - if token_left.is_ident() || token_left.is_lit() && - token_right.is_ident() || token_right.is_lit() => *sp, + if (token_left.is_ident() || token_left.is_lit()) && + (token_right.is_ident() || token_right.is_lit()) => *sp, ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), _ => continue, }; From 9d938f69362e9568c14955d7df801c21a2266e66 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 13 Mar 2019 12:38:10 +0100 Subject: [PATCH 33/37] Add test for #55809. This commit adds a regression test for #55809 which checks that a overflow does not occur when evaluating a requirement for async functions and `&mut` arguments in some specific circumstances. --- src/test/run-pass/issue-55809.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/run-pass/issue-55809.rs diff --git a/src/test/run-pass/issue-55809.rs b/src/test/run-pass/issue-55809.rs new file mode 100644 index 0000000000000..86b0977bebe1d --- /dev/null +++ b/src/test/run-pass/issue-55809.rs @@ -0,0 +1,30 @@ +// edition:2018 +// run-pass + +#![feature(async_await, await_macro, futures_api)] + +trait Foo { } + +impl Foo for () { } + +impl<'a, T> Foo for &'a mut T where T: Foo { } + +async fn foo_async(_v: T) -> u8 where T: Foo { + 0 +} + +async fn bad(v: T) -> u8 where T: Foo { + await!(foo_async(v)) +} + +async fn async_main() { + let mut v = (); + + let _ = await!(bad(&mut v)); + let _ = await!(foo_async(&mut v)); + let _ = await!(bad(v)); +} + +fn main() { + let _ = async_main(); +} From 311025e6a5aad80d028f0771970c43cb4ed025a8 Mon Sep 17 00:00:00 2001 From: Angelos Oikonomopoulos Date: Thu, 7 Mar 2019 18:30:26 +0100 Subject: [PATCH 34/37] Fix generic argument lookup for Self Rewrite the SelfCtor early and use the replacement Def when calculating the path_segs. Note that this also changes which def is seen by the code that computes user_self_ty and is_alias_variant_ctor; I don't see a immediate issue with that, but I'm not 100% clear on the implications. Fixes #57924 --- src/librustc_typeck/check/mod.rs | 119 ++++++++++++------------ src/test/run-pass/issues/issue-57924.rs | 9 ++ 2 files changed, 69 insertions(+), 59 deletions(-) create mode 100644 src/test/run-pass/issues/issue-57924.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 301d7d3ac5623..7dfe9f40d318f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5302,6 +5302,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(original_span.with_lo(original_span.hi() - BytePos(1))) } + // Rewrite `SelfCtor` to `StructCtor` + pub fn rewrite_self_ctor(&self, def: Def, span: Span) -> (Def, DefId, Ty<'tcx>) { + let tcx = self.tcx; + if let Def::SelfCtor(impl_def_id) = def { + let ty = self.impl_self_ty(span, impl_def_id).ty; + let adt_def = ty.ty_adt_def(); + + match adt_def { + Some(adt_def) if adt_def.has_ctor() => { + let variant = adt_def.non_enum_variant(); + let def = Def::StructCtor(variant.did, variant.ctor_kind); + (def, variant.did, tcx.type_of(variant.did)) + } + _ => { + let mut err = tcx.sess.struct_span_err(span, + "the `Self` constructor can only be used with tuple or unit structs"); + if let Some(adt_def) = adt_def { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.help("did you mean to use one of the enum's variants?"); + }, + AdtKind::Struct | + AdtKind::Union => { + err.span_suggestion( + span, + "use curly brackets", + String::from("Self { /* fields */ }"), + Applicability::HasPlaceholders, + ); + } + } + } + err.emit(); + + (def, impl_def_id, tcx.types.err) + } + } + } else { + let def_id = def.def_id(); + + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = tcx.type_of(def_id); + (def, def_id, ty) + } + } + // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. pub fn instantiate_value_path(&self, @@ -5321,6 +5368,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; + match def { + Def::Local(nid) | Def::Upvar(nid, ..) => { + let hid = self.tcx.hir().node_to_hir_id(nid); + let ty = self.local_ty(span, hid).decl_ty; + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(hir_id, ty); + return (ty, def); + } + _ => {} + } + + let (def, def_id, ty) = self.rewrite_self_ctor(def, span); let path_segs = AstConv::def_ids_for_path_segments(self, segments, self_ty, def); let mut user_self_ty = None; @@ -5382,17 +5441,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { user_self_ty = None; } - match def { - Def::Local(nid) | Def::Upvar(nid, ..) => { - let hid = self.tcx.hir().node_to_hir_id(nid); - let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(hir_id, ty); - return (ty, def); - } - _ => {} - } - // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user // did not provide any types, then we want to substitute inference @@ -5425,53 +5473,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.generics_of(*def_id).has_self }).unwrap_or(false); - let mut new_def = def; - let (def_id, ty) = match def { - Def::SelfCtor(impl_def_id) => { - let ty = self.impl_self_ty(span, impl_def_id).ty; - let adt_def = ty.ty_adt_def(); - - match adt_def { - Some(adt_def) if adt_def.has_ctor() => { - let variant = adt_def.non_enum_variant(); - new_def = Def::StructCtor(variant.did, variant.ctor_kind); - (variant.did, tcx.type_of(variant.did)) - } - _ => { - let mut err = tcx.sess.struct_span_err(span, - "the `Self` constructor can only be used with tuple or unit structs"); - if let Some(adt_def) = adt_def { - match adt_def.adt_kind() { - AdtKind::Enum => { - err.help("did you mean to use one of the enum's variants?"); - }, - AdtKind::Struct | - AdtKind::Union => { - err.span_suggestion( - span, - "use curly brackets", - String::from("Self { /* fields */ }"), - Applicability::HasPlaceholders, - ); - } - } - } - err.emit(); - - (impl_def_id, tcx.types.err) - } - } - } - _ => { - let def_id = def.def_id(); - - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = tcx.type_of(def_id); - (def_id, ty) - } - }; - let substs = AstConv::create_substs_for_generic_args( tcx, def_id, @@ -5587,7 +5588,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty_substituted); self.write_substs(hir_id, substs); - (ty_substituted, new_def) + (ty_substituted, def) } fn check_rustc_args_require_const(&self, diff --git a/src/test/run-pass/issues/issue-57924.rs b/src/test/run-pass/issues/issue-57924.rs new file mode 100644 index 0000000000000..232596334b0ed --- /dev/null +++ b/src/test/run-pass/issues/issue-57924.rs @@ -0,0 +1,9 @@ +pub struct Gcm(E); + +impl Gcm { + pub fn crash(e: E) -> Self { + Self::(e) + } +} + +fn main() {} From 4e5692d9858d298f27757579688c71ba494cb5c3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 18 Jan 2019 12:18:57 +0100 Subject: [PATCH 35/37] test that wildcard type `_` is not duplicated by `type Foo = (X, X);` and potentially instantiated at different types. (Updated to reflect changes in diagnostic output and compiletest infrastructure.) --- ...ssue-55748-pat-types-constrain-bindings.rs | 70 +++++++++++++++++++ ...-55748-pat-types-constrain-bindings.stderr | 29 ++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs create mode 100644 src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs new file mode 100644 index 0000000000000..3d042d442d531 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs @@ -0,0 +1,70 @@ +// This test is ensuring that type ascriptions on let bindings +// constrain both: +// +// 1. the input expression on the right-hand side (after any potential +// coercion, and allowing for covariance), *and* +// +// 2. the bindings (if any) nested within the pattern on the left-hand +// side (and here, the type-constraint is *invariant*). + +#![feature(nll)] + +#![allow(dead_code, unused_mut)] +type PairUncoupled<'a, 'b, T> = (&'a T, &'b T); +type PairCoupledRegions<'a, T> = (&'a T, &'a T); +type PairCoupledTypes = (T, T); + +fn uncoupled_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((mut y, mut _z),): (PairUncoupled,) = ((s, &_x),); // ok + // Above compiling does *not* imply below would compile. + // ::std::mem::swap(&mut y, &mut _z); + y +} + +fn swap_regions((mut y, mut _z): PairCoupledRegions) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledRegions,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_regions((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn swap_types((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<&u32>,) = ((s, &_x),); + // If above line compiled, so should line below ... + + // swap_types((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn swap_wilds((mut y, mut _z): PairCoupledTypes<&u32>) { + ::std::mem::swap(&mut y, &mut _z); +} + +fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + let ((y, _z),): (PairCoupledTypes<_>,) = ((s, &_x),); + // If above line compiled, so should line below + // swap_wilds((y, _z)); + + // ... but the ascribed type also invalidates this use of `y` + y //~ ERROR lifetime may not live long enough +} + +fn main() { + uncoupled_lhs(&3, &4); + coupled_regions_lhs(&3, &4); + coupled_types_lhs(&3, &4); + coupled_wilds_lhs(&3, &4); +} diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr new file mode 100644 index 0000000000000..5929707e41e10 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr @@ -0,0 +1,29 @@ +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:35:5 + | +LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5 + | +LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: lifetime may not live long enough + --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5 + | +LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { + | -- lifetime `'a` defined here +... +LL | y + | ^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 3 previous errors + From 88d43a052a9230230bb263ff0b7b072134203510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 14 Mar 2019 05:53:44 +0100 Subject: [PATCH 36/37] Don't run test launching `echo` since that doesn't exist on Windows --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 568400093440c..ad86acbb47de4 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -8,7 +8,7 @@ //! //! The [`Command`] struct is used to configure and spawn processes: //! -//! ``` +//! ```no_run //! use std::process::Command; //! //! let output = Command::new("echo") From 41cdf07483ed39ccd85ce1c9ae7512ceb3bbb657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 14 Mar 2019 06:35:48 +0100 Subject: [PATCH 37/37] Run RustdocUi earlier --- src/bootstrap/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ffd23e72e80a6..daa6749f87f3e 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -408,11 +408,11 @@ impl<'a> Builder<'a> { test::RustdocJSStd, test::RustdocJSNotStd, test::RustdocTheme, + test::RustdocUi, // Run bootstrap close to the end as it's unlikely to fail test::Bootstrap, // Run run-make last, since these won't pass without make on Windows test::RunMake, - test::RustdocUi ), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!(