From a2cdeb58f680b87b5bdb6a17cba857ac51307c8f Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Thu, 21 Dec 2017 20:23:47 -0500 Subject: Expose float from_bits and to_bits in libcore. --- src/libstd/f32.rs | 5 ++--- src/libstd/f64.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index e5b1394f070..18eb2a27b91 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1016,7 +1016,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u32 { - unsafe { ::mem::transmute(self) } + num::Float::to_bits(self) } /// Raw transmutation from `u32`. @@ -1060,8 +1060,7 @@ impl f32 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u32) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } + num::Float::from_bits(v) } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f4d804fd508..cabb2c48054 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -971,7 +971,7 @@ impl f64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u64 { - unsafe { ::mem::transmute(self) } + num::Float::to_bits(self) } /// Raw transmutation from `u64`. @@ -1015,8 +1015,7 @@ impl f64 { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u64) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { ::mem::transmute(v) } + num::Float::from_bits(v) } } -- cgit 1.4.1-3-g733a5 From 25574e58b68dae94f7d9931b5e648a327a94ecd1 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 9 Jan 2018 11:39:23 -0800 Subject: Make core::ops::Place an unsafe trait --- src/liballoc/binary_heap.rs | 2 +- src/liballoc/boxed.rs | 2 +- src/liballoc/linked_list.rs | 4 ++-- src/liballoc/vec.rs | 2 +- src/liballoc/vec_deque.rs | 4 ++-- src/libcore/ops/place.rs | 5 ++++- src/libstd/collections/hash/map.rs | 2 +- 7 files changed, 12 insertions(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index 94bbaf92ce9..3041f85cd4c 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -1211,7 +1211,7 @@ where T: Clone + Ord { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for BinaryHeapPlace<'a, T> +unsafe impl<'a, T> Place for BinaryHeapPlace<'a, T> where T: Clone + Ord { fn pointer(&mut self) -> *mut T { self.place.pointer() diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6f125cdba81..c8ab3f681f8 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -142,7 +142,7 @@ pub struct IntermediateBox { #[unstable(feature = "placement_in", reason = "placement box design is still being worked out.", issue = "27779")] -impl Place for IntermediateBox { +unsafe impl Place for IntermediateBox { fn pointer(&mut self) -> *mut T { self.ptr as *mut T } diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 3ac5a85d721..ccb2da46f8d 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -1286,7 +1286,7 @@ impl<'a, T> Placer for FrontPlace<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for FrontPlace<'a, T> { +unsafe impl<'a, T> Place for FrontPlace<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { &mut (*self.node.pointer()).element } } @@ -1341,7 +1341,7 @@ impl<'a, T> Placer for BackPlace<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for BackPlace<'a, T> { +unsafe impl<'a, T> Place for BackPlace<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { &mut (*self.node.pointer()).element } } diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 301e44632b8..4a8982bf85c 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2544,7 +2544,7 @@ impl<'a, T> Placer for PlaceBack<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for PlaceBack<'a, T> { +unsafe impl<'a, T> Place for PlaceBack<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) } } diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index f56aa23a4eb..df49c1df082 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -2564,7 +2564,7 @@ impl<'a, T> Placer for PlaceBack<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for PlaceBack<'a, T> { +unsafe impl<'a, T> Place for PlaceBack<'a, T> { fn pointer(&mut self) -> *mut T { unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) } } @@ -2610,7 +2610,7 @@ impl<'a, T> Placer for PlaceFront<'a, T> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, T> Place for PlaceFront<'a, T> { +unsafe impl<'a, T> Place for PlaceFront<'a, T> { fn pointer(&mut self) -> *mut T { let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); unsafe { self.vec_deque.ptr().offset(tail as isize) } diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs index 9fb171e7b92..4c8c6e63fc6 100644 --- a/src/libcore/ops/place.rs +++ b/src/libcore/ops/place.rs @@ -27,10 +27,13 @@ /// implementation of Place to clean up any intermediate state /// (e.g. deallocate box storage, pop a stack, etc). #[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Place { +pub unsafe trait Place { /// Returns the address where the input value will be written. /// Note that the data at this address is generally uninitialized, /// and thus one should use `ptr::write` for initializing it. + /// + /// This function must return a valid (non-zero) pointer to + /// a location at which a value of type `Data` can be written. fn pointer(&mut self) -> *mut Data; } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 7a79a472d58..595b01ff77c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1932,7 +1932,7 @@ impl<'a, K, V> Placer for Entry<'a, K, V> { #[unstable(feature = "collection_placement", reason = "placement protocol is subject to change", issue = "30172")] -impl<'a, K, V> Place for EntryPlace<'a, K, V> { +unsafe impl<'a, K, V> Place for EntryPlace<'a, K, V> { fn pointer(&mut self) -> *mut V { self.bucket.read_mut().1 } -- cgit 1.4.1-3-g733a5 From 2624c05acf93ca2b35dae7ae3770fd92b5dce4b5 Mon Sep 17 00:00:00 2001 From: Nathaniel Ringo Date: Tue, 9 Jan 2018 14:21:45 -0600 Subject: Makes the constructors of Duration const fns. --- src/libstd/time/duration.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 15ddb62bab5..e0c90664119 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -73,7 +73,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] - pub fn new(secs: u64, nanos: u32) -> Duration { + pub const fn new(secs: u64, nanos: u32) -> Duration { let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) .expect("overflow in Duration::new"); let nanos = nanos % NANOS_PER_SEC; @@ -94,7 +94,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] - pub fn from_secs(secs: u64) -> Duration { + pub const fn from_secs(secs: u64) -> Duration { Duration { secs: secs, nanos: 0 } } @@ -112,7 +112,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] - pub fn from_millis(millis: u64) -> Duration { + pub const fn from_millis(millis: u64) -> Duration { let secs = millis / MILLIS_PER_SEC; let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI; Duration { secs: secs, nanos: nanos } @@ -133,7 +133,7 @@ impl Duration { /// ``` #[unstable(feature = "duration_from_micros", issue = "44400")] #[inline] - pub fn from_micros(micros: u64) -> Duration { + pub const fn from_micros(micros: u64) -> Duration { let secs = micros / MICROS_PER_SEC; let nanos = ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO; Duration { secs: secs, nanos: nanos } @@ -154,7 +154,7 @@ impl Duration { /// ``` #[unstable(feature = "duration_extras", issue = "46507")] #[inline] - pub fn from_nanos(nanos: u64) -> Duration { + pub const fn from_nanos(nanos: u64) -> Duration { let secs = nanos / (NANOS_PER_SEC as u64); let nanos = (nanos % (NANOS_PER_SEC as u64)) as u32; Duration { secs: secs, nanos: nanos } -- cgit 1.4.1-3-g733a5 From 7caf753d4413cb0ae7bc266fd89e56f1d3842857 Mon Sep 17 00:00:00 2001 From: Nathaniel Ringo Date: Tue, 9 Jan 2018 15:09:54 -0600 Subject: Fixes Duration constructor const fns other than new, reverts new to non-const. --- src/libstd/time/duration.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index e0c90664119..bb30d0d80bd 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -73,7 +73,7 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] - pub const fn new(secs: u64, nanos: u32) -> Duration { + pub fn new(secs: u64, nanos: u32) -> Duration { let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) .expect("overflow in Duration::new"); let nanos = nanos % NANOS_PER_SEC; @@ -113,9 +113,10 @@ impl Duration { #[stable(feature = "duration", since = "1.3.0")] #[inline] pub const fn from_millis(millis: u64) -> Duration { - let secs = millis / MILLIS_PER_SEC; - let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI; - Duration { secs: secs, nanos: nanos } + Duration { + secs: millis / MILLIS_PER_SEC, + nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI, + } } /// Creates a new `Duration` from the specified number of microseconds. @@ -134,9 +135,10 @@ impl Duration { #[unstable(feature = "duration_from_micros", issue = "44400")] #[inline] pub const fn from_micros(micros: u64) -> Duration { - let secs = micros / MICROS_PER_SEC; - let nanos = ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO; - Duration { secs: secs, nanos: nanos } + Duration { + secs: micros / MICROS_PER_SEC, + nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO, + } } /// Creates a new `Duration` from the specified number of nanoseconds. @@ -155,9 +157,10 @@ impl Duration { #[unstable(feature = "duration_extras", issue = "46507")] #[inline] pub const fn from_nanos(nanos: u64) -> Duration { - let secs = nanos / (NANOS_PER_SEC as u64); - let nanos = (nanos % (NANOS_PER_SEC as u64)) as u32; - Duration { secs: secs, nanos: nanos } + Duration { + secs: nanos / (NANOS_PER_SEC as u64), + nanos: (nanos % (NANOS_PER_SEC as u64)) as u32, + } } /// Returns the number of _whole_ seconds contained by this `Duration`. -- cgit 1.4.1-3-g733a5 From c25178c9fd15a5dffdc91d1905e44e6c39e306aa Mon Sep 17 00:00:00 2001 From: Nathaniel Ringo Date: Tue, 9 Jan 2018 15:31:25 -0600 Subject: Fixes whitespace. --- src/libstd/time/duration.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index bb30d0d80bd..f01a27c84c1 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -114,9 +114,9 @@ impl Duration { #[inline] pub const fn from_millis(millis: u64) -> Duration { Duration { - secs: millis / MILLIS_PER_SEC, - nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI, - } + secs: millis / MILLIS_PER_SEC, + nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI, + } } /// Creates a new `Duration` from the specified number of microseconds. @@ -136,9 +136,9 @@ impl Duration { #[inline] pub const fn from_micros(micros: u64) -> Duration { Duration { - secs: micros / MICROS_PER_SEC, - nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO, - } + secs: micros / MICROS_PER_SEC, + nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO, + } } /// Creates a new `Duration` from the specified number of nanoseconds. @@ -158,9 +158,9 @@ impl Duration { #[inline] pub const fn from_nanos(nanos: u64) -> Duration { Duration { - secs: nanos / (NANOS_PER_SEC as u64), - nanos: (nanos % (NANOS_PER_SEC as u64)) as u32, - } + secs: nanos / (NANOS_PER_SEC as u64), + nanos: (nanos % (NANOS_PER_SEC as u64)) as u32, + } } /// Returns the number of _whole_ seconds contained by this `Duration`. -- cgit 1.4.1-3-g733a5 From 090a968fe7680cce0d3aa8fde25a5dc48948e43e Mon Sep 17 00:00:00 2001 From: Ryan Cumming Date: Wed, 10 Jan 2018 20:13:03 +1100 Subject: Only link res_init() on GNU/*nix To workaround a bug in glibc <= 2.26 lookup_host() calls res_init() based on the glibc version detected at runtime. While this avoids calling res_init() on platforms where it's not required we will still end up linking against the symbol. This causes an issue on macOS where res_init() is implemented in a separate library (libresolv.9.dylib) from the main libc. While this is harmless for standalone programs it becomes a problem if Rust code is statically linked against another program. If the linked program doesn't already specify -lresolv it will cause the link to fail. This is captured in issue #46797 Fix this by hooking in to the glibc workaround in `cvt_gai` and only activating it for the "gnu" environment on Unix This should include all glibc platforms while excluding musl, windows-gnu, macOS, FreeBSD, etc. This has the side benefit of removing the #[cfg] in sys_common; only unix.rs has code related to the workaround now. --- src/libstd/sys/unix/l4re.rs | 4 ---- src/libstd/sys/unix/net.rs | 20 +++++++++++++------- src/libstd/sys_common/net.rs | 24 +++--------------------- 3 files changed, 16 insertions(+), 32 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs index c3e8d0b7d95..21218489679 100644 --- a/src/libstd/sys/unix/l4re.rs +++ b/src/libstd/sys/unix/l4re.rs @@ -437,9 +437,5 @@ pub mod net { pub fn lookup_host(_: &str) -> io::Result { unimpl!(); } - - pub fn res_init_if_glibc_before_2_26() -> io::Result<()> { - unimpl!(); - } } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index e775f857f2b..3f65975e608 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -51,6 +51,10 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { if err == 0 { return Ok(()) } + + // We may need to trigger a glibc workaround. See on_resolver_failure() for details. + on_resolver_failure(); + if err == EAI_SYSTEM { return Err(io::Error::last_os_error()) } @@ -377,21 +381,22 @@ impl IntoInner for Socket { // res_init unconditionally, we call it only when we detect we're linking // against glibc version < 2.26. (That is, when we both know its needed and // believe it's thread-safe). -pub fn res_init_if_glibc_before_2_26() -> io::Result<()> { +#[cfg(target_env = "gnu")] +fn on_resolver_failure() { // If the version fails to parse, we treat it the same as "not glibc". if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { if let Some(version) = parse_glibc_version(version_str) { if version < (2, 26) { - let ret = unsafe { libc::res_init() }; - if ret != 0 { - return Err(io::Error::last_os_error()); - } + unsafe { libc::res_init() }; } } } - Ok(()) } +#[cfg(not(target_env = "gnu"))] +fn on_resolver_failure() {} + +#[cfg(target_env = "gnu")] fn glibc_version_cstr() -> Option<&'static CStr> { weak! { fn gnu_get_libc_version() -> *const libc::c_char @@ -405,6 +410,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> { // Returns Some((major, minor)) if the string is a valid "x.y" version, // ignoring any extra dot-separated parts. Otherwise return None. +#[cfg(target_env = "gnu")] fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { let mut parsed_ints = version.split(".").map(str::parse::).fuse(); match (parsed_ints.next(), parsed_ints.next()) { @@ -413,7 +419,7 @@ fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { } } -#[cfg(test)] +#[cfg(all(test, taget_env = "gnu"))] mod test { use super::*; diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index c70b39995eb..b841afe1a51 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -166,27 +166,9 @@ pub fn lookup_host(host: &str) -> io::Result { hints.ai_socktype = c::SOCK_STREAM; let mut res = ptr::null_mut(); unsafe { - match cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) { - Ok(_) => { - Ok(LookupHost { original: res, cur: res }) - }, - #[cfg(unix)] - Err(e) => { - // If we're running glibc prior to version 2.26, the lookup - // failure could be caused by caching a stale /etc/resolv.conf. - // We need to call libc::res_init() to clear the cache. But we - // shouldn't call it in on any other platform, because other - // res_init implementations aren't thread-safe. See - // https://github.com/rust-lang/rust/issues/41570 and - // https://github.com/rust-lang/rust/issues/43592. - use sys::net::res_init_if_glibc_before_2_26; - let _ = res_init_if_glibc_before_2_26(); - Err(e) - }, - // the cfg is needed here to avoid an "unreachable pattern" warning - #[cfg(not(unix))] - Err(e) => Err(e), - } + cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| { + LookupHost { original: res, cur: res } + }) } } -- cgit 1.4.1-3-g733a5 From e9fdee8818f5c089013b9c8604e183b1cbd816ad Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 17 Jan 2018 08:37:03 -0800 Subject: Use File::metadata instead of fs::metadata to choose buffer size This replaces a `stat` syscall with `fstat` or similar, which can be faster. Fixes #47519. --- src/libstd/fs.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 51cb9609120..1325ca464c4 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -211,12 +211,12 @@ pub struct DirBuilder { recursive: bool, } -/// How large a buffer to pre-allocate before reading the entire file at `path`. -fn initial_buffer_size>(path: P) -> usize { +/// How large a buffer to pre-allocate before reading the entire file. +fn initial_buffer_size(file: &File) -> usize { // Allocate one extra byte so the buffer doesn't need to grow before the // final `read` call at the end of the file. Don't worry about `usize` // overflow because reading will fail regardless in that case. - metadata(path).map(|m| m.len() as usize + 1).unwrap_or(0) + file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0) } /// Read the entire contents of a file into a bytes vector. @@ -254,8 +254,9 @@ fn initial_buffer_size>(path: P) -> usize { /// ``` #[unstable(feature = "fs_read_write", issue = "46588")] pub fn read>(path: P) -> io::Result> { - let mut bytes = Vec::with_capacity(initial_buffer_size(&path)); - File::open(path)?.read_to_end(&mut bytes)?; + let mut file = File::open(path)?; + let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); + file.read_to_end(&mut bytes)?; Ok(bytes) } @@ -295,8 +296,9 @@ pub fn read>(path: P) -> io::Result> { /// ``` #[unstable(feature = "fs_read_write", issue = "46588")] pub fn read_string>(path: P) -> io::Result { - let mut string = String::with_capacity(initial_buffer_size(&path)); - File::open(path)?.read_to_string(&mut string)?; + let mut file = File::open(path)?; + let mut string = String::with_capacity(initial_buffer_size(&file)); + file.read_to_string(&mut string)?; Ok(string) } -- cgit 1.4.1-3-g733a5 From 1b9c65694354b6507627d4f1662a9123de9b764a Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 18 Jan 2018 01:22:20 +0100 Subject: Add some edge cases to the documentation of `Path` Affected methods are `starts_with` and `strip_prefix`. --- src/libstd/path.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 7631a9a44bb..ed102c2949e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1869,7 +1869,11 @@ impl Path { /// /// let path = Path::new("/test/haha/foo.txt"); /// + /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt"))); /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt"))); + /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new(""))); + /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("test").is_ok(), false); /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); /// ``` @@ -1900,6 +1904,9 @@ impl Path { /// let path = Path::new("/etc/passwd"); /// /// assert!(path.starts_with("/etc")); + /// assert!(path.starts_with("/etc/")); + /// assert!(path.starts_with("/etc/passwd")); + /// assert!(path.starts_with("/etc/passwd/")); /// /// assert!(!path.starts_with("/e")); /// ``` -- cgit 1.4.1-3-g733a5 From 908aa388f9f0745f133a044d75e8c994c17f3152 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 16 Jan 2018 20:54:48 -0800 Subject: Deprecate std::net::lookup_host We intended to do this quite a while ago but it snuck through. --- src/libstd/net/addr.rs | 5 ++++- src/libstd/net/mod.rs | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 1ca7e66ed9c..fa430939f05 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -12,7 +12,9 @@ use fmt; use hash; use io; use mem; -use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; +use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; +#[allow(deprecated)] +use net::lookup_host; use option; use sys::net::netc as c; use sys_common::{FromInner, AsInner, IntoInner}; @@ -845,6 +847,7 @@ impl ToSocketAddrs for (Ipv6Addr, u16) { } } +#[allow(deprecated)] fn resolve_socket_addr(s: &str, p: u16) -> io::Result> { let ips = lookup_host(s)?; let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect(); diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index 9fcb93e2032..eb0e2e13b4c 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -134,12 +134,15 @@ fn each_addr(addr: A, mut f: F) -> io::Result iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] pub struct LookupHost(net_imp::LookupHost); #[unstable(feature = "lookup_host", reason = "unsure about the returned \ iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[allow(deprecated)] impl Iterator for LookupHost { type Item = SocketAddr; fn next(&mut self) -> Option { self.0.next() } @@ -149,6 +152,8 @@ impl Iterator for LookupHost { iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[allow(deprecated)] impl fmt::Debug for LookupHost { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("LookupHost { .. }") @@ -181,6 +186,8 @@ impl fmt::Debug for LookupHost { iterator and returning socket \ addresses", issue = "27705")] +#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[allow(deprecated)] pub fn lookup_host(host: &str) -> io::Result { net_imp::lookup_host(host).map(LookupHost) } -- cgit 1.4.1-3-g733a5 From 14982db2d68268458a3de03e395b2e9afe518b50 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 23 Dec 2017 19:28:33 -0800 Subject: in which the unused-parens lint comes to cover function and method args Resolves #46137. --- src/liballoc/vec_deque.rs | 2 +- src/librustc_apfloat/ieee.rs | 2 +- src/librustc_lint/unused.rs | 12 ++++++++++++ src/librustc_mir/dataflow/impls/borrows.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/libstd/sys/unix/thread.rs | 4 ++-- src/test/compile-fail/lint-unnecessary-parens.rs | 12 +++++++----- 7 files changed, 25 insertions(+), 11 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index f56aa23a4eb..1f6c6660d9b 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -2480,7 +2480,7 @@ impl From> for Vec { if other.is_contiguous() { ptr::copy(buf.offset(tail as isize), buf, len); } else { - if (tail - head) >= cmp::min((cap - tail), head) { + if (tail - head) >= cmp::min(cap - tail, head) { // There is enough free space in the centre for the shortest block so we can // do this in at most three copy moves. if (cap - tail) > head { diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 3e76b60b84a..7abd02b6656 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -1434,7 +1434,7 @@ impl Float for IeeeFloat { let max_change = S::MAX_EXP as i32 - (S::MIN_EXP as i32 - sig_bits) + 1; // Clamp to one past the range ends to let normalize handle overflow. - let exp_change = cmp::min(cmp::max(exp as i32, (-max_change - 1)), max_change); + let exp_change = cmp::min(cmp::max(exp as i32, -max_change - 1), max_change); self.exp = self.exp.saturating_add(exp_change as ExpInt); self = self.normalize(round, Loss::ExactlyZero).value; if self.is_nan() { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 4e066ecf999..ef6475f9ee4 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -302,6 +302,18 @@ impl EarlyLintPass for UnusedParens { Assign(_, ref value) => (value, "assigned value", false), AssignOp(.., ref value) => (value, "assigned value", false), InPlace(_, ref value) => (value, "emplacement value", false), + Call(_, ref args) => { + for arg in args { + self.check_unused_parens_core(cx, arg, "function argument", false) + } + return; + }, + MethodCall(_, ref args) => { + for arg in &args[1..] { // first "argument" is self (which sometimes needs parens) + self.check_unused_parens_core(cx, arg, "method argument", false) + } + return; + } _ => return, }; self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index f76aea19677..f543a33b130 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -131,7 +131,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { } impl ReserveOrActivateIndex { - fn reserved(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new((i.index() * 2)) } + fn reserved(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new(i.index() * 2) } fn active(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new((i.index() * 2) + 1) } pub(crate) fn is_reservation(self) -> bool { self.index() % 2 == 0 } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5b9b3767cb6..231a32c4382 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -963,7 +963,7 @@ impl<'a> ModuleData<'a> { unresolved_invocations: RefCell::new(FxHashSet()), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), - globs: RefCell::new((Vec::new())), + globs: RefCell::new(Vec::new()), traits: RefCell::new(None), populated: Cell::new(normal_ancestor_id.is_local()), span, diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index cb249af4254..525882c1e1e 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -311,8 +311,8 @@ pub mod guard { #[cfg(target_os = "macos")] pub unsafe fn current() -> Option { - Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self()))) + Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - + libc::pthread_get_stacksize_np(libc::pthread_self())) } #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] diff --git a/src/test/compile-fail/lint-unnecessary-parens.rs b/src/test/compile-fail/lint-unnecessary-parens.rs index b5eac73a55d..7cd0a6bbf0f 100644 --- a/src/test/compile-fail/lint-unnecessary-parens.rs +++ b/src/test/compile-fail/lint-unnecessary-parens.rs @@ -13,19 +13,19 @@ #[derive(Eq, PartialEq)] struct X { y: bool } impl X { - fn foo(&self) -> bool { self.y } + fn foo(&self, conjunct: bool) -> bool { self.y && conjunct } } fn foo() -> isize { return (1); //~ ERROR unnecessary parentheses around `return` value } -fn bar() -> X { - return (X { y: true }); //~ ERROR unnecessary parentheses around `return` value +fn bar(y: bool) -> X { + return (X { y }); //~ ERROR unnecessary parentheses around `return` value } fn main() { foo(); - bar(); + bar((true)); //~ ERROR unnecessary parentheses around function argument if (true) {} //~ ERROR unnecessary parentheses around `if` condition while (true) {} //~ ERROR unnecessary parentheses around `while` condition @@ -40,13 +40,15 @@ fn main() { if (X { y: true } == v) {} if (X { y: false }.y) {} - while (X { y: false }.foo()) {} + while (X { y: false }.foo(true)) {} while (true | X { y: false }.y) {} match (X { y: false }) { _ => {} } + X { y: false }.foo((true)); //~ ERROR unnecessary parentheses around method argument + let mut _a = (0); //~ ERROR unnecessary parentheses around assigned value _a = (0); //~ ERROR unnecessary parentheses around assigned value _a += (1); //~ ERROR unnecessary parentheses around assigned value -- cgit 1.4.1-3-g733a5 From fdf444da766715ec6bb181eb12b553333e925eb4 Mon Sep 17 00:00:00 2001 From: Arthur Silva Date: Fri, 19 Jan 2018 15:40:02 +0100 Subject: Update BTreeMap recommendation Focus on the ordering/range benefit. --- src/libstd/collections/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index b8a6a66eaa6..e9a150f34a5 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -64,11 +64,11 @@ //! * You want a map, with no extra functionality. //! //! ### Use a `BTreeMap` when: +//! * You want a map sorted by its keys. +//! * You want to be able to get a range of entries on-demand. //! * You're interested in what the smallest or largest key-value pair is. //! * You want to find the largest or smallest key that is smaller or larger //! than something. -//! * You want to be able to get all of the entries in order on-demand. -//! * You want a map sorted by its keys. //! //! ### Use the `Set` variant of any of these `Map`s when: //! * You just want to remember which keys you've seen. -- cgit 1.4.1-3-g733a5 From f19baf0977b176ba26277af479a19b71b7ee1fdb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 18:58:39 +0100 Subject: Rename std::ptr::Shared to NonNull `Shared` is now a deprecated `type` alias. CC https://github.com/rust-lang/rust/issues/27730#issuecomment-352800629 --- src/liballoc/arc.rs | 18 +++---- src/liballoc/heap.rs | 2 +- src/liballoc/lib.rs | 2 +- src/liballoc/linked_list.rs | 28 +++++----- src/liballoc/rc.rs | 20 +++---- src/liballoc/vec.rs | 10 ++-- src/liballoc/vec_deque.rs | 6 +-- src/libcore/ptr.rs | 87 ++++++++++++++++--------------- src/librustc_data_structures/array_vec.rs | 6 +-- src/librustc_data_structures/lib.rs | 2 +- src/libstd/collections/hash/table.rs | 6 +-- src/libstd/lib.rs | 2 +- src/libstd/panic.rs | 6 +-- 13 files changed, 100 insertions(+), 95 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 185af8835d1..49a6220d591 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -25,7 +25,7 @@ use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val, uninitialized}; use core::ops::Deref; use core::ops::CoerceUnsized; -use core::ptr::{self, Shared}; +use core::ptr::{self, NonNull}; use core::marker::{Unsize, PhantomData}; use core::hash::{Hash, Hasher}; use core::{isize, usize}; @@ -197,7 +197,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// [rc_examples]: ../../std/rc/index.html#examples #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { - ptr: Shared>, + ptr: NonNull>, phantom: PhantomData, } @@ -234,7 +234,7 @@ impl, U: ?Sized> CoerceUnsized> for Arc {} /// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { - ptr: Shared>, + ptr: NonNull>, } #[stable(feature = "arc_weak", since = "1.4.0")] @@ -286,7 +286,7 @@ impl Arc { weak: atomic::AtomicUsize::new(1), data, }; - Arc { ptr: Shared::from(Box::into_unique(x)), phantom: PhantomData } + Arc { ptr: NonNull::from(Box::into_unique(x)), phantom: PhantomData } } /// Returns the contained value, if the `Arc` has exactly one strong reference. @@ -397,7 +397,7 @@ impl Arc { let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); Arc { - ptr: Shared::new_unchecked(arc_ptr), + ptr: NonNull::new_unchecked(arc_ptr), phantom: PhantomData, } } @@ -582,7 +582,7 @@ impl Arc { // Free the allocation without dropping its contents box_free(bptr); - Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -609,7 +609,7 @@ impl Arc<[T]> { &mut (*ptr).data as *mut [T] as *mut T, v.len()); - Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } @@ -669,7 +669,7 @@ impl ArcFromSlice for Arc<[T]> { // All clear. Forget the guard so it doesn't free the new ArcInner. mem::forget(guard); - Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -991,7 +991,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::from(Box::into_unique(box ArcInner { + ptr: NonNull::from(Box::into_unique(box ArcInner { strong: atomic::AtomicUsize::new(0), weak: atomic::AtomicUsize::new(1), data: uninitialized(), diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index b2bd9d7d8fa..37af9ea5295 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -232,7 +232,7 @@ unsafe impl Alloc for Heap { /// /// This preserves the non-null invariant for types like `Box`. The address /// may overlap with non-zero-size memory allocations. -#[rustc_deprecated(since = "1.19", reason = "Use Unique/Shared::empty() instead")] +#[rustc_deprecated(since = "1.19", reason = "Use Unique/NonNull::empty() instead")] #[unstable(feature = "heap_api", issue = "27700")] pub const EMPTY: *mut () = 1 as *mut (); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 6ee4f802802..eaad6f1116f 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -103,6 +103,7 @@ #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] +#![feature(nonnull)] #![feature(nonzero)] #![feature(offset_to)] #![feature(optin_builtin_traits)] @@ -110,7 +111,6 @@ #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(rustc_attrs)] -#![feature(shared)] #![feature(slice_get_slice)] #![feature(slice_patterns)] #![feature(slice_rsplit)] diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 3ac5a85d721..e6e84101275 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -29,7 +29,7 @@ use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem; use core::ops::{BoxPlace, InPlace, Place, Placer}; -use core::ptr::{self, Shared}; +use core::ptr::{self, NonNull}; use boxed::{Box, IntermediateBox}; use super::SpecExtend; @@ -44,15 +44,15 @@ use super::SpecExtend; /// more memory efficient and make better use of CPU cache. #[stable(feature = "rust1", since = "1.0.0")] pub struct LinkedList { - head: Option>>, - tail: Option>>, + head: Option>>, + tail: Option>>, len: usize, marker: PhantomData>>, } struct Node { - next: Option>>, - prev: Option>>, + next: Option>>, + prev: Option>>, element: T, } @@ -65,8 +65,8 @@ struct Node { /// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { - head: Option>>, - tail: Option>>, + head: Option>>, + tail: Option>>, len: usize, marker: PhantomData<&'a Node>, } @@ -98,8 +98,8 @@ impl<'a, T> Clone for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { list: &'a mut LinkedList, - head: Option>>, - tail: Option>>, + head: Option>>, + tail: Option>>, len: usize, } @@ -157,7 +157,7 @@ impl LinkedList { unsafe { node.next = self.head; node.prev = None; - let node = Some(Shared::from(Box::into_unique(node))); + let node = Some(NonNull::from(Box::into_unique(node))); match self.head { None => self.tail = node, @@ -192,7 +192,7 @@ impl LinkedList { unsafe { node.next = None; node.prev = self.tail; - let node = Some(Shared::from(Box::into_unique(node))); + let node = Some(NonNull::from(Box::into_unique(node))); match self.tail { None => self.head = node, @@ -225,7 +225,7 @@ impl LinkedList { /// /// Warning: this will not check that the provided node belongs to the current list. #[inline] - unsafe fn unlink_node(&mut self, mut node: Shared>) { + unsafe fn unlink_node(&mut self, mut node: NonNull>) { let node = node.as_mut(); match node.prev { @@ -986,7 +986,7 @@ impl<'a, T> IterMut<'a, T> { Some(prev) => prev, }; - let node = Some(Shared::from(Box::into_unique(box Node { + let node = Some(NonNull::from(Box::into_unique(box Node { next: Some(head), prev: Some(prev), element, @@ -1038,7 +1038,7 @@ pub struct DrainFilter<'a, T: 'a, F: 'a> where F: FnMut(&mut T) -> bool, { list: &'a mut LinkedList, - it: Option>>, + it: Option>>, pred: F, idx: usize, old_len: usize, diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 59079f9ba76..aa7b96139fa 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -256,7 +256,7 @@ use core::marker::{Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val, uninitialized}; use core::ops::Deref; use core::ops::CoerceUnsized; -use core::ptr::{self, Shared}; +use core::ptr::{self, NonNull}; use core::convert::From; use heap::{Heap, Alloc, Layout, box_free}; @@ -282,7 +282,7 @@ struct RcBox { /// [get_mut]: #method.get_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { - ptr: Shared>, + ptr: NonNull>, phantom: PhantomData, } @@ -311,7 +311,7 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - ptr: Shared::from(Box::into_unique(box RcBox { + ptr: NonNull::from(Box::into_unique(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value, @@ -428,7 +428,7 @@ impl Rc { let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); Rc { - ptr: Shared::new_unchecked(rc_ptr), + ptr: NonNull::new_unchecked(rc_ptr), phantom: PhantomData, } } @@ -649,7 +649,7 @@ impl Rc { let raw: *const RcBox = self.ptr.as_ptr(); forget(self); Ok(Rc { - ptr: Shared::new_unchecked(raw as *const RcBox as *mut _), + ptr: NonNull::new_unchecked(raw as *const RcBox as *mut _), phantom: PhantomData, }) } @@ -695,7 +695,7 @@ impl Rc { // Free the allocation without dropping its contents box_free(bptr); - Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -722,7 +722,7 @@ impl Rc<[T]> { &mut (*ptr).value as *mut [T] as *mut T, v.len()); - Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } @@ -781,7 +781,7 @@ impl RcFromSlice for Rc<[T]> { // All clear. Forget the guard so it doesn't free the new RcBox. forget(guard); - Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData } + Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } } } @@ -1160,7 +1160,7 @@ impl From> for Rc<[T]> { /// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { - ptr: Shared>, + ptr: NonNull>, } #[stable(feature = "rc_weak", since = "1.4.0")] @@ -1190,7 +1190,7 @@ impl Weak { pub fn new() -> Weak { unsafe { Weak { - ptr: Shared::from(Box::into_unique(box RcBox { + ptr: NonNull::from(Box::into_unique(box RcBox { strong: Cell::new(0), weak: Cell::new(1), value: uninitialized(), diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 301e44632b8..b14b9d74765 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -78,7 +78,7 @@ use core::num::Float; use core::ops::{InPlace, Index, IndexMut, Place, Placer}; use core::ops; use core::ptr; -use core::ptr::Shared; +use core::ptr::NonNull; use core::slice; use borrow::ToOwned; @@ -1124,7 +1124,7 @@ impl Vec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - vec: Shared::from(self), + vec: NonNull::from(self), } } } @@ -1745,7 +1745,7 @@ impl IntoIterator for Vec { let cap = self.buf.cap(); mem::forget(self); IntoIter { - buf: Shared::new_unchecked(begin), + buf: NonNull::new_unchecked(begin), phantom: PhantomData, cap, ptr: begin, @@ -2267,7 +2267,7 @@ impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { /// [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - buf: Shared, + buf: NonNull, phantom: PhantomData, cap: usize, ptr: *const T, @@ -2442,7 +2442,7 @@ pub struct Drain<'a, T: 'a> { tail_len: usize, /// Current remaining range to remove iter: slice::Iter<'a, T>, - vec: Shared>, + vec: NonNull>, } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index f56aa23a4eb..8f05a69c5f3 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -23,7 +23,7 @@ use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; -use core::ptr::Shared; +use core::ptr::NonNull; use core::slice; use core::hash::{Hash, Hasher}; @@ -895,7 +895,7 @@ impl VecDeque { self.head = drain_tail; Drain { - deque: Shared::from(&mut *self), + deque: NonNull::from(&mut *self), after_tail: drain_head, after_head: head, iter: Iter { @@ -2154,7 +2154,7 @@ pub struct Drain<'a, T: 'a> { after_tail: usize, after_head: usize, iter: Iter<'a, T>, - deque: Shared>, + deque: NonNull>, } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4da51a33128..fd8f9138f36 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2321,7 +2321,7 @@ impl PartialOrd for *mut T { /// its owning Unique. /// /// If you're uncertain of whether it's correct to use `Unique` for your purposes, -/// consider using `Shared`, which has weaker semantics. +/// consider using `NonNull`, which has weaker semantics. /// /// Unlike `*mut T`, the pointer must always be non-null, even if the pointer /// is never dereferenced. This is so that enums may use this forbidden value @@ -2452,18 +2452,23 @@ impl<'a, T: ?Sized> From<&'a T> for Unique { } } +/// Previous name of `NonNull`. +#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")] +#[unstable(feature = "shared", issue = "27730")] +pub type Shared = NonNull; + /// `*mut T` but non-zero and covariant. /// /// This is often the correct thing to use when building data structures using /// raw pointers, but is ultimately more dangerous to use because of its additional -/// properties. If you're not sure if you should use `Shared`, just use `*mut T`! +/// properties. If you're not sure if you should use `NonNull`, just use `*mut T`! /// /// Unlike `*mut T`, the pointer must always be non-null, even if the pointer /// is never dereferenced. This is so that enums may use this forbidden value -/// as a discriminant -- `Option>` has the same size as `Shared`. +/// as a discriminant -- `Option>` has the same size as `NonNull`. /// However the pointer may still dangle if it isn't dereferenced. /// -/// Unlike `*mut T`, `Shared` is covariant over `T`. If this is incorrect +/// Unlike `*mut T`, `NonNull` is covariant over `T`. If this is incorrect /// for your use case, you should include some PhantomData in your type to /// provide invariance, such as `PhantomData>` or `PhantomData<&'a mut T>`. /// Usually this won't be necessary; covariance is correct for most safe abstractions, @@ -2471,56 +2476,56 @@ impl<'a, T: ?Sized> From<&'a T> for Unique { /// provide a public API that follows the normal shared XOR mutable rules of Rust. #[unstable(feature = "shared", reason = "needs an RFC to flesh out design", issue = "27730")] -pub struct Shared { +pub struct NonNull { pointer: NonZero<*const T>, } #[unstable(feature = "shared", issue = "27730")] -impl fmt::Debug for Shared { +impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:p}", self.as_ptr()) } } -/// `Shared` pointers are not `Send` because the data they reference may be aliased. +/// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "shared", issue = "27730")] -impl !Send for Shared { } +#[unstable(feature = "nonnull", issue = "27730")] +impl !Send for NonNull { } -/// `Shared` pointers are not `Sync` because the data they reference may be aliased. +/// `NonNull` pointers are not `Sync` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "shared", issue = "27730")] -impl !Sync for Shared { } +#[unstable(feature = "nonnull", issue = "27730")] +impl !Sync for NonNull { } -#[unstable(feature = "shared", issue = "27730")] -impl Shared { - /// Creates a new `Shared` that is dangling, but well-aligned. +#[unstable(feature = "nonnull", issue = "27730")] +impl NonNull { + /// Creates a new `NonNull` that is dangling, but well-aligned. /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; - Shared::new_unchecked(ptr) + NonNull::new_unchecked(ptr) } } } -#[unstable(feature = "shared", issue = "27730")] -impl Shared { - /// Creates a new `Shared`. +#[unstable(feature = "nonnull", issue = "27730")] +impl NonNull { + /// Creates a new `NonNull`. /// /// # Safety /// /// `ptr` must be non-null. - #[unstable(feature = "shared", issue = "27730")] + #[unstable(feature = "nonnull", issue = "27730")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - Shared { pointer: NonZero::new_unchecked(ptr) } + NonNull { pointer: NonZero::new_unchecked(ptr) } } - /// Creates a new `Shared` if `ptr` is non-null. + /// Creates a new `NonNull` if `ptr` is non-null. pub fn new(ptr: *mut T) -> Option { - NonZero::new(ptr as *const T).map(|nz| Shared { pointer: nz }) + NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) } /// Acquires the underlying `*mut` pointer. @@ -2548,49 +2553,49 @@ impl Shared { /// Acquires the underlying pointer as a `*mut` pointer. #[rustc_deprecated(since = "1.19", reason = "renamed to `as_ptr` for ergonomics/consistency")] - #[unstable(feature = "shared", issue = "27730")] + #[unstable(feature = "nonnull", issue = "27730")] pub unsafe fn as_mut_ptr(&self) -> *mut T { self.as_ptr() } } -#[unstable(feature = "shared", issue = "27730")] -impl Clone for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl Clone for NonNull { fn clone(&self) -> Self { *self } } -#[unstable(feature = "shared", issue = "27730")] -impl Copy for Shared { } +#[unstable(feature = "nonnull", issue = "27730")] +impl Copy for NonNull { } -#[unstable(feature = "shared", issue = "27730")] -impl CoerceUnsized> for Shared where T: Unsize { } +#[unstable(feature = "nonnull", issue = "27730")] +impl CoerceUnsized> for NonNull where T: Unsize { } -#[unstable(feature = "shared", issue = "27730")] -impl fmt::Pointer for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[unstable(feature = "shared", issue = "27730")] -impl From> for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl From> for NonNull { fn from(unique: Unique) -> Self { - Shared { pointer: unique.pointer } + NonNull { pointer: unique.pointer } } } -#[unstable(feature = "shared", issue = "27730")] -impl<'a, T: ?Sized> From<&'a mut T> for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { - Shared { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero::from(reference) } } } -#[unstable(feature = "shared", issue = "27730")] -impl<'a, T: ?Sized> From<&'a T> for Shared { +#[unstable(feature = "nonnull", issue = "27730")] +impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { - Shared { pointer: NonZero::from(reference) } + NonNull { pointer: NonZero::from(reference) } } } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 57fc78ef531..511c407d45a 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -12,7 +12,7 @@ use std::marker::Unsize; use std::iter::Extend; -use std::ptr::{self, drop_in_place, Shared}; +use std::ptr::{self, drop_in_place, NonNull}; use std::ops::{Deref, DerefMut, Range}; use std::hash::{Hash, Hasher}; use std::slice; @@ -146,7 +146,7 @@ impl ArrayVec { tail_start: end, tail_len: len - end, iter: range_slice.iter(), - array_vec: Shared::from(self), + array_vec: NonNull::from(self), } } } @@ -232,7 +232,7 @@ pub struct Drain<'a, A: Array> tail_start: usize, tail_len: usize, iter: slice::Iter<'a, ManuallyDrop>, - array_vec: Shared>, + array_vec: NonNull>, } impl<'a, A: Array> Iterator for Drain<'a, A> { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 24048e606df..1d53825ac37 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -21,8 +21,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(shared)] #![feature(collections_range)] +#![feature(nonnull)] #![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 96f98efe4aa..73bd5747c10 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -16,7 +16,7 @@ use marker; use mem::{align_of, size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; -use ptr::{self, Unique, Shared}; +use ptr::{self, Unique, NonNull}; use self::BucketState::*; @@ -873,7 +873,7 @@ impl RawTable { elems_left, marker: marker::PhantomData, }, - table: Shared::from(self), + table: NonNull::from(self), marker: marker::PhantomData, } } @@ -1020,7 +1020,7 @@ impl IntoIter { /// Iterator over the entries in a table, clearing the table. pub struct Drain<'a, K: 'a, V: 'a> { - table: Shared>, + table: NonNull>, iter: RawBuckets<'static, K, V>, marker: marker::PhantomData<&'a RawTable>, } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bb38fc55091..8a1ba32f7dc 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -283,6 +283,7 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] +#![feature(nonnull)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] @@ -297,7 +298,6 @@ #![feature(raw)] #![feature(repr_align)] #![feature(rustc_attrs)] -#![feature(shared)] #![feature(sip_hash_13)] #![feature(slice_bytes)] #![feature(slice_concat_ext)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 53c2211745c..68584b7cf25 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -17,7 +17,7 @@ use cell::UnsafeCell; use fmt; use ops::{Deref, DerefMut}; use panicking; -use ptr::{Unique, Shared}; +use ptr::{Unique, NonNull}; use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; @@ -198,8 +198,8 @@ impl UnwindSafe for *const T {} impl UnwindSafe for *mut T {} #[unstable(feature = "unique", issue = "27730")] impl UnwindSafe for Unique {} -#[unstable(feature = "shared", issue = "27730")] -impl UnwindSafe for Shared {} +#[unstable(feature = "nonnull", issue = "27730")] +impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} #[stable(feature = "catch_unwind", since = "1.9.0")] -- cgit 1.4.1-3-g733a5 From c97c1f7dc3b8c2e5e1c40681094c45cf55be5832 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 19:29:16 +0100 Subject: Mark Unique as perma-unstable, with the feature renamed to ptr_internals. --- src/doc/nomicon | 2 +- src/liballoc/lib.rs | 2 +- src/libcore/ptr.rs | 30 +++++++++++++++--------------- src/libcore/tests/lib.rs | 2 +- src/libcore/tests/ptr.rs | 4 ++-- src/libstd/lib.rs | 2 +- src/libstd/panic.rs | 2 +- src/test/run-pass/issue-23433.rs | 6 +++--- 8 files changed, 25 insertions(+), 25 deletions(-) (limited to 'src/libstd') diff --git a/src/doc/nomicon b/src/doc/nomicon index 2f7b05fd593..fec3182d0b0 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 2f7b05fd5939aa49d52c4ab309b9a47776ba7bd8 +Subproject commit fec3182d0b0a3cf8122e192b3270064a5b19be5b diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index eaad6f1116f..07e4ccc45a9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -110,6 +110,7 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] +#![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] #![feature(slice_patterns)] @@ -120,7 +121,6 @@ #![feature(trusted_len)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(unique)] #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 89ecb3457fc..e39c520880a 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2330,8 +2330,9 @@ impl PartialOrd for *mut T { /// /// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct /// for any type which upholds Unique's aliasing requirements. -#[unstable(feature = "unique", reason = "needs an RFC to flesh out design", - issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0", + reason = "use NonNull instead and consider PhantomData \ + (if you also use #[may_dangle]), Send, and/or Sync")] pub struct Unique { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2342,7 +2343,7 @@ pub struct Unique { _marker: PhantomData, } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl fmt::Debug for Unique { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:p}", self.as_ptr()) @@ -2353,17 +2354,17 @@ impl fmt::Debug for Unique { /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] unsafe impl Send for Unique { } /// `Unique` pointers are `Sync` if `T` is `Sync` because the data they /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] unsafe impl Sync for Unique { } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Unique { /// Creates a new `Unique` that is dangling, but well-aligned. /// @@ -2377,14 +2378,13 @@ impl Unique { } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Unique { /// Creates a new `Unique`. /// /// # Safety /// /// `ptr` must be non-null. - #[unstable(feature = "unique", issue = "27730")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { Unique { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData } } @@ -2418,41 +2418,41 @@ impl Unique { } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Clone for Unique { fn clone(&self) -> Self { *self } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl Copy for Unique { } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl CoerceUnsized> for Unique where T: Unsize { } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl fmt::Pointer for Unique { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a mut T> for Unique { fn from(reference: &'a mut T) -> Self { Unique { pointer: NonZero::from(reference), _marker: PhantomData } } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a T> for Unique { fn from(reference: &'a T) -> Self { Unique { pointer: NonZero::from(reference), _marker: PhantomData } } } -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From> for Unique { fn from(p: NonNull) -> Self { Unique { pointer: p.pointer, _marker: PhantomData } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 2c0009569d7..bc7052d676d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,6 +27,7 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] +#![feature(nonnull)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] @@ -41,7 +42,6 @@ #![feature(trusted_len)] #![feature(try_from)] #![feature(try_trait)] -#![feature(unique)] #![feature(exact_chunks)] extern crate core; diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index 98436f0e1d1..00f87336f3c 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -249,9 +249,9 @@ fn test_set_memory() { } #[test] -fn test_unsized_unique() { +fn test_unsized_nonnull() { let xs: &[i32] = &[1, 2, 3]; - let ptr = unsafe { Unique::new_unchecked(xs as *const [i32] as *mut [i32]) }; + let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) }; let ys = unsafe { ptr.as_ref() }; let zs: &[i32] = &[1, 2, 3]; assert!(ys == zs); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 8a1ba32f7dc..9f65d61658c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -294,6 +294,7 @@ #![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(prelude_import)] +#![feature(ptr_internals)] #![feature(rand)] #![feature(raw)] #![feature(repr_align)] @@ -315,7 +316,6 @@ #![feature(try_from)] #![feature(unboxed_closures)] #![feature(unicode)] -#![feature(unique)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 68584b7cf25..6f7d8ddb770 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -196,7 +196,7 @@ impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} impl UnwindSafe for *const T {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for *mut T {} -#[unstable(feature = "unique", issue = "27730")] +#[unstable(feature = "ptr_internals", issue = "0")] impl UnwindSafe for Unique {} #[unstable(feature = "nonnull", issue = "27730")] impl UnwindSafe for NonNull {} diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index aa13d6fad47..37cc1b134c3 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -10,13 +10,13 @@ // Don't fail if we encounter a NonZero<*T> where T is an unsized type -#![feature(unique)] +#![feature(nonnull)] -use std::ptr::Unique; +use std::ptr::NonNull; fn main() { let mut a = [0u8; 5]; - let b: Option> = Some(Unique::from(&mut a)); + let b: Option> = Some(NonNull::from(&mut a)); match b { Some(_) => println!("Got `Some`"), None => panic!("Unexpected `None`"), -- cgit 1.4.1-3-g733a5 From 55c50cd8ac5ed5a799bc9f5aa1fe8fcfbb956706 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 22 Dec 2017 19:50:21 +0100 Subject: Stabilize std::ptr::NonNull --- src/liballoc/boxed.rs | 10 ++-------- src/liballoc/lib.rs | 1 - src/libcore/ptr.rs | 32 +++++++++++++++++--------------- src/libcore/tests/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd/panic.rs | 2 +- src/test/run-pass/issue-23433.rs | 2 -- 8 files changed, 20 insertions(+), 30 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 994466e2249..e7bc10dfaa9 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -288,16 +288,13 @@ impl Box { /// # Examples /// /// ``` - /// #![feature(nonnull)] - /// /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_nonnull_raw(x); /// let x = unsafe { Box::from_nonnull_raw(ptr) }; /// } /// ``` - #[unstable(feature = "nonnull", reason = "needs an RFC to flesh out design", - issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] #[inline] pub unsafe fn from_nonnull_raw(u: NonNull) -> Self { Box(u.into()) @@ -352,15 +349,12 @@ impl Box { /// # Examples /// /// ``` - /// #![feature(nonnull)] - /// /// fn main() { /// let x = Box::new(5); /// let ptr = Box::into_nonnull_raw(x); /// } /// ``` - #[unstable(feature = "nonnull", reason = "needs an RFC to flesh out design", - issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] #[inline] pub fn into_nonnull_raw(b: Box) -> NonNull { Box::into_unique(b).into() diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 07e4ccc45a9..f25b455f915 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -103,7 +103,6 @@ #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(offset_to)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6cb84615d09..2e5f36ed71f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2481,13 +2481,12 @@ pub type Shared = NonNull; /// Usually this won't be necessary; covariance is correct for most safe abstractions, /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. -#[unstable(feature = "shared", reason = "needs an RFC to flesh out design", - issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] pub struct NonNull { pointer: NonZero<*const T>, } -#[unstable(feature = "shared", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:p}", self.as_ptr()) @@ -2496,20 +2495,20 @@ impl fmt::Debug for NonNull { /// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl !Send for NonNull { } /// `NonNull` pointers are not `Sync` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl !Sync for NonNull { } -#[unstable(feature = "nonnull", issue = "27730")] impl NonNull { /// Creates a new `NonNull` that is dangling, but well-aligned. /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn empty() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; @@ -2518,24 +2517,25 @@ impl NonNull { } } -#[unstable(feature = "nonnull", issue = "27730")] impl NonNull { /// Creates a new `NonNull`. /// /// # Safety /// /// `ptr` must be non-null. - #[unstable(feature = "nonnull", issue = "27730")] + #[stable(feature = "nonnull", since = "1.24.0")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { NonNull { pointer: NonZero::new_unchecked(ptr) } } /// Creates a new `NonNull` if `ptr` is non-null. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn new(ptr: *mut T) -> Option { NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) } /// Acquires the underlying `*mut` pointer. + #[stable(feature = "nonnull", since = "1.24.0")] pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T } @@ -2545,6 +2545,7 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`. + #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_ref(&self) -> &T { &*self.as_ptr() } @@ -2554,46 +2555,47 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr_mut()`. + #[stable(feature = "nonnull", since = "1.24.0")] pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl Clone for NonNull { fn clone(&self) -> Self { *self } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl Copy for NonNull { } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl CoerceUnsized> for NonNull where T: Unsize { } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero::from(reference) } } } -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero::from(reference) } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bc7052d676d..1c32452f846 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -27,7 +27,6 @@ #![feature(iterator_try_fold)] #![feature(iter_rfind)] #![feature(iter_rfold)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(pattern)] #![feature(raw)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1d53825ac37..a35ef2f7ce7 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -22,7 +22,6 @@ #![deny(warnings)] #![feature(collections_range)] -#![feature(nonnull)] #![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9f65d61658c..91cc6d25cce 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -283,7 +283,6 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] -#![feature(nonnull)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 6f7d8ddb770..560876006d3 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -198,7 +198,7 @@ impl UnwindSafe for *const T {} impl UnwindSafe for *mut T {} #[unstable(feature = "ptr_internals", issue = "0")] impl UnwindSafe for Unique {} -#[unstable(feature = "nonnull", issue = "27730")] +#[stable(feature = "nonnull", since = "1.24.0")] impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} diff --git a/src/test/run-pass/issue-23433.rs b/src/test/run-pass/issue-23433.rs index 37cc1b134c3..7af732f561d 100644 --- a/src/test/run-pass/issue-23433.rs +++ b/src/test/run-pass/issue-23433.rs @@ -10,8 +10,6 @@ // Don't fail if we encounter a NonZero<*T> where T is an unsized type -#![feature(nonnull)] - use std::ptr::NonNull; fn main() { -- cgit 1.4.1-3-g733a5 From 3f557947abf99b262aab994e896522c76329d315 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 21 Jan 2018 09:48:23 +0100 Subject: NonNull ended up landing in 1.25 --- src/libcore/ptr.rs | 36 ++++++++++++++++++------------------ src/libstd/panic.rs | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index fab5832d905..607e4a1a9fa 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2461,7 +2461,7 @@ impl<'a, T: ?Sized> From> for Unique { } /// Previous name of `NonNull`. -#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")] +#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")] #[unstable(feature = "shared", issue = "27730")] pub type Shared = NonNull; @@ -2482,12 +2482,12 @@ pub type Shared = NonNull; /// Usually this won't be necessary; covariance is correct for most safe abstractions, /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] pub struct NonNull { pointer: NonZero<*const T>, } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) @@ -2496,12 +2496,12 @@ impl fmt::Debug for NonNull { /// `NonNull` pointers are not `Send` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl !Send for NonNull { } /// `NonNull` pointers are not `Sync` because the data they reference may be aliased. // NB: This impl is unnecessary, but should provide better error messages. -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl !Sync for NonNull { } impl NonNull { @@ -2509,7 +2509,7 @@ impl NonNull { /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub fn dangling() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; @@ -2524,19 +2524,19 @@ impl NonNull { /// # Safety /// /// `ptr` must be non-null. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { NonNull { pointer: NonZero::new_unchecked(ptr) } } /// Creates a new `NonNull` if `ptr` is non-null. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub fn new(ptr: *mut T) -> Option { NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz }) } /// Acquires the underlying `*mut` pointer. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub fn as_ptr(self) -> *mut T { self.pointer.get() as *mut T } @@ -2546,7 +2546,7 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub unsafe fn as_ref(&self) -> &T { &*self.as_ptr() } @@ -2556,47 +2556,47 @@ impl NonNull { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. - #[stable(feature = "nonnull", since = "1.24.0")] + #[stable(feature = "nonnull", since = "1.25.0")] pub unsafe fn as_mut(&mut self) -> &mut T { &mut *self.as_ptr() } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl Clone for NonNull { fn clone(&self) -> Self { *self } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl CoerceUnsized> for NonNull where T: Unsize { } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Pointer for NonNull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero::from(reference) } } } -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero::from(reference) } diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 560876006d3..112e1106093 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -198,7 +198,7 @@ impl UnwindSafe for *const T {} impl UnwindSafe for *mut T {} #[unstable(feature = "ptr_internals", issue = "0")] impl UnwindSafe for Unique {} -#[stable(feature = "nonnull", since = "1.24.0")] +#[stable(feature = "nonnull", since = "1.25.0")] impl UnwindSafe for NonNull {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} -- cgit 1.4.1-3-g733a5 From 651ea8ea44d8ac8a02dc357412eb73f830057cae Mon Sep 17 00:00:00 2001 From: Cameron Hart Date: Tue, 26 Dec 2017 10:24:23 +1100 Subject: Stabilized `#[repr(align(x))]` attribute (RFC 1358) --- src/liballoc/tests/lib.rs | 1 - src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 30 ++++++++++++---------- src/test/codegen/align-struct.rs | 3 --- src/test/compile-fail/conflicting-repr-hints.rs | 2 -- src/test/compile-fail/repr-align.rs | 2 -- .../compile-fail/repr-packed-contains-align.rs | 2 -- src/test/run-pass/align-struct.rs | 2 -- src/test/run-pass/union/union-align.rs | 2 -- src/test/ui/feature-gate-repr_align.rs | 15 ----------- src/test/ui/feature-gate-repr_align.stderr | 10 -------- src/test/ui/print_type_sizes/repr-align.rs | 2 -- src/test/ui/span/gated-features-attr-spans.rs | 2 +- src/test/ui/span/gated-features-attr-spans.stderr | 10 +------- 14 files changed, 20 insertions(+), 65 deletions(-) delete mode 100644 src/test/ui/feature-gate-repr_align.rs delete mode 100644 src/test/ui/feature-gate-repr_align.stderr (limited to 'src/libstd') diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index eee229bc6fd..427a7adcbde 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(repr_align)] #![feature(slice_rotate)] #![feature(splice)] #![feature(str_escape)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 91cc6d25cce..a8049e676b3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -296,7 +296,6 @@ #![feature(ptr_internals)] #![feature(rand)] #![feature(raw)] -#![feature(repr_align)] #![feature(rustc_attrs)] #![feature(sip_hash_13)] #![feature(slice_bytes)] @@ -323,6 +322,7 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] +#![cfg_attr(stage0, feature(repr_align))] #![default_lib_allocator] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ac5a10ec703..5a7b53153fd 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -343,9 +343,6 @@ declare_features! ( // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), - // Allows `repr(align(u16))` struct attribute (RFC 1358) - (active, repr_align, "1.17.0", Some(33626)), - // Used to preserve symbols (see llvm.used) (active, used, "1.18.0", Some(40289)), @@ -546,6 +543,8 @@ declare_features! ( // Allows the sysV64 ABI to be specified on all platforms // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), + // Allows `repr(align(16))` struct attribute (RFC 1358) + (accepted, repr_align, "1.24.0", Some(33626)), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1456,15 +1455,25 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } + // allow attr_literals in #[repr(align(x))] + let mut is_repr_align = false; + if attr.path == "repr" { + if let Some(content) = attr.meta_item_list() { + is_repr_align = content.iter().any(|c| c.check_name("align")); + } + } + if self.context.features.proc_macro && attr::is_known(attr) { return } - let meta = panictry!(attr.parse_meta(self.context.parse_sess)); - if contains_novel_literal(&meta) { - gate_feature_post!(&self, attr_literals, attr.span, - "non-string literals in attributes, or string \ - literals in top-level positions, are experimental"); + if !is_repr_align { + let meta = panictry!(attr.parse_meta(self.context.parse_sess)); + if contains_novel_literal(&meta) { + gate_feature_post!(&self, attr_literals, attr.span, + "non-string literals in attributes, or string \ + literals in top-level positions, are experimental"); + } } } @@ -1522,11 +1531,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, repr_simd, attr.span, "SIMD types are experimental and possibly buggy"); } - if item.check_name("align") { - gate_feature_post!(&self, repr_align, attr.span, - "the struct `#[repr(align(u16))]` attribute \ - is experimental"); - } if item.check_name("transparent") { gate_feature_post!(&self, repr_transparent, attr.span, "the `#[repr(transparent)]` attribute \ diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs index ab9f5dda3a1..155319cb154 100644 --- a/src/test/codegen/align-struct.rs +++ b/src/test/codegen/align-struct.rs @@ -13,9 +13,6 @@ #![crate_type = "lib"] -#![feature(attr_literals)] -#![feature(repr_align)] - #[repr(align(64))] pub struct Align64(i32); // CHECK: %Align64 = type { [0 x i32], i32, [15 x i32] } diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs index 12ac8fb57b1..8acc8b7bb1e 100644 --- a/src/test/compile-fail/conflicting-repr-hints.rs +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -9,8 +9,6 @@ // except according to those terms. #![allow(dead_code)] -#![feature(attr_literals)] -#![feature(repr_align)] #[repr(C)] enum A { A } diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs index bc9cf065e5a..7c8eb6a2de9 100644 --- a/src/test/compile-fail/repr-align.rs +++ b/src/test/compile-fail/repr-align.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(dead_code)] -#![feature(attr_literals)] -#![feature(repr_align)] #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer struct A(i32); diff --git a/src/test/compile-fail/repr-packed-contains-align.rs b/src/test/compile-fail/repr-packed-contains-align.rs index 78d43064ea3..27890333a51 100644 --- a/src/test/compile-fail/repr-packed-contains-align.rs +++ b/src/test/compile-fail/repr-packed-contains-align.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(untagged_unions)] #![allow(dead_code)] diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs index e42aa868c47..dea8462705f 100644 --- a/src/test/run-pass/align-struct.rs +++ b/src/test/run-pass/align-struct.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(box_syntax)] use std::mem; diff --git a/src/test/run-pass/union/union-align.rs b/src/test/run-pass/union/union-align.rs index c0100df53e7..54e4e12d24f 100644 --- a/src/test/run-pass/union/union-align.rs +++ b/src/test/run-pass/union/union-align.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(untagged_unions)] use std::mem::{size_of, size_of_val, align_of, align_of_val}; diff --git a/src/test/ui/feature-gate-repr_align.rs b/src/test/ui/feature-gate-repr_align.rs deleted file mode 100644 index 9591d367a2d..00000000000 --- a/src/test/ui/feature-gate-repr_align.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -#![feature(attr_literals)] - -#[repr(align(64))] //~ error: the struct `#[repr(align(u16))]` attribute is experimental -struct Foo(u64, u64); - -fn main() {} diff --git a/src/test/ui/feature-gate-repr_align.stderr b/src/test/ui/feature-gate-repr_align.stderr deleted file mode 100644 index dd88067d58f..00000000000 --- a/src/test/ui/feature-gate-repr_align.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error[E0658]: the struct `#[repr(align(u16))]` attribute is experimental (see issue #33626) - --> $DIR/feature-gate-repr_align.rs:12:1 - | -12 | #[repr(align(64))] //~ error: the struct `#[repr(align(u16))]` attribute is experimental - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_align)] to the crate attributes to enable - -error: aborting due to previous error - diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs index 108b8dbba01..92928bba1c3 100644 --- a/src/test/ui/print_type_sizes/repr-align.rs +++ b/src/test/ui/print_type_sizes/repr-align.rs @@ -18,8 +18,6 @@ // It avoids using u64/i64 because on some targets that is only 4-byte // aligned (while on most it is 8-byte aligned) and so the resulting // padding and overall computed sizes can be quite different. -#![feature(attr_literals)] -#![feature(repr_align)] #![feature(start)] #![allow(dead_code)] diff --git a/src/test/ui/span/gated-features-attr-spans.rs b/src/test/ui/span/gated-features-attr-spans.rs index ace185d0169..83a4c5d5dd2 100644 --- a/src/test/ui/span/gated-features-attr-spans.rs +++ b/src/test/ui/span/gated-features-attr-spans.rs @@ -10,7 +10,7 @@ #![feature(attr_literals)] -#[repr(align(16))] //~ ERROR is experimental +#[repr(align(16))] struct Gem { mohs_hardness: u8, poofed: bool, diff --git a/src/test/ui/span/gated-features-attr-spans.stderr b/src/test/ui/span/gated-features-attr-spans.stderr index 74a2c1d742b..f15c4a72c5a 100644 --- a/src/test/ui/span/gated-features-attr-spans.stderr +++ b/src/test/ui/span/gated-features-attr-spans.stderr @@ -1,11 +1,3 @@ -error[E0658]: the struct `#[repr(align(u16))]` attribute is experimental (see issue #33626) - --> $DIR/gated-features-attr-spans.rs:13:1 - | -13 | #[repr(align(16))] //~ ERROR is experimental - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(repr_align)] to the crate attributes to enable - error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) --> $DIR/gated-features-attr-spans.rs:20:1 | @@ -30,5 +22,5 @@ warning: `#[must_use]` on functions is experimental (see issue #43302) | = help: add #![feature(fn_must_use)] to the crate attributes to enable -error: aborting due to 2 previous errors +error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 2f98f4b12b8fd5d93ffff3d7b98931b3f1f2b07a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jan 2018 16:31:53 +0100 Subject: Move PanicInfo and Location to libcore Per https://rust-lang.github.io/rfcs/2070-panic-implementation.html --- src/libcore/lib.rs | 1 + src/libcore/panic.rs | 213 ++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/panic.rs | 5 +- src/libstd/panicking.rs | 200 +++------------------------------------------ 5 files changed, 230 insertions(+), 190 deletions(-) create mode 100644 src/libcore/panic.rs (limited to 'src/libstd') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d5190b65863..11476a05dd3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -158,6 +158,7 @@ pub mod array; pub mod sync; pub mod cell; pub mod char; +pub mod panic; pub mod panicking; pub mod iter; pub mod option; diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs new file mode 100644 index 00000000000..dbfe531063b --- /dev/null +++ b/src/libcore/panic.rs @@ -0,0 +1,213 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Panic support in the standard library. + +#![unstable(feature = "core_panic_info", + reason = "newly available in libcore", + issue = "44489")] + +use any::Any; + +/// A struct providing information about a panic. +/// +/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] +/// function. +/// +/// [`set_hook`]: ../../std/panic/fn.set_hook.html +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|panic_info| { +/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); +/// })); +/// +/// panic!("Normal panic"); +/// ``` +#[stable(feature = "panic_hooks", since = "1.10.0")] +#[derive(Debug)] +pub struct PanicInfo<'a> { + payload: &'a (Any + Send), + location: Location<'a>, +} + +impl<'a> PanicInfo<'a> { + #![unstable(feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` \ + and related macros", + issue = "0")] + #[doc(hidden)] + pub fn internal_constructor(payload: &'a (Any + Send), location: Location<'a>,) -> Self { + PanicInfo { payload, location } + } + + /// Returns the payload associated with the panic. + /// + /// This will commonly, but not always, be a `&'static str` or [`String`]. + /// + /// [`String`]: ../../std/string/struct.String.html + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn payload(&self) -> &(Any + Send) { + self.payload + } + + /// Returns information about the location from which the panic originated, + /// if available. + /// + /// This method will currently always return [`Some`], but this may change + /// in future versions. + /// + /// [`Some`]: ../../std/option/enum.Option.html#variant.Some + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred in file '{}' at line {}", location.file(), + /// location.line()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn location(&self) -> Option<&Location> { + // NOTE: If this is changed to sometimes return None, + // deal with that case in std::panicking::default_hook. + Some(&self.location) + } +} + +/// A struct containing information about the location of a panic. +/// +/// This structure is created by the [`location`] method of [`PanicInfo`]. +/// +/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location +/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html +/// +/// # Examples +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|panic_info| { +/// if let Some(location) = panic_info.location() { +/// println!("panic occurred in file '{}' at line {}", location.file(), location.line()); +/// } else { +/// println!("panic occurred but can't get location information..."); +/// } +/// })); +/// +/// panic!("Normal panic"); +/// ``` +#[derive(Debug)] +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub struct Location<'a> { + file: &'a str, + line: u32, + col: u32, +} + +impl<'a> Location<'a> { + #![unstable(feature = "panic_internals", + reason = "internal details of the implementation of the `panic!` \ + and related macros", + issue = "0")] + #[doc(hidden)] + pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self { + Location { file, line, col } + } + + /// Returns the name of the source file from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred in file '{}'", location.file()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn file(&self) -> &str { + self.file + } + + /// Returns the line number from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred at line {}", location.line()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_hooks", since = "1.10.0")] + pub fn line(&self) -> u32 { + self.line + } + + /// Returns the column from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occurred at column {}", location.column()); + /// } else { + /// println!("panic occurred but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[stable(feature = "panic_col", since = "1.25")] + pub fn column(&self) -> u32 { + self.col + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 91cc6d25cce..4b374dc1407 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -288,6 +288,7 @@ #![feature(on_unimplemented)] #![feature(oom)] #![feature(optin_builtin_traits)] +#![feature(panic_internals)] #![feature(panic_unwind)] #![feature(peek)] #![feature(placement_in_syntax)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 560876006d3..566ef16f295 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -23,7 +23,10 @@ use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] -pub use panicking::{take_hook, set_hook, PanicInfo, Location}; +pub use panicking::{take_hook, set_hook}; + +#[stable(feature = "panic_hooks", since = "1.10.0")] +pub use core::panic::{PanicInfo, Location}; /// A marker trait which represents "panic safe" types in Rust. /// diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index f91eaf433d7..a748c89f9d4 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -21,6 +21,7 @@ use io::prelude::*; use any::Any; use cell::RefCell; +use core::panic::{PanicInfo, Location}; use fmt; use intrinsics; use mem; @@ -158,182 +159,6 @@ pub fn take_hook() -> Box { } } -/// A struct providing information about a panic. -/// -/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] -/// function. -/// -/// [`set_hook`]: ../../std/panic/fn.set_hook.html -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|panic_info| { -/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[stable(feature = "panic_hooks", since = "1.10.0")] -#[derive(Debug)] -pub struct PanicInfo<'a> { - payload: &'a (Any + Send), - location: Location<'a>, -} - -impl<'a> PanicInfo<'a> { - /// Returns the payload associated with the panic. - /// - /// This will commonly, but not always, be a `&'static str` or [`String`]. - /// - /// [`String`]: ../../std/string/struct.String.html - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn payload(&self) -> &(Any + Send) { - self.payload - } - - /// Returns information about the location from which the panic originated, - /// if available. - /// - /// This method will currently always return [`Some`], but this may change - /// in future versions. - /// - /// [`Some`]: ../../std/option/enum.Option.html#variant.Some - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}' at line {}", location.file(), - /// location.line()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn location(&self) -> Option<&Location> { - Some(&self.location) - } -} - -/// A struct containing information about the location of a panic. -/// -/// This structure is created by the [`location`] method of [`PanicInfo`]. -/// -/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location -/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html -/// -/// # Examples -/// -/// ```should_panic -/// use std::panic; -/// -/// panic::set_hook(Box::new(|panic_info| { -/// if let Some(location) = panic_info.location() { -/// println!("panic occurred in file '{}' at line {}", location.file(), location.line()); -/// } else { -/// println!("panic occurred but can't get location information..."); -/// } -/// })); -/// -/// panic!("Normal panic"); -/// ``` -#[derive(Debug)] -#[stable(feature = "panic_hooks", since = "1.10.0")] -pub struct Location<'a> { - file: &'a str, - line: u32, - col: u32, -} - -impl<'a> Location<'a> { - /// Returns the name of the source file from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred in file '{}'", location.file()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn file(&self) -> &str { - self.file - } - - /// Returns the line number from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at line {}", location.line()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn line(&self) -> u32 { - self.line - } - - /// Returns the column from which the panic originated. - /// - /// # Examples - /// - /// ```should_panic - /// use std::panic; - /// - /// panic::set_hook(Box::new(|panic_info| { - /// if let Some(location) = panic_info.location() { - /// println!("panic occurred at column {}", location.column()); - /// } else { - /// println!("panic occurred but can't get location information..."); - /// } - /// })); - /// - /// panic!("Normal panic"); - /// ``` - #[stable(feature = "panic_col", since = "1.25")] - pub fn column(&self) -> u32 { - self.col - } -} - fn default_hook(info: &PanicInfo) { #[cfg(feature = "backtrace")] use sys_common::backtrace; @@ -351,13 +176,14 @@ fn default_hook(info: &PanicInfo) { } }; - let file = info.location.file; - let line = info.location.line; - let col = info.location.col; + let location = info.location().unwrap(); // The current implementation always returns Some + let file = location.file(); + let line = location.line(); + let col = location.column(); - let msg = match info.payload.downcast_ref::<&'static str>() { + let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, - None => match info.payload.downcast_ref::() { + None => match info.payload().downcast_ref::() { Some(s) => &s[..], None => "Box", } @@ -563,14 +389,10 @@ fn rust_panic_with_hook(msg: Box, } unsafe { - let info = PanicInfo { - payload: &*msg, - location: Location { - file, - line, - col, - }, - }; + let info = PanicInfo::internal_constructor( + &*msg, + Location::internal_constructor(file, line, col), + ); HOOK_LOCK.read(); match HOOK { Hook::Default => default_hook(&info), -- cgit 1.4.1-3-g733a5 From 9e96c1ef7fcac0ac85b3c9160f5486e91dd27dd2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jan 2018 17:24:19 +0100 Subject: Add an unstable PanicInfo::message(&self) -> Option<&fmt::Arguments> method --- src/libcore/panic.rs | 19 +++++++++++++++++-- src/libstd/panicking.rs | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index dbfe531063b..2dfd950225c 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -15,6 +15,7 @@ issue = "44489")] use any::Any; +use fmt; /// A struct providing information about a panic. /// @@ -38,6 +39,7 @@ use any::Any; #[derive(Debug)] pub struct PanicInfo<'a> { payload: &'a (Any + Send), + message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>, } @@ -47,8 +49,11 @@ impl<'a> PanicInfo<'a> { and related macros", issue = "0")] #[doc(hidden)] - pub fn internal_constructor(payload: &'a (Any + Send), location: Location<'a>,) -> Self { - PanicInfo { payload, location } + pub fn internal_constructor(payload: &'a (Any + Send), + message: Option<&'a fmt::Arguments<'a>>, + location: Location<'a>) + -> Self { + PanicInfo { payload, location, message } } /// Returns the payload associated with the panic. @@ -73,6 +78,16 @@ impl<'a> PanicInfo<'a> { self.payload } + /// If the `panic!` macro from the `core` crate (not from `std`) + /// was used with a formatting string and some additional arguments, + /// returns that message ready to be used for example with [`fmt::write`] + /// + /// [`fmt::write`]: ../fmt/fn.write.html + #[unstable(feature = "panic_info_message", issue = "44489")] + pub fn message(&self) -> Option<&fmt::Arguments> { + self.message + } + /// Returns information about the location from which the panic originated, /// if available. /// diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index a748c89f9d4..3f5523548ce 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -391,6 +391,7 @@ fn rust_panic_with_hook(msg: Box, unsafe { let info = PanicInfo::internal_constructor( &*msg, + None, Location::internal_constructor(file, line, col), ); HOOK_LOCK.read(); -- cgit 1.4.1-3-g733a5 From f15c8169327244730f8e68598bf85d288e16fd70 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jan 2018 18:19:21 +0100 Subject: Make PanicInfo::message available for std::panic! with a formatting string. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables PanicInfo’s Display impl to show the panic message in those cases. --- src/libcore/panic.rs | 4 ++-- src/libstd/panicking.rs | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index cf8ceff6cda..14eb68d9b95 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -130,8 +130,8 @@ impl<'a> fmt::Display for PanicInfo<'a> { } // NOTE: we cannot use downcast_ref::() here // since String is not available in libcore! - // A String payload and no message is what we’d get from `std::panic!` - // called with multiple arguments. + // The payload is a String when `std::panic!` is called with multiple arguments, + // but in that case the message is also available. self.location.fmt(formatter) } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 3f5523548ce..161c3fc7113 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -344,7 +344,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, let mut s = String::new(); let _ = s.write_fmt(*msg); - begin_panic(s, file_line_col) + rust_panic_with_hook(Box::new(s), Some(msg), file_line_col) } /// This is the entry point of panicking for panic!() and assert!(). @@ -360,7 +360,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(Box::new(msg), file_line_col) + rust_panic_with_hook(Box::new(msg), None, file_line_col) } /// Executes the primary logic for a panic, including checking for recursive @@ -371,7 +371,8 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// run panic hooks, and then delegate to the actual implementation of panics. #[inline(never)] #[cold] -fn rust_panic_with_hook(msg: Box, +fn rust_panic_with_hook(payload: Box, + message: Option<&fmt::Arguments>, file_line_col: &(&'static str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; @@ -390,8 +391,8 @@ fn rust_panic_with_hook(msg: Box, unsafe { let info = PanicInfo::internal_constructor( - &*msg, - None, + &*payload, + message, Location::internal_constructor(file, line, col), ); HOOK_LOCK.read(); @@ -412,7 +413,7 @@ fn rust_panic_with_hook(msg: Box, unsafe { intrinsics::abort() } } - rust_panic(msg) + rust_panic(payload) } /// Shim around rust_panic. Called by resume_unwind. -- cgit 1.4.1-3-g733a5 From 399dcd112725a35352075262863781b3355452cd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 24 Jan 2018 22:25:42 +0100 Subject: Add missing micro version number component in stability attributes. --- src/liballoc/heap.rs | 2 +- src/libcore/panic.rs | 2 +- src/libcore/ptr.rs | 2 +- src/libstd/net/mod.rs | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 37af9ea5295..372d606e457 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -232,7 +232,7 @@ unsafe impl Alloc for Heap { /// /// This preserves the non-null invariant for types like `Box`. The address /// may overlap with non-zero-size memory allocations. -#[rustc_deprecated(since = "1.19", reason = "Use Unique/NonNull::empty() instead")] +#[rustc_deprecated(since = "1.19.0", reason = "Use Unique/NonNull::empty() instead")] #[unstable(feature = "heap_api", issue = "27700")] pub const EMPTY: *mut () = 1 as *mut (); diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 14eb68d9b95..4e72eaa57c7 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -238,7 +238,7 @@ impl<'a> Location<'a> { /// /// panic!("Normal panic"); /// ``` - #[stable(feature = "panic_col", since = "1.25")] + #[stable(feature = "panic_col", since = "1.25.0")] pub fn column(&self) -> u32 { self.col } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index fab5832d905..2c1dfb13633 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2461,7 +2461,7 @@ impl<'a, T: ?Sized> From> for Unique { } /// Previous name of `NonNull`. -#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")] +#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")] #[unstable(feature = "shared", issue = "27730")] pub type Shared = NonNull; diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index eb0e2e13b4c..eef043683b0 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -134,14 +134,14 @@ fn each_addr(addr: A, mut f: F) -> io::Result iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] pub struct LookupHost(net_imp::LookupHost); #[unstable(feature = "lookup_host", reason = "unsure about the returned \ iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] #[allow(deprecated)] impl Iterator for LookupHost { type Item = SocketAddr; @@ -152,7 +152,7 @@ impl Iterator for LookupHost { iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] #[allow(deprecated)] impl fmt::Debug for LookupHost { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -186,7 +186,7 @@ impl fmt::Debug for LookupHost { iterator and returning socket \ addresses", issue = "27705")] -#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")] +#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] #[allow(deprecated)] pub fn lookup_host(host: &str) -> io::Result { net_imp::lookup_host(host).map(LookupHost) -- cgit 1.4.1-3-g733a5 From 831ff775703eb5126f741fc3be1cf829ec060011 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Thu, 25 Jan 2018 15:08:48 -0800 Subject: implement Send for process::Command on unix closes https://github.com/rust-lang/rust/issues/47751 --- src/libstd/sys/unix/process/process_common.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index c53bcdbf8e3..b09fc36dee0 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -87,6 +87,11 @@ pub enum Stdio { Fd(FileDesc), } +// Command is not Send by default due to the Command.argv field containing a raw pointers. However +// it is safe to implement Send, because anyway, these pointers point to memory owned by the +// Command.args field. +unsafe impl Send for Command {} + impl Command { pub fn new(program: &OsStr) -> Command { let mut saw_nul = false; -- cgit 1.4.1-3-g733a5 From 634f8cc06a88eb978c5e52390014740c4bab1e33 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Wed, 15 Nov 2017 18:01:09 +0100 Subject: Print inlined functions on Windows --- src/libstd/sys/cloudabi/backtrace.rs | 1 + src/libstd/sys/redox/backtrace/tracing.rs | 1 + .../sys/unix/backtrace/tracing/backtrace_fn.rs | 1 + src/libstd/sys/unix/backtrace/tracing/gcc_s.rs | 1 + src/libstd/sys/windows/backtrace/mod.rs | 31 ++++++------- src/libstd/sys/windows/backtrace/printing/msvc.rs | 54 ++++++++++++++-------- src/libstd/sys/windows/c.rs | 4 +- src/libstd/sys_common/backtrace.rs | 3 ++ src/test/run-pass/backtrace-debuginfo-aux.rs | 4 +- src/test/run-pass/backtrace-debuginfo.rs | 12 +---- 10 files changed, 62 insertions(+), 50 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs index 33d93179237..1b970187558 100644 --- a/src/libstd/sys/cloudabi/backtrace.rs +++ b/src/libstd/sys/cloudabi/backtrace.rs @@ -77,6 +77,7 @@ extern "C" fn trace_fn( cx.frames[cx.idx] = Frame { symbol_addr: symaddr as *mut u8, exact_position: ip as *mut u8, + inline_context: 0, }; cx.idx += 1; } diff --git a/src/libstd/sys/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs index 0a174b3c3f5..bb70ca36037 100644 --- a/src/libstd/sys/redox/backtrace/tracing.rs +++ b/src/libstd/sys/redox/backtrace/tracing.rs @@ -98,6 +98,7 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, cx.frames[cx.idx] = Frame { symbol_addr: symaddr as *mut u8, exact_position: ip as *mut u8, + inline_context: 0, }; cx.idx += 1; } diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs index 400d39cd4bd..6293eeb4ed6 100644 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs @@ -38,6 +38,7 @@ pub fn unwind_backtrace(frames: &mut [Frame]) *to = Frame { exact_position: *from as *mut u8, symbol_addr: *from as *mut u8, + inline_context: 0, }; } Ok((nb_frames as usize, BacktraceContext)) diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs index 000c08d2e0d..1b92fc0e6ad 100644 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -98,6 +98,7 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, cx.frames[cx.idx] = Frame { symbol_addr: symaddr as *mut u8, exact_position: ip as *mut u8, + inline_context: 0, }; cx.idx += 1; } diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 176891fff23..82498ad4d58 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -56,14 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame]) // Fetch the symbols necessary from dbghelp.dll let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?; + let StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?; // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; let thread = unsafe { c::GetCurrentThread() }; let mut context: c::CONTEXT = unsafe { mem::zeroed() }; unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; + let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; + frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; let image = init_frame(&mut frame, &context); let backtrace_context = BacktraceContext { @@ -79,24 +80,22 @@ pub fn unwind_backtrace(frames: &mut [Frame]) } // And now that we're done with all the setup, do the stack walking! - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. let mut i = 0; unsafe { while i < frames.len() && - StackWalk64(image, process, thread, &mut frame, &mut context, + StackWalkEx(image, process, thread, &mut frame, &mut context, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), - ptr::null_mut()) == c::TRUE + ptr::null_mut(), + 0) == c::TRUE { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || - frame.AddrReturn.Offset == 0 { break } + let addr = (frame.AddrPC.Offset - 1) as *const u8; frames[i] = Frame { - symbol_addr: (addr - 1) as *const u8, - exact_position: (addr - 1) as *const u8, + symbol_addr: addr, + exact_position: addr, + inline_context: frame.InlineFrameContext, }; i += 1; } @@ -111,14 +110,14 @@ type SymInitializeFn = type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; -type StackWalk64Fn = +type StackWalkExFn = unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE, - *mut c::STACKFRAME64, *mut c::CONTEXT, + *mut c::STACKFRAME_EX, *mut c::CONTEXT, *mut c_void, *mut c_void, - *mut c_void, *mut c_void) -> c::BOOL; + *mut c_void, *mut c_void, c::DWORD) -> c::BOOL; #[cfg(target_arch = "x86")] -fn init_frame(frame: &mut c::STACKFRAME64, +fn init_frame(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Eip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; @@ -130,7 +129,7 @@ fn init_frame(frame: &mut c::STACKFRAME64, } #[cfg(target_arch = "x86_64")] -fn init_frame(frame: &mut c::STACKFRAME64, +fn init_frame(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Rip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 5a49b77af8e..967df1c8a2d 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -16,12 +16,12 @@ use sys::c; use sys::backtrace::BacktraceContext; use sys_common::backtrace::Frame; -type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, - *mut c::SYMBOL_INFO) -> c::BOOL; -type SymGetLineFromAddr64Fn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u32, - *mut c::IMAGEHLP_LINE64) -> c::BOOL; +type SymFromInlineContextFn = + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, + *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; +type SymGetLineFromInlineContextFn = + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, + u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL; /// Converts a pointer to symbol to its string value. pub fn resolve_symname(frame: Frame, @@ -29,7 +29,9 @@ pub fn resolve_symname(frame: Frame, context: &BacktraceContext) -> io::Result<()> where F: FnOnce(Option<&str>) -> io::Result<()> { - let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?; + let SymFromInlineContext = sym!(&context.dbghelp, + "SymFromInlineContext", + SymFromInlineContextFn)?; unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); @@ -40,12 +42,22 @@ pub fn resolve_symname(frame: Frame, info.SizeOfStruct = 88; let mut displacement = 0u64; - let ret = SymFromAddr(context.handle, - frame.symbol_addr as u64, - &mut displacement, - &mut info); - - let symname = if ret == c::TRUE { + let ret = SymFromInlineContext(context.handle, + frame.symbol_addr as u64, + frame.inline_context, + &mut displacement, + &mut info); + let valid_range = if ret == c::TRUE && + frame.symbol_addr as usize >= info.Address as usize { + if info.Size != 0 { + (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize + } else { + true + } + } else { + false + }; + let symname = if valid_range { let ptr = info.Name.as_ptr() as *const c_char; CStr::from_ptr(ptr).to_str().ok() } else { @@ -61,19 +73,21 @@ pub fn foreach_symbol_fileline(frame: Frame, -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()> { - let SymGetLineFromAddr64 = sym!(&context.dbghelp, - "SymGetLineFromAddr64", - SymGetLineFromAddr64Fn)?; + let SymGetLineFromInlineContext = sym!(&context.dbghelp, + "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn)?; unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::() as u32; let mut displacement = 0u32; - let ret = SymGetLineFromAddr64(context.handle, - frame.exact_position as u64, - &mut displacement, - &mut line); + let ret = SymGetLineFromInlineContext(context.handle, + frame.exact_position as u64, + frame.inline_context, + 0, + &mut displacement, + &mut line); if ret == c::TRUE { let name = CStr::from_ptr(line.Filename).to_bytes(); f(name, line.LineNumber as u32)?; diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 66b44f1402f..6d929f21365 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -619,7 +619,7 @@ pub struct ADDRESS64 { #[repr(C)] #[cfg(feature = "backtrace")] -pub struct STACKFRAME64 { +pub struct STACKFRAME_EX { pub AddrPC: ADDRESS64, pub AddrReturn: ADDRESS64, pub AddrFrame: ADDRESS64, @@ -631,6 +631,8 @@ pub struct STACKFRAME64 { pub Virtual: BOOL, pub Reserved: [u64; 3], pub KdHelp: KDHELP64, + pub StackFrameSize: DWORD, + pub InlineFrameContext: DWORD, } #[repr(C)] diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 36cbce2df75..a364a0392b3 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -41,6 +41,8 @@ pub struct Frame { pub exact_position: *const u8, /// Address of the enclosing function. pub symbol_addr: *const u8, + /// Which inlined function is this frame referring to + pub inline_context: u32, } /// Max number of frames to print. @@ -64,6 +66,7 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { let mut frames = [Frame { exact_position: ptr::null(), symbol_addr: ptr::null(), + inline_context: 0, }; MAX_NB_FRAMES]; let (nb_frames, context) = unwind_backtrace(&mut frames)?; let (skipped_before, skipped_after) = diff --git a/src/test/run-pass/backtrace-debuginfo-aux.rs b/src/test/run-pass/backtrace-debuginfo-aux.rs index 1236acf3511..cb7ef7e3006 100644 --- a/src/test/run-pass/backtrace-debuginfo-aux.rs +++ b/src/test/run-pass/backtrace-debuginfo-aux.rs @@ -15,9 +15,7 @@ pub fn callback(f: F) where F: FnOnce((&'static str, u32)) { f((file!(), line!())) } -// LLVM does not yet output the required debug info to support showing inlined -// function calls in backtraces when targeting MSVC, so disable inlining in -// this case. +// We emit the wrong location for the caller here when inlined on MSVC #[cfg_attr(not(target_env = "msvc"), inline(always))] #[cfg_attr(target_env = "msvc", inline(never))] pub fn callback_inlined(f: F) where F: FnOnce((&'static str, u32)) { diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 2f1c5c0574a..e8b5f3490e5 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -62,10 +62,7 @@ type Pos = (&'static str, u32); // this goes to stdout and each line has to be occurred // in the following backtrace to stderr with a correct order. fn dump_filelines(filelines: &[Pos]) { - // Skip top frame for MSVC, because it sees the macro rather than - // the containing function. - let skip = if cfg!(target_env = "msvc") {1} else {0}; - for &(file, line) in filelines.iter().rev().skip(skip) { + for &(file, line) in filelines.iter().rev() { // extract a basename let basename = file.split(&['/', '\\'][..]).last().unwrap(); println!("{}:{}", basename, line); @@ -84,9 +81,7 @@ fn inner(counter: &mut i32, main_pos: Pos, outer_pos: Pos) { }); } -// LLVM does not yet output the required debug info to support showing inlined -// function calls in backtraces when targeting MSVC, so disable inlining in -// this case. +// We emit the wrong location for the caller here when inlined on MSVC #[cfg_attr(not(target_env = "msvc"), inline(always))] #[cfg_attr(target_env = "msvc", inline(never))] fn inner_inlined(counter: &mut i32, main_pos: Pos, outer_pos: Pos) { @@ -137,9 +132,6 @@ fn run_test(me: &str) { use std::str; use std::process::Command; - let mut template = Command::new(me); - template.env("RUST_BACKTRACE", "full"); - let mut i = 0; loop { let out = Command::new(me) -- cgit 1.4.1-3-g733a5 From 9e6ed17c4f5befef64fa9e8a1d2b2f155c345cac Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Fri, 26 Jan 2018 07:22:43 -0800 Subject: make Command.argv Send on unix platforms Implementing Send for a specific field rather than the whole struct is safer: if a field is changed/modified and becomes non-Send, we can catch it. --- src/libstd/sys/unix/process/process_common.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index b09fc36dee0..7e057401fab 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -45,7 +45,7 @@ pub struct Command { // other keys. program: CString, args: Vec, - argv: Vec<*const c_char>, + argv: Argv, env: CommandEnv, cwd: Option, @@ -58,6 +58,12 @@ pub struct Command { stderr: Option, } +// Create a new type for argv, so that we can make it `Send` +struct Argv(Vec<*const c_char>); + +// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args` +unsafe impl Send for Argv {} + // passed back to std::process with the pipes connected to the child, if any // were requested pub struct StdioPipes { @@ -87,17 +93,12 @@ pub enum Stdio { Fd(FileDesc), } -// Command is not Send by default due to the Command.argv field containing a raw pointers. However -// it is safe to implement Send, because anyway, these pointers point to memory owned by the -// Command.args field. -unsafe impl Send for Command {} - impl Command { pub fn new(program: &OsStr) -> Command { let mut saw_nul = false; let program = os2c(program, &mut saw_nul); Command { - argv: vec![program.as_ptr(), ptr::null()], + argv: Argv(vec![program.as_ptr(), ptr::null()]), program, args: Vec::new(), env: Default::default(), @@ -116,8 +117,8 @@ impl Command { // Overwrite the trailing NULL pointer in `argv` and then add a new null // pointer. let arg = os2c(arg, &mut self.saw_nul); - self.argv[self.args.len() + 1] = arg.as_ptr(); - self.argv.push(ptr::null()); + self.argv.0[self.args.len() + 1] = arg.as_ptr(); + self.argv.0.push(ptr::null()); // Also make sure we keep track of the owned value to schedule a // destructor for this memory. @@ -138,7 +139,7 @@ impl Command { self.saw_nul } pub fn get_argv(&self) -> &Vec<*const c_char> { - &self.argv + &self.argv.0 } #[allow(dead_code)] -- cgit 1.4.1-3-g733a5 From 077d3434aa8a2a3064afcc1c9406a49d0acf0a8d Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Fri, 26 Jan 2018 07:33:58 -0800 Subject: add test checking that process::Command is Send --- src/libstd/process.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 5c66ac6ddde..9b2f815b713 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1843,4 +1843,10 @@ mod tests { } assert!(events > 0); } + + #[test] + fn test_command_implements_send() { + fn take_send_type(_: T) {} + take_send_type(Command::new("")) + } } -- cgit 1.4.1-3-g733a5 From 6c86da288a6b658a2adb2c3de5dced871dc6826b Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 27 Jan 2018 17:54:01 +0100 Subject: Make wording around 0-cost casts more precise --- src/libstd/ffi/c_str.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index a19fe825f21..e91d3a32a50 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -1026,9 +1026,9 @@ impl CStr { /// The returned slice will **not** contain the trailing nul terminator that this C /// string has. /// - /// > **Note**: This method is currently implemented as a 0-cost cast, but - /// > it is planned to alter its definition in the future to perform the - /// > length calculation whenever this method is called. + /// > **Note**: This method is currently implemented as a constant-time + /// > cast, but it is planned to alter its definition in the future to + /// > perform the length calculation whenever this method is called. /// /// # Examples /// @@ -1077,9 +1077,9 @@ impl CStr { /// it will return an error with details of where UTF-8 validation failed. /// /// > **Note**: This method is currently implemented to check for validity - /// > after a 0-cost cast, but it is planned to alter its definition in the - /// > future to perform the length calculation in addition to the UTF-8 - /// > check whenever this method is called. + /// > after a constant-time cast, but it is planned to alter its definition + /// > in the future to perform the length calculation in addition to the + /// > UTF-8 check whenever this method is called. /// /// [`&str`]: ../primitive.str.html /// @@ -1110,9 +1110,9 @@ impl CStr { /// with the result. /// /// > **Note**: This method is currently implemented to check for validity - /// > after a 0-cost cast, but it is planned to alter its definition in the - /// > future to perform the length calculation in addition to the UTF-8 - /// > check whenever this method is called. + /// > after a constant-time cast, but it is planned to alter its definition + /// > in the future to perform the length calculation in addition to the + /// > UTF-8 check whenever this method is called. /// /// [`Cow`]: ../borrow/enum.Cow.html /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed -- cgit 1.4.1-3-g733a5 From 7b4cbbd12d88c8e64d9c7aa1e326c7c78f2a7ed9 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 28 Jan 2018 21:50:01 -0500 Subject: Document that `Index` ops can panic on `HashMap` & `BTreeMap`. Fixes https://github.com/rust-lang/rust/issues/47011. --- src/liballoc/btree/map.rs | 5 +++++ src/libstd/collections/hash/map.rs | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index b114dc640fb..b320bed5432 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1748,6 +1748,11 @@ impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap { type Output = V; + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `BTreeMap`. #[inline] fn index(&self, key: &Q) -> &V { self.get(key).expect("no entry found for key") diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index b01420f36a0..82a687ae5e4 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1384,9 +1384,14 @@ impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap { type Output = V; + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. #[inline] - fn index(&self, index: &Q) -> &V { - self.get(index).expect("no entry found for key") + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") } } -- cgit 1.4.1-3-g733a5 From 1a043533f504145fa51beeb6c94765e6865031ee Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Fri, 22 Dec 2017 21:43:09 -0500 Subject: Document std::os::raw. --- src/libstd/lib.rs | 1 + src/libstd/os/raw.rs | 107 --------------------------------- src/libstd/os/raw/char.md | 11 ++++ src/libstd/os/raw/double.md | 6 ++ src/libstd/os/raw/float.md | 5 ++ src/libstd/os/raw/int.md | 6 ++ src/libstd/os/raw/long.md | 8 +++ src/libstd/os/raw/longlong.md | 6 ++ src/libstd/os/raw/mod.rs | 131 +++++++++++++++++++++++++++++++++++++++++ src/libstd/os/raw/schar.md | 6 ++ src/libstd/os/raw/short.md | 6 ++ src/libstd/os/raw/uchar.md | 6 ++ src/libstd/os/raw/uint.md | 6 ++ src/libstd/os/raw/ulong.md | 8 +++ src/libstd/os/raw/ulonglong.md | 6 ++ src/libstd/os/raw/ushort.md | 6 ++ 16 files changed, 218 insertions(+), 107 deletions(-) delete mode 100644 src/libstd/os/raw.rs create mode 100644 src/libstd/os/raw/char.md create mode 100644 src/libstd/os/raw/double.md create mode 100644 src/libstd/os/raw/float.md create mode 100644 src/libstd/os/raw/int.md create mode 100644 src/libstd/os/raw/long.md create mode 100644 src/libstd/os/raw/longlong.md create mode 100644 src/libstd/os/raw/mod.rs create mode 100644 src/libstd/os/raw/schar.md create mode 100644 src/libstd/os/raw/short.md create mode 100644 src/libstd/os/raw/uchar.md create mode 100644 src/libstd/os/raw/uint.md create mode 100644 src/libstd/os/raw/ulong.md create mode 100644 src/libstd/os/raw/ulonglong.md create mode 100644 src/libstd/os/raw/ushort.md (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a8049e676b3..642fa8775a4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -260,6 +260,7 @@ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] +#![feature(external_doc)] #![feature(fs_read_write)] #![feature(fixed_size_array)] #![feature(float_from_str_radix)] diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs deleted file mode 100644 index 279caf8053a..00000000000 --- a/src/libstd/os/raw.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Raw OS-specific types for the current platform/architecture - -#![stable(feature = "raw_os", since = "1.1.0")] - -use fmt; - -#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x")), - all(target_os = "android", any(target_arch = "aarch64", - target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all(target_os = "openbsd", target_arch = "aarch64"), - all(target_os = "fuchsia", target_arch = "aarch64")))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; -#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x")), - all(target_os = "android", any(target_arch = "aarch64", - target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all(target_os = "openbsd", target_arch = "aarch64"), - all(target_os = "fuchsia", target_arch = "aarch64"))))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32; -#[cfg(any(target_pointer_width = "32", windows))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32; -#[cfg(any(target_pointer_width = "32", windows))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32; -#[cfg(all(target_pointer_width = "64", not(windows)))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64; -#[cfg(all(target_pointer_width = "64", not(windows)))] -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32; -#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64; - -/// Type used to construct void pointers for use with C. -/// -/// This type is only useful as a pointer target. Do not use it as a -/// return type for FFI functions which have the `void` return type in -/// C. Use the unit type `()` or omit the return type instead. -// NB: For LLVM to recognize the void pointer type and by extension -// functions like malloc(), we need to have it represented as i8* in -// LLVM bitcode. The enum used here ensures this and prevents misuse -// of the "raw" type by only having private variants.. We need two -// variants, because the compiler complains about the repr attribute -// otherwise. -#[repr(u8)] -#[stable(feature = "raw_os", since = "1.1.0")] -pub enum c_void { - #[unstable(feature = "c_void_variant", reason = "should not have to exist", - issue = "0")] - #[doc(hidden)] __variant1, - #[unstable(feature = "c_void_variant", reason = "should not have to exist", - issue = "0")] - #[doc(hidden)] __variant2, -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for c_void { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("c_void") - } -} - -#[cfg(test)] -#[allow(unused_imports)] -mod tests { - use any::TypeId; - use libc; - use mem; - - macro_rules! ok { - ($($t:ident)*) => {$( - assert!(TypeId::of::() == TypeId::of::(), - "{} is wrong", stringify!($t)); - )*} - } - - #[test] - fn same() { - use os::raw; - ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong - c_longlong c_ulonglong c_float c_double); - } -} diff --git a/src/libstd/os/raw/char.md b/src/libstd/os/raw/char.md new file mode 100644 index 00000000000..fb47dff187e --- /dev/null +++ b/src/libstd/os/raw/char.md @@ -0,0 +1,11 @@ +Equivalent to C's `char` type. + +[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. In practice, this type will always be either [`i8`] or [`u8`], but you're technically not supposed to rely on this behaviour, as the standard only defines a char as being at least eight bits long. + +C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with a zero. See [`CStr`] for more information. + +[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types +[Rust's `char` type]: ../../primitive.char.html +[`CStr`]: ../../ffi/struct.CStr.html +[`i8`]: ../../primitive.i8.html +[`u8`]: ../../primitive.u8.html diff --git a/src/libstd/os/raw/double.md b/src/libstd/os/raw/double.md new file mode 100644 index 00000000000..5ac09ee284c --- /dev/null +++ b/src/libstd/os/raw/double.md @@ -0,0 +1,6 @@ +Equivalent to C's `double` type. + +This type will almost always be [`f64`], however, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`]. + +[`float`]: type.c_float.html +[`f64`]: ../../primitive.f64.html diff --git a/src/libstd/os/raw/float.md b/src/libstd/os/raw/float.md new file mode 100644 index 00000000000..20ba8645055 --- /dev/null +++ b/src/libstd/os/raw/float.md @@ -0,0 +1,5 @@ +Equivalent to C's `float` type. + +This type will almost always be [`f32`], however, the standard technically only guarantees that it be a floating-point number. + +[`f32`]: ../../primitive.f32.html diff --git a/src/libstd/os/raw/int.md b/src/libstd/os/raw/int.md new file mode 100644 index 00000000000..efe7786099a --- /dev/null +++ b/src/libstd/os/raw/int.md @@ -0,0 +1,6 @@ +Equivalent to C's `signed int` (`int`) type. + +This type will almost always be [`i32`], however, the standard technically only requires that it be at least the size of a [`short`]. + +[`short`]: type.c_short.html +[`i32`]: ../../primitive.i32.html diff --git a/src/libstd/os/raw/long.md b/src/libstd/os/raw/long.md new file mode 100644 index 00000000000..c281e017336 --- /dev/null +++ b/src/libstd/os/raw/long.md @@ -0,0 +1,8 @@ +Equivalent to C's `signed long` (`long`) type. + +This type will usually be [`i64`], but is sometimes [`i32`] \(i.e. [`isize`]\) on 32-bit systems. Technically, the standard only requires that it be at least 32 bits, or at least the size of an [`int`]. + +[`int`]: type.c_int.html +[`i32`]: ../../primitive.i32.html +[`i64`]: ../../primitive.i64.html +[`isize`]: ../../primitive.isize.html diff --git a/src/libstd/os/raw/longlong.md b/src/libstd/os/raw/longlong.md new file mode 100644 index 00000000000..6594fcd564c --- /dev/null +++ b/src/libstd/os/raw/longlong.md @@ -0,0 +1,6 @@ +Equivalent to C's `signed long long` (`long long`) type. + +This type will almost always be [`i64`], however, the standard technically only requires that it be at least 64 bits, or at least the size of an [`long`]. + +[`long`]: type.c_int.html +[`i64`]: ../../primitive.i64.html diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs new file mode 100644 index 00000000000..e96ba045ce7 --- /dev/null +++ b/src/libstd/os/raw/mod.rs @@ -0,0 +1,131 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Platform-specific types, as defined by C. +//! +//! Code that interacts via FFI will almost certainly be using the +//! base types provided by C, which aren't nearly as nicely defined +//! as Rust's primitive types. This module provides types which will +//! match those defined by C, so that code that interacts with C will +//! refer to the correct types. + +#![stable(feature = "raw_os", since = "1.1.0")] + +use fmt; + +#[doc(include = "os/raw/char.md")] +#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), + all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "openbsd", target_arch = "aarch64"), + all(target_os = "fuchsia", target_arch = "aarch64")))] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; +#[doc(include = "os/raw/char.md")] +#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x")), + all(target_os = "android", any(target_arch = "aarch64", + target_arch = "arm")), + all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "openbsd", target_arch = "aarch64"), + all(target_os = "fuchsia", target_arch = "aarch64"))))] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; +#[doc(include = "os/raw/schar.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; +#[doc(include = "os/raw/uchar.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; +#[doc(include = "os/raw/short.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16; +#[doc(include = "os/raw/ushort.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16; +#[doc(include = "os/raw/int.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32; +#[doc(include = "os/raw/uint.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32; +#[doc(include = "os/raw/long.md")] +#[cfg(any(target_pointer_width = "32", windows))] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32; +#[doc(include = "os/raw/ulong.md")] +#[cfg(any(target_pointer_width = "32", windows))] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32; +#[doc(include = "os/raw/long.md")] +#[cfg(all(target_pointer_width = "64", not(windows)))] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64; +#[doc(include = "os/raw/ulong.md")] +#[cfg(all(target_pointer_width = "64", not(windows)))] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64; +#[doc(include = "os/raw/longlong.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64; +#[doc(include = "os/raw/ulonglong.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64; +#[doc(include = "os/raw/float.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32; +#[doc(include = "os/raw/double.md")] +#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64; + +/// Equivalent to C's `void` type when used as a [pointer]. +/// +/// In essence, `*const c_void` is equivalent to C's `const void*` +/// and `*mut c_void` is equivalent to C's `void*`. That said, this is +/// *not* the same as C's `void` return type, which is Rust's `()` type. +/// +/// [pointer]: ../primitive.pointer.html +// NB: For LLVM to recognize the void pointer type and by extension +// functions like malloc(), we need to have it represented as i8* in +// LLVM bitcode. The enum used here ensures this and prevents misuse +// of the "raw" type by only having private variants.. We need two +// variants, because the compiler complains about the repr attribute +// otherwise. +#[repr(u8)] +#[stable(feature = "raw_os", since = "1.1.0")] +pub enum c_void { + #[unstable(feature = "c_void_variant", reason = "should not have to exist", + issue = "0")] + #[doc(hidden)] __variant1, + #[unstable(feature = "c_void_variant", reason = "should not have to exist", + issue = "0")] + #[doc(hidden)] __variant2, +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for c_void { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("c_void") + } +} + +#[cfg(test)] +#[allow(unused_imports)] +mod tests { + use any::TypeId; + use libc; + use mem; + + macro_rules! ok { + ($($t:ident)*) => {$( + assert!(TypeId::of::() == TypeId::of::(), + "{} is wrong", stringify!($t)); + )*} + } + + #[test] + fn same() { + use os::raw; + ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong + c_longlong c_ulonglong c_float c_double); + } +} diff --git a/src/libstd/os/raw/schar.md b/src/libstd/os/raw/schar.md new file mode 100644 index 00000000000..42a403ef5d7 --- /dev/null +++ b/src/libstd/os/raw/schar.md @@ -0,0 +1,6 @@ +Equivalent to C's `signed char` type. + +This type will almost always be [`i8`], but its size is technically equal to the size of a C [`char`], which isn't very clear-cut. + +[`char`]: type.c_char.html +[`i8`]: ../../primitive.i8.html diff --git a/src/libstd/os/raw/short.md b/src/libstd/os/raw/short.md new file mode 100644 index 00000000000..86a8495eae2 --- /dev/null +++ b/src/libstd/os/raw/short.md @@ -0,0 +1,6 @@ +Equivalent to C's `signed short` (`short`) type. + +This type will almost always be [`i16`], however, the standard technically only requires that it be at least 16 bits, or at least the size of a C [`char`]. + +[`char`]: type.c_char.html +[`i16`]: ../../primitive.i16.html diff --git a/src/libstd/os/raw/uchar.md b/src/libstd/os/raw/uchar.md new file mode 100644 index 00000000000..a5b74170229 --- /dev/null +++ b/src/libstd/os/raw/uchar.md @@ -0,0 +1,6 @@ +Equivalent to C's `unsigned char` type. + +This type will almost always be [`u8`], but its size is technically equal to the size of a C [`char`], which isn't very clear-cut. + +[`char`]: type.c_char.html +[`u8`]: ../../primitive.u8.html diff --git a/src/libstd/os/raw/uint.md b/src/libstd/os/raw/uint.md new file mode 100644 index 00000000000..ec4714a9ab4 --- /dev/null +++ b/src/libstd/os/raw/uint.md @@ -0,0 +1,6 @@ +Equivalent to C's `unsigned int` type. + +This type will almost always be [`u32`], however, the standard technically on requires that it be the same size as an [`int`], which isn't very clear-cut. + +[`int`]: type.c_int.html +[`u32`]: ../../primitive.u32.html diff --git a/src/libstd/os/raw/ulong.md b/src/libstd/os/raw/ulong.md new file mode 100644 index 00000000000..3cdbc6f59bf --- /dev/null +++ b/src/libstd/os/raw/ulong.md @@ -0,0 +1,8 @@ +Equivalent to C's `unsigned long` type. + +This type will usually be [`u64`], but is sometimes [`u32`] \(i.e. [`usize`]\) on 32-bit systems. Technically, the standard only requires that it be the same size as a [`long`], which isn't very clear-cut. + +[`long`]: type.c_long.html +[`u32`]: ../../primitive.u32.html +[`u64`]: ../../primitive.u64.html +[`usize`]: ../../primitive.usize.html diff --git a/src/libstd/os/raw/ulonglong.md b/src/libstd/os/raw/ulonglong.md new file mode 100644 index 00000000000..9f5ff74f261 --- /dev/null +++ b/src/libstd/os/raw/ulonglong.md @@ -0,0 +1,6 @@ +Equivalent to C's `unsigned long long` type. + +This type will almost always be [`u64`], however, the standard technically only requires that it be the same size as a [`long long`], which isn't very clear-cut. + +[`long long`]: type.c_longlong.html +[`u64`]: ../../primitive.u64.html diff --git a/src/libstd/os/raw/ushort.md b/src/libstd/os/raw/ushort.md new file mode 100644 index 00000000000..6dea582fda2 --- /dev/null +++ b/src/libstd/os/raw/ushort.md @@ -0,0 +1,6 @@ +Equivalent to C's `unsigned short` type. + +This type will almost always be [`u16`], however, the standard technically only requires that it be the same size as a [`short`], which isn't very clear-cut. + +[`short`]: type.c_short.html +[`u16`]: ../../primitive.u16.html -- cgit 1.4.1-3-g733a5 From 853fa5873c91ad1d01e69e7cbdb758001a31e9c1 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sat, 23 Dec 2017 17:29:51 -0500 Subject: Revisions suggested in comments --- src/libstd/os/raw/char.md | 2 +- src/libstd/os/raw/long.md | 3 +-- src/libstd/os/raw/mod.rs | 2 +- src/libstd/os/raw/ulong.md | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/os/raw/char.md b/src/libstd/os/raw/char.md index fb47dff187e..6816e519d1a 100644 --- a/src/libstd/os/raw/char.md +++ b/src/libstd/os/raw/char.md @@ -2,7 +2,7 @@ Equivalent to C's `char` type. [C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. In practice, this type will always be either [`i8`] or [`u8`], but you're technically not supposed to rely on this behaviour, as the standard only defines a char as being at least eight bits long. -C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with a zero. See [`CStr`] for more information. +C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. [C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types [Rust's `char` type]: ../../primitive.char.html diff --git a/src/libstd/os/raw/long.md b/src/libstd/os/raw/long.md index c281e017336..5a2e2331c0a 100644 --- a/src/libstd/os/raw/long.md +++ b/src/libstd/os/raw/long.md @@ -1,8 +1,7 @@ Equivalent to C's `signed long` (`long`) type. -This type will usually be [`i64`], but is sometimes [`i32`] \(i.e. [`isize`]\) on 32-bit systems. Technically, the standard only requires that it be at least 32 bits, or at least the size of an [`int`]. +This type will usually be [`i64`], but is sometimes [`i32`]. Technically, the standard only requires that it be at least 32 bits, or at least the size of an [`int`]. [`int`]: type.c_int.html [`i32`]: ../../primitive.i32.html [`i64`]: ../../primitive.i64.html -[`isize`]: ../../primitive.isize.html diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index e96ba045ce7..710976ed8e0 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -83,7 +83,7 @@ use fmt; /// and `*mut c_void` is equivalent to C's `void*`. That said, this is /// *not* the same as C's `void` return type, which is Rust's `()` type. /// -/// [pointer]: ../primitive.pointer.html +/// [pointer]: ../../primitive.pointer.html // NB: For LLVM to recognize the void pointer type and by extension // functions like malloc(), we need to have it represented as i8* in // LLVM bitcode. The enum used here ensures this and prevents misuse diff --git a/src/libstd/os/raw/ulong.md b/src/libstd/os/raw/ulong.md index 3cdbc6f59bf..919de171a39 100644 --- a/src/libstd/os/raw/ulong.md +++ b/src/libstd/os/raw/ulong.md @@ -1,8 +1,7 @@ Equivalent to C's `unsigned long` type. -This type will usually be [`u64`], but is sometimes [`u32`] \(i.e. [`usize`]\) on 32-bit systems. Technically, the standard only requires that it be the same size as a [`long`], which isn't very clear-cut. +This type will usually be [`u64`], but is sometimes [`u32`]. Technically, the standard only requires that it be the same size as a [`long`], which isn't very clear-cut. [`long`]: type.c_long.html [`u32`]: ../../primitive.u32.html [`u64`]: ../../primitive.u64.html -[`usize`]: ../../primitive.usize.html -- cgit 1.4.1-3-g733a5 From 2cab06855a9b325c527ab08be4660c4353816833 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Mon, 29 Jan 2018 18:13:18 -0500 Subject: Reworded to avoid fuzziness, mention ! in c_void docs. --- src/libstd/os/raw/char.md | 2 +- src/libstd/os/raw/double.md | 3 ++- src/libstd/os/raw/float.md | 3 ++- src/libstd/os/raw/int.md | 3 ++- src/libstd/os/raw/long.md | 2 +- src/libstd/os/raw/longlong.md | 3 ++- src/libstd/os/raw/mod.rs | 4 ++++ src/libstd/os/raw/schar.md | 2 +- src/libstd/os/raw/short.md | 2 +- src/libstd/os/raw/uchar.md | 2 +- src/libstd/os/raw/uint.md | 3 ++- src/libstd/os/raw/ulong.md | 2 +- src/libstd/os/raw/ulonglong.md | 3 ++- src/libstd/os/raw/ushort.md | 2 +- 14 files changed, 23 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/os/raw/char.md b/src/libstd/os/raw/char.md index 6816e519d1a..9a55767d965 100644 --- a/src/libstd/os/raw/char.md +++ b/src/libstd/os/raw/char.md @@ -1,6 +1,6 @@ Equivalent to C's `char` type. -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. In practice, this type will always be either [`i8`] or [`u8`], but you're technically not supposed to rely on this behaviour, as the standard only defines a char as being at least eight bits long. +[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long. C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. diff --git a/src/libstd/os/raw/double.md b/src/libstd/os/raw/double.md index 5ac09ee284c..6818dada317 100644 --- a/src/libstd/os/raw/double.md +++ b/src/libstd/os/raw/double.md @@ -1,6 +1,7 @@ Equivalent to C's `double` type. -This type will almost always be [`f64`], however, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`]. +This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. +[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 [`float`]: type.c_float.html [`f64`]: ../../primitive.f64.html diff --git a/src/libstd/os/raw/float.md b/src/libstd/os/raw/float.md index 20ba8645055..57d1071d0da 100644 --- a/src/libstd/os/raw/float.md +++ b/src/libstd/os/raw/float.md @@ -1,5 +1,6 @@ Equivalent to C's `float` type. -This type will almost always be [`f32`], however, the standard technically only guarantees that it be a floating-point number. +This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. +[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 [`f32`]: ../../primitive.f32.html diff --git a/src/libstd/os/raw/int.md b/src/libstd/os/raw/int.md index efe7786099a..a0d25fd21d8 100644 --- a/src/libstd/os/raw/int.md +++ b/src/libstd/os/raw/int.md @@ -1,6 +1,7 @@ Equivalent to C's `signed int` (`int`) type. -This type will almost always be [`i32`], however, the standard technically only requires that it be at least the size of a [`short`]. +This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example. [`short`]: type.c_short.html [`i32`]: ../../primitive.i32.html +[`i16`]: ../../primitive.i16.html diff --git a/src/libstd/os/raw/long.md b/src/libstd/os/raw/long.md index 5a2e2331c0a..c620b402819 100644 --- a/src/libstd/os/raw/long.md +++ b/src/libstd/os/raw/long.md @@ -1,6 +1,6 @@ Equivalent to C's `signed long` (`long`) type. -This type will usually be [`i64`], but is sometimes [`i32`]. Technically, the standard only requires that it be at least 32 bits, or at least the size of an [`int`]. +This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`. [`int`]: type.c_int.html [`i32`]: ../../primitive.i32.html diff --git a/src/libstd/os/raw/longlong.md b/src/libstd/os/raw/longlong.md index 6594fcd564c..ab3d6436568 100644 --- a/src/libstd/os/raw/longlong.md +++ b/src/libstd/os/raw/longlong.md @@ -1,6 +1,7 @@ Equivalent to C's `signed long long` (`long long`) type. -This type will almost always be [`i64`], however, the standard technically only requires that it be at least 64 bits, or at least the size of an [`long`]. +This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type. [`long`]: type.c_int.html [`i64`]: ../../primitive.i64.html +[`i128`]: ../../primitive.i128.html diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index 710976ed8e0..d5eeb5252f0 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -83,6 +83,10 @@ use fmt; /// and `*mut c_void` is equivalent to C's `void*`. That said, this is /// *not* the same as C's `void` return type, which is Rust's `()` type. /// +/// Ideally, this type would be equivalent to [`!`], but currently it may +/// be more ideal to use `c_void` for FFI purposes. +/// +/// [`!`]: ../../primitive.never.html /// [pointer]: ../../primitive.pointer.html // NB: For LLVM to recognize the void pointer type and by extension // functions like malloc(), we need to have it represented as i8* in diff --git a/src/libstd/os/raw/schar.md b/src/libstd/os/raw/schar.md index 42a403ef5d7..6aa8b1211d8 100644 --- a/src/libstd/os/raw/schar.md +++ b/src/libstd/os/raw/schar.md @@ -1,6 +1,6 @@ Equivalent to C's `signed char` type. -This type will almost always be [`i8`], but its size is technically equal to the size of a C [`char`], which isn't very clear-cut. +This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`]. [`char`]: type.c_char.html [`i8`]: ../../primitive.i8.html diff --git a/src/libstd/os/raw/short.md b/src/libstd/os/raw/short.md index 86a8495eae2..be92c6c106d 100644 --- a/src/libstd/os/raw/short.md +++ b/src/libstd/os/raw/short.md @@ -1,6 +1,6 @@ Equivalent to C's `signed short` (`short`) type. -This type will almost always be [`i16`], however, the standard technically only requires that it be at least 16 bits, or at least the size of a C [`char`]. +This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example. [`char`]: type.c_char.html [`i16`]: ../../primitive.i16.html diff --git a/src/libstd/os/raw/uchar.md b/src/libstd/os/raw/uchar.md index a5b74170229..b6ca711f869 100644 --- a/src/libstd/os/raw/uchar.md +++ b/src/libstd/os/raw/uchar.md @@ -1,6 +1,6 @@ Equivalent to C's `unsigned char` type. -This type will almost always be [`u8`], but its size is technically equal to the size of a C [`char`], which isn't very clear-cut. +This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`]. [`char`]: type.c_char.html [`u8`]: ../../primitive.u8.html diff --git a/src/libstd/os/raw/uint.md b/src/libstd/os/raw/uint.md index ec4714a9ab4..1e710f804c4 100644 --- a/src/libstd/os/raw/uint.md +++ b/src/libstd/os/raw/uint.md @@ -1,6 +1,7 @@ Equivalent to C's `unsigned int` type. -This type will almost always be [`u32`], however, the standard technically on requires that it be the same size as an [`int`], which isn't very clear-cut. +This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example. [`int`]: type.c_int.html [`u32`]: ../../primitive.u32.html +[`u16`]: ../../primitive.u16.html diff --git a/src/libstd/os/raw/ulong.md b/src/libstd/os/raw/ulong.md index 919de171a39..c350395080e 100644 --- a/src/libstd/os/raw/ulong.md +++ b/src/libstd/os/raw/ulong.md @@ -1,6 +1,6 @@ Equivalent to C's `unsigned long` type. -This type will usually be [`u64`], but is sometimes [`u32`]. Technically, the standard only requires that it be the same size as a [`long`], which isn't very clear-cut. +This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`. [`long`]: type.c_long.html [`u32`]: ../../primitive.u32.html diff --git a/src/libstd/os/raw/ulonglong.md b/src/libstd/os/raw/ulonglong.md index 9f5ff74f261..c41faf74c5c 100644 --- a/src/libstd/os/raw/ulonglong.md +++ b/src/libstd/os/raw/ulonglong.md @@ -1,6 +1,7 @@ Equivalent to C's `unsigned long long` type. -This type will almost always be [`u64`], however, the standard technically only requires that it be the same size as a [`long long`], which isn't very clear-cut. +This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type. [`long long`]: type.c_longlong.html [`u64`]: ../../primitive.u64.html +[`u128`]: ../../primitive.u128.html diff --git a/src/libstd/os/raw/ushort.md b/src/libstd/os/raw/ushort.md index 6dea582fda2..d364abb3c8e 100644 --- a/src/libstd/os/raw/ushort.md +++ b/src/libstd/os/raw/ushort.md @@ -1,6 +1,6 @@ Equivalent to C's `unsigned short` type. -This type will almost always be [`u16`], however, the standard technically only requires that it be the same size as a [`short`], which isn't very clear-cut. +This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`]. [`short`]: type.c_short.html [`u16`]: ../../primitive.u16.html -- cgit 1.4.1-3-g733a5 From aab712cbc8f657f3e87dacd762d23c80e589ac95 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Mon, 11 Dec 2017 13:42:01 -0500 Subject: Move time::Duration to libcore --- src/libcore/lib.rs | 1 + src/libcore/time.rs | 603 ++++++++++++++++++++++++++++++++++++++++++++ src/libstd/time.rs | 565 +++++++++++++++++++++++++++++++++++++++++ src/libstd/time/duration.rs | 590 ------------------------------------------- src/libstd/time/mod.rs | 567 ----------------------------------------- 5 files changed, 1169 insertions(+), 1157 deletions(-) create mode 100644 src/libcore/time.rs create mode 100644 src/libstd/time.rs delete mode 100644 src/libstd/time/duration.rs delete mode 100644 src/libstd/time/mod.rs (limited to 'src/libstd') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index d5190b65863..2e1f925c49a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -168,6 +168,7 @@ pub mod slice; pub mod str; pub mod hash; pub mod fmt; +pub mod time; // note: does not need to be public mod char_private; diff --git a/src/libcore/time.rs b/src/libcore/time.rs new file mode 100644 index 00000000000..1a0208d2f25 --- /dev/null +++ b/src/libcore/time.rs @@ -0,0 +1,603 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![stable(feature = "duration_core", since = "1.24.0")] + +//! Temporal quantification. +//! +//! Example: +//! +//! ``` +//! use std::time::Duration; +//! +//! let five_seconds = Duration::new(5, 0); +//! // both declarations are equivalent +//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); +//! ``` + +use iter::Sum; +use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; + +const NANOS_PER_SEC: u32 = 1_000_000_000; +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; + +/// A `Duration` type to represent a span of time, typically used for system +/// timeouts. +/// +/// Each `Duration` is composed of a whole number of seconds and a fractional part +/// represented in nanoseconds. If the underlying system does not support +/// nanosecond-level precision, APIs binding a system timeout will typically round up +/// the number of nanoseconds. +/// +/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other +/// [`ops`] traits. +/// +/// [`Add`]: ../../std/ops/trait.Add.html +/// [`Sub`]: ../../std/ops/trait.Sub.html +/// [`ops`]: ../../std/ops/index.html +/// +/// # Examples +/// +/// ``` +/// use std::time::Duration; +/// +/// let five_seconds = Duration::new(5, 0); +/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5); +/// +/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5); +/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5); +/// +/// let ten_millis = Duration::from_millis(10); +/// ``` +#[stable(feature = "duration_core", since = "1.24.0")] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] +pub struct Duration { + secs: u64, + nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC +} + +impl Duration { + /// Creates a new `Duration` from the specified number of whole seconds and + /// additional nanoseconds. + /// + /// If the number of nanoseconds is greater than 1 billion (the number of + /// nanoseconds in a second), then it will carry over into the seconds provided. + /// + /// # Panics + /// + /// This constructor will panic if the carry from the nanoseconds overflows + /// the seconds counter. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let five_seconds = Duration::new(5, 0); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub fn new(secs: u64, nanos: u32) -> Duration { + let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) + .expect("overflow in Duration::new"); + let nanos = nanos % NANOS_PER_SEC; + Duration { secs: secs, nanos: nanos } + } + + /// Creates a new `Duration` from the specified number of whole seconds. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::from_secs(5); + /// + /// assert_eq!(5, duration.as_secs()); + /// assert_eq!(0, duration.subsec_nanos()); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub const fn from_secs(secs: u64) -> Duration { + Duration { secs: secs, nanos: 0 } + } + + /// Creates a new `Duration` from the specified number of milliseconds. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::from_millis(2569); + /// + /// assert_eq!(2, duration.as_secs()); + /// assert_eq!(569_000_000, duration.subsec_nanos()); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub const fn from_millis(millis: u64) -> Duration { + Duration { + secs: millis / MILLIS_PER_SEC, + nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI, + } + } + + /// Creates a new `Duration` from the specified number of microseconds. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_from_micros)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_micros(1_000_002); + /// + /// assert_eq!(1, duration.as_secs()); + /// assert_eq!(2000, duration.subsec_nanos()); + /// ``` + #[unstable(feature = "duration_from_micros", issue = "44400")] + #[inline] + pub const fn from_micros(micros: u64) -> Duration { + Duration { + secs: micros / MICROS_PER_SEC, + nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO, + } + } + + /// Creates a new `Duration` from the specified number of nanoseconds. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_extras)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_nanos(1_000_000_123); + /// + /// assert_eq!(1, duration.as_secs()); + /// assert_eq!(123, duration.subsec_nanos()); + /// ``` + #[unstable(feature = "duration_extras", issue = "46507")] + #[inline] + pub const fn from_nanos(nanos: u64) -> Duration { + Duration { + secs: nanos / (NANOS_PER_SEC as u64), + nanos: (nanos % (NANOS_PER_SEC as u64)) as u32, + } + } + + /// Returns the number of _whole_ seconds contained by this `Duration`. + /// + /// The returned value does not include the fractional (nanosecond) part of the + /// duration, which can be obtained using [`subsec_nanos`]. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_secs(), 5); + /// ``` + /// + /// To determine the total number of seconds represented by the `Duration`, + /// use `as_secs` in combination with [`subsec_nanos`]: + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// + /// assert_eq!(5.730023852, + /// duration.as_secs() as f64 + /// + duration.subsec_nanos() as f64 * 1e-9); + /// ``` + /// + /// [`subsec_nanos`]: #method.subsec_nanos + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub fn as_secs(&self) -> u64 { self.secs } + + /// Returns the fractional part of this `Duration`, in milliseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by milliseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is less than one thousand). + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_extras)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_millis(5432); + /// assert_eq!(duration.as_secs(), 5); + /// assert_eq!(duration.subsec_millis(), 432); + /// ``` + #[unstable(feature = "duration_extras", issue = "46507")] + #[inline] + pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } + + /// Returns the fractional part of this `Duration`, in microseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by microseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is less than one million). + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_extras, duration_from_micros)] + /// use std::time::Duration; + /// + /// let duration = Duration::from_micros(1_234_567); + /// assert_eq!(duration.as_secs(), 1); + /// assert_eq!(duration.subsec_micros(), 234_567); + /// ``` + #[unstable(feature = "duration_extras", issue = "46507")] + #[inline] + pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } + + /// Returns the fractional part of this `Duration`, in nanoseconds. + /// + /// This method does **not** return the length of the duration when + /// represented by nanoseconds. The returned number always represents a + /// fractional portion of a second (i.e. it is less than one billion). + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// + /// let duration = Duration::from_millis(5010); + /// assert_eq!(duration.as_secs(), 5); + /// assert_eq!(duration.subsec_nanos(), 10_000_000); + /// ``` + #[stable(feature = "duration", since = "1.3.0")] + #[inline] + pub fn subsec_nanos(&self) -> u32 { self.nanos } + + /// Checked `Duration` addition. Computes `self + other`, returning [`None`] + /// if overflow occurred. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_add(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_add(rhs.secs) { + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + if let Some(new_secs) = secs.checked_add(1) { + secs = new_secs; + } else { + return None; + } + } + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs, + nanos, + }) + } else { + None + } + } + + /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] + /// if the result would be negative or if overflow occurred. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_sub(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { + let nanos = if self.nanos >= rhs.nanos { + self.nanos - rhs.nanos + } else { + if let Some(sub_secs) = secs.checked_sub(1) { + secs = sub_secs; + self.nanos + NANOS_PER_SEC - rhs.nanos + } else { + return None; + } + }; + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } + + /// Checked `Duration` multiplication. Computes `self * other`, returning + /// [`None`] if overflow occurred. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); + /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_mul(self, rhs: u32) -> Option { + // Multiply nanoseconds as u64, because it cannot overflow that way. + let total_nanos = self.nanos as u64 * rhs as u64; + let extra_secs = total_nanos / (NANOS_PER_SEC as u64); + let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; + if let Some(secs) = self.secs + .checked_mul(rhs as u64) + .and_then(|s| s.checked_add(extra_secs)) { + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs, + nanos, + }) + } else { + None + } + } + + /// Checked `Duration` division. Computes `self / other`, returning [`None`] + /// if `other == 0`. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + /// assert_eq!(Duration::new(2, 0).checked_div(0), None); + /// ``` + #[stable(feature = "duration_checked_ops", since = "1.16.0")] + #[inline] + pub fn checked_div(self, rhs: u32) -> Option { + if rhs != 0 { + let secs = self.secs / (rhs as u64); + let carry = self.secs - secs * (rhs as u64); + let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); + let nanos = self.nanos / rhs + (extra_nanos as u32); + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Add for Duration { + type Output = Duration; + + fn add(self, rhs: Duration) -> Duration { + self.checked_add(rhs).expect("overflow when adding durations") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl AddAssign for Duration { + fn add_assign(&mut self, rhs: Duration) { + *self = *self + rhs; + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Sub for Duration { + type Output = Duration; + + fn sub(self, rhs: Duration) -> Duration { + self.checked_sub(rhs).expect("overflow when subtracting durations") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl SubAssign for Duration { + fn sub_assign(&mut self, rhs: Duration) { + *self = *self - rhs; + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Mul for Duration { + type Output = Duration; + + fn mul(self, rhs: u32) -> Duration { + self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl MulAssign for Duration { + fn mul_assign(&mut self, rhs: u32) { + *self = *self * rhs; + } +} + +#[stable(feature = "duration", since = "1.3.0")] +impl Div for Duration { + type Output = Duration; + + fn div(self, rhs: u32) -> Duration { + self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl DivAssign for Duration { + fn div_assign(&mut self, rhs: u32) { + *self = *self / rhs; + } +} + +#[stable(feature = "duration_sum", since = "1.16.0")] +impl Sum for Duration { + fn sum>(iter: I) -> Duration { + iter.fold(Duration::new(0, 0), |a, b| a + b) + } +} + +#[stable(feature = "duration_sum", since = "1.16.0")] +impl<'a> Sum<&'a Duration> for Duration { + fn sum>(iter: I) -> Duration { + iter.fold(Duration::new(0, 0), |a, b| a + *b) + } +} + +#[cfg(test)] +mod tests { + use super::Duration; + + #[test] + fn creation() { + assert!(Duration::from_secs(1) != Duration::from_secs(0)); + assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), + Duration::from_secs(3)); + assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), + Duration::new(4, 10 * 1_000_000)); + assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); + } + + #[test] + fn secs() { + assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::from_secs(1).as_secs(), 1); + assert_eq!(Duration::from_millis(999).as_secs(), 0); + assert_eq!(Duration::from_millis(1001).as_secs(), 1); + } + + #[test] + fn nanos() { + assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); + assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); + assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); + assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); + } + + #[test] + fn add() { + assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), + Duration::new(1, 1)); + } + + #[test] + fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), + Some(Duration::new(0, 1))); + assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1))); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + } + + #[test] + fn sub() { + assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), + Duration::new(0, 1)); + assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), + Duration::new(0, 1)); + assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), + Duration::new(0, 999_999_999)); + } + + #[test] + fn checked_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); + assert_eq!(one_sec.checked_sub(one_nano), + Some(Duration::new(0, 999_999_999))); + assert_eq!(zero.checked_sub(one_nano), None); + assert_eq!(zero.checked_sub(one_sec), None); + } + + #[test] #[should_panic] + fn sub_bad1() { + Duration::new(0, 0) - Duration::new(0, 1); + } + + #[test] #[should_panic] + fn sub_bad2() { + Duration::new(0, 0) - Duration::new(1, 0); + } + + #[test] + fn mul() { + assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001) * 4000, + Duration::new(2000, 4000)); + } + + #[test] + fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), + Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + } + + #[test] + fn div() { + assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); + assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); + assert_eq!(Duration::new(99, 999_999_000) / 100, + Duration::new(0, 999_999_990)); + } + + #[test] + fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); + } +} diff --git a/src/libstd/time.rs b/src/libstd/time.rs new file mode 100644 index 00000000000..12f2a9bb85f --- /dev/null +++ b/src/libstd/time.rs @@ -0,0 +1,565 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Temporal quantification. +//! +//! Example: +//! +//! ``` +//! use std::time::Duration; +//! +//! let five_seconds = Duration::new(5, 0); +//! // both declarations are equivalent +//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); +//! ``` + +#![stable(feature = "time", since = "1.3.0")] + +use error::Error; +use fmt; +use ops::{Add, Sub, AddAssign, SubAssign}; +use sys::time; +use sys_common::FromInner; + +#[stable(feature = "time", since = "1.3.0")] +pub use core::time::Duration; + +/// A measurement of a monotonically nondecreasing clock. +/// Opaque and useful only with `Duration`. +/// +/// Instants are always guaranteed to be no less than any previously measured +/// instant when created, and are often useful for tasks such as measuring +/// benchmarks or timing how long an operation takes. +/// +/// Note, however, that instants are not guaranteed to be **steady**. In other +/// words, each tick of the underlying clock may not be the same length (e.g. +/// some seconds may be longer than others). An instant may jump forwards or +/// experience time dilation (slow down or speed up), but it will never go +/// backwards. +/// +/// Instants are opaque types that can only be compared to one another. There is +/// no method to get "the number of seconds" from an instant. Instead, it only +/// allows measuring the duration between two instants (or comparing two +/// instants). +/// +/// Example: +/// +/// ```no_run +/// use std::time::{Duration, Instant}; +/// use std::thread::sleep; +/// +/// fn main() { +/// let now = Instant::now(); +/// +/// // we sleep for 2 seconds +/// sleep(Duration::new(2, 0)); +/// // it prints '2' +/// println!("{}", now.elapsed().as_secs()); +/// } +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[stable(feature = "time2", since = "1.8.0")] +pub struct Instant(time::Instant); + +/// A measurement of the system clock, useful for talking to +/// external entities like the file system or other processes. +/// +/// Distinct from the [`Instant`] type, this time measurement **is not +/// monotonic**. This means that you can save a file to the file system, then +/// save another file to the file system, **and the second file has a +/// `SystemTime` measurement earlier than the first**. In other words, an +/// operation that happens after another operation in real time may have an +/// earlier `SystemTime`! +/// +/// Consequently, comparing two `SystemTime` instances to learn about the +/// duration between them returns a [`Result`] instead of an infallible [`Duration`] +/// to indicate that this sort of time drift may happen and needs to be handled. +/// +/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`] +/// constant is provided in this module as an anchor in time to learn +/// information about a `SystemTime`. By calculating the duration from this +/// fixed point in time, a `SystemTime` can be converted to a human-readable time, +/// or perhaps some other string representation. +/// +/// [`Instant`]: ../../std/time/struct.Instant.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`Duration`]: ../../std/time/struct.Duration.html +/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html +/// +/// Example: +/// +/// ```no_run +/// use std::time::{Duration, SystemTime}; +/// use std::thread::sleep; +/// +/// fn main() { +/// let now = SystemTime::now(); +/// +/// // we sleep for 2 seconds +/// sleep(Duration::new(2, 0)); +/// match now.elapsed() { +/// Ok(elapsed) => { +/// // it prints '2' +/// println!("{}", elapsed.as_secs()); +/// } +/// Err(e) => { +/// // an error occurred! +/// println!("Error: {:?}", e); +/// } +/// } +/// } +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[stable(feature = "time2", since = "1.8.0")] +pub struct SystemTime(time::SystemTime); + +/// An error returned from the `duration_since` and `elapsed` methods on +/// `SystemTime`, used to learn how far in the opposite direction a system time +/// lies. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread::sleep; +/// use std::time::{Duration, SystemTime}; +/// +/// let sys_time = SystemTime::now(); +/// sleep(Duration::from_secs(1)); +/// let new_sys_time = SystemTime::now(); +/// match sys_time.duration_since(new_sys_time) { +/// Ok(_) => {} +/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), +/// } +/// ``` +#[derive(Clone, Debug)] +#[stable(feature = "time2", since = "1.8.0")] +pub struct SystemTimeError(Duration); + +impl Instant { + /// Returns an instant corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// use std::time::Instant; + /// + /// let now = Instant::now(); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn now() -> Instant { + Instant(time::Instant::now()) + } + + /// Returns the amount of time elapsed from another instant to this one. + /// + /// # Panics + /// + /// This function will panic if `earlier` is later than `self`. + /// + /// # Examples + /// + /// ```no_run + /// use std::time::{Duration, Instant}; + /// use std::thread::sleep; + /// + /// let now = Instant::now(); + /// sleep(Duration::new(1, 0)); + /// let new_now = Instant::now(); + /// println!("{:?}", new_now.duration_since(now)); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn duration_since(&self, earlier: Instant) -> Duration { + self.0.sub_instant(&earlier.0) + } + + /// Returns the amount of time elapsed since this instant was created. + /// + /// # Panics + /// + /// This function may panic if the current time is earlier than this + /// instant, which is something that can happen if an `Instant` is + /// produced synthetically. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, Instant}; + /// + /// let instant = Instant::now(); + /// let three_secs = Duration::from_secs(3); + /// sleep(three_secs); + /// assert!(instant.elapsed() >= three_secs); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn elapsed(&self) -> Duration { + Instant::now() - *self + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Add for Instant { + type Output = Instant; + + fn add(self, other: Duration) -> Instant { + Instant(self.0.add_duration(&other)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl AddAssign for Instant { + fn add_assign(&mut self, other: Duration) { + *self = *self + other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Sub for Instant { + type Output = Instant; + + fn sub(self, other: Duration) -> Instant { + Instant(self.0.sub_duration(&other)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl SubAssign for Instant { + fn sub_assign(&mut self, other: Duration) { + *self = *self - other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Sub for Instant { + type Output = Duration; + + fn sub(self, other: Instant) -> Duration { + self.duration_since(other) + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl fmt::Debug for Instant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl SystemTime { + /// Returns the system time corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// use std::time::SystemTime; + /// + /// let sys_time = SystemTime::now(); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn now() -> SystemTime { + SystemTime(time::SystemTime::now()) + } + + /// Returns the amount of time elapsed from an earlier point in time. + /// + /// This function may fail because measurements taken earlier are not + /// guaranteed to always be before later measurements (due to anomalies such + /// as the system clock being adjusted either forwards or backwards). + /// + /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents + /// the amount of time elapsed from the specified measurement to this one. + /// + /// Returns an [`Err`] if `earlier` is later than `self`, and the error + /// contains how far from `self` the time is. + /// + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ``` + /// use std::time::SystemTime; + /// + /// let sys_time = SystemTime::now(); + /// let difference = sys_time.duration_since(sys_time) + /// .expect("SystemTime::duration_since failed"); + /// println!("{:?}", difference); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn duration_since(&self, earlier: SystemTime) + -> Result { + self.0.sub_time(&earlier.0).map_err(SystemTimeError) + } + + /// Returns the amount of time elapsed since this system time was created. + /// + /// This function may fail as the underlying system clock is susceptible to + /// drift and updates (e.g. the system clock could go backwards), so this + /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is + /// returned where the duration represents the amount of time elapsed from + /// this time measurement to the current time. + /// + /// Returns an [`Err`] if `self` is later than the current system time, and + /// the error contains how far from the current system time `self` is. + /// + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, SystemTime}; + /// + /// let sys_time = SystemTime::now(); + /// let one_sec = Duration::from_secs(1); + /// sleep(one_sec); + /// assert!(sys_time.elapsed().unwrap() >= one_sec); + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn elapsed(&self) -> Result { + SystemTime::now().duration_since(*self) + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Add for SystemTime { + type Output = SystemTime; + + fn add(self, dur: Duration) -> SystemTime { + SystemTime(self.0.add_duration(&dur)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl AddAssign for SystemTime { + fn add_assign(&mut self, other: Duration) { + *self = *self + other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Sub for SystemTime { + type Output = SystemTime; + + fn sub(self, dur: Duration) -> SystemTime { + SystemTime(self.0.sub_duration(&dur)) + } +} + +#[stable(feature = "time_augmented_assignment", since = "1.9.0")] +impl SubAssign for SystemTime { + fn sub_assign(&mut self, other: Duration) { + *self = *self - other; + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl fmt::Debug for SystemTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +/// An anchor in time which can be used to create new `SystemTime` instances or +/// learn about where in time a `SystemTime` lies. +/// +/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with +/// respect to the system clock. Using `duration_since` on an existing +/// [`SystemTime`] instance can tell how far away from this point in time a +/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a +/// [`SystemTime`] instance to represent another fixed point in time. +/// +/// [`SystemTime`]: ../../std/time/struct.SystemTime.html +/// +/// # Examples +/// +/// ```no_run +/// use std::time::{SystemTime, UNIX_EPOCH}; +/// +/// match SystemTime::now().duration_since(UNIX_EPOCH) { +/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), +/// Err(_) => panic!("SystemTime before UNIX EPOCH!"), +/// } +/// ``` +#[stable(feature = "time2", since = "1.8.0")] +pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); + +impl SystemTimeError { + /// Returns the positive duration which represents how far forward the + /// second system time was from the first. + /// + /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`] + /// methods of [`SystemTime`] whenever the second system time represents a point later + /// in time than the `self` of the method call. + /// + /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since + /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed + /// [`SystemTime`]: ../../std/time/struct.SystemTime.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, SystemTime}; + /// + /// let sys_time = SystemTime::now(); + /// sleep(Duration::from_secs(1)); + /// let new_sys_time = SystemTime::now(); + /// match sys_time.duration_since(new_sys_time) { + /// Ok(_) => {} + /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), + /// } + /// ``` + #[stable(feature = "time2", since = "1.8.0")] + pub fn duration(&self) -> Duration { + self.0 + } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl Error for SystemTimeError { + fn description(&self) -> &str { "other time was not earlier than self" } +} + +#[stable(feature = "time2", since = "1.8.0")] +impl fmt::Display for SystemTimeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "second time provided was later than self") + } +} + +impl FromInner for SystemTime { + fn from_inner(time: time::SystemTime) -> SystemTime { + SystemTime(time) + } +} + +#[cfg(test)] +mod tests { + use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; + + macro_rules! assert_almost_eq { + ($a:expr, $b:expr) => ({ + let (a, b) = ($a, $b); + if a != b { + let (a, b) = if a > b {(a, b)} else {(b, a)}; + assert!(a - Duration::new(0, 100) <= b); + } + }) + } + + #[test] + fn instant_monotonic() { + let a = Instant::now(); + let b = Instant::now(); + assert!(b >= a); + } + + #[test] + fn instant_elapsed() { + let a = Instant::now(); + a.elapsed(); + } + + #[test] + fn instant_math() { + let a = Instant::now(); + let b = Instant::now(); + let dur = b.duration_since(a); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + + let second = Duration::new(1, 0); + assert_almost_eq!(a - second + second, a); + } + + #[test] + #[should_panic] + fn instant_duration_panic() { + let a = Instant::now(); + (a - Duration::new(1, 0)).duration_since(a); + } + + #[test] + fn system_time_math() { + let a = SystemTime::now(); + let b = SystemTime::now(); + match b.duration_since(a) { + Ok(dur) if dur == Duration::new(0, 0) => { + assert_almost_eq!(a, b); + } + Ok(dur) => { + assert!(b > a); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + } + Err(dur) => { + let dur = dur.duration(); + assert!(a > b); + assert_almost_eq!(b + dur, a); + assert_almost_eq!(a - dur, b); + } + } + + let second = Duration::new(1, 0); + assert_almost_eq!(a.duration_since(a - second).unwrap(), second); + assert_almost_eq!(a.duration_since(a + second).unwrap_err() + .duration(), second); + + assert_almost_eq!(a - second + second, a); + + // A difference of 80 and 800 years cannot fit inside a 32-bit time_t + if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 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); + assert_eq!(one_second_from_epoch, one_second_from_epoch2); + } + + #[test] + fn system_time_elapsed() { + let a = SystemTime::now(); + drop(a.elapsed()); + } + + #[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(); + assert!(b > a); + assert_eq!(b - a, Duration::new(1, 0)); + + let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; + + // Right now for CI this test is run in an emulator, and apparently the + // aarch64 emulator's sense of time is that we're still living in the + // 70s. + // + // Otherwise let's assume that we're all running computers later than + // 2000. + if !cfg!(target_arch = "aarch64") { + assert!(a > thirty_years); + } + + // let's assume that we're all running computers earlier than 2090. + // Should give us ~70 years to fix this! + let hundred_twenty_years = thirty_years * 4; + assert!(a < hundred_twenty_years); + } +} diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs deleted file mode 100644 index ee444830be4..00000000000 --- a/src/libstd/time/duration.rs +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use iter::Sum; -use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; - -const NANOS_PER_SEC: u32 = 1_000_000_000; -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; - -/// A `Duration` type to represent a span of time, typically used for system -/// timeouts. -/// -/// Each `Duration` is composed of a whole number of seconds and a fractional part -/// represented in nanoseconds. If the underlying system does not support -/// nanosecond-level precision, APIs binding a system timeout will typically round up -/// the number of nanoseconds. -/// -/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other -/// [`ops`] traits. -/// -/// [`Add`]: ../../std/ops/trait.Add.html -/// [`Sub`]: ../../std/ops/trait.Sub.html -/// [`ops`]: ../../std/ops/index.html -/// -/// # Examples -/// -/// ``` -/// use std::time::Duration; -/// -/// let five_seconds = Duration::new(5, 0); -/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5); -/// -/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5); -/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5); -/// -/// let ten_millis = Duration::from_millis(10); -/// ``` -#[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] -pub struct Duration { - secs: u64, - nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC -} - -impl Duration { - /// Creates a new `Duration` from the specified number of whole seconds and - /// additional nanoseconds. - /// - /// If the number of nanoseconds is greater than 1 billion (the number of - /// nanoseconds in a second), then it will carry over into the seconds provided. - /// - /// # Panics - /// - /// This constructor will panic if the carry from the nanoseconds overflows - /// the seconds counter. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let five_seconds = Duration::new(5, 0); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn new(secs: u64, nanos: u32) -> Duration { - let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64) - .expect("overflow in Duration::new"); - let nanos = nanos % NANOS_PER_SEC; - Duration { secs: secs, nanos: nanos } - } - - /// Creates a new `Duration` from the specified number of whole seconds. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_secs(5); - /// - /// assert_eq!(5, duration.as_secs()); - /// assert_eq!(0, duration.subsec_nanos()); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub const fn from_secs(secs: u64) -> Duration { - Duration { secs: secs, nanos: 0 } - } - - /// Creates a new `Duration` from the specified number of milliseconds. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(2569); - /// - /// assert_eq!(2, duration.as_secs()); - /// assert_eq!(569_000_000, duration.subsec_nanos()); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub const fn from_millis(millis: u64) -> Duration { - Duration { - secs: millis / MILLIS_PER_SEC, - nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI, - } - } - - /// Creates a new `Duration` from the specified number of microseconds. - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_from_micros)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_micros(1_000_002); - /// - /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(2000, duration.subsec_nanos()); - /// ``` - #[unstable(feature = "duration_from_micros", issue = "44400")] - #[inline] - pub const fn from_micros(micros: u64) -> Duration { - Duration { - secs: micros / MICROS_PER_SEC, - nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO, - } - } - - /// Creates a new `Duration` from the specified number of nanoseconds. - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_nanos(1_000_000_123); - /// - /// assert_eq!(1, duration.as_secs()); - /// assert_eq!(123, duration.subsec_nanos()); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub const fn from_nanos(nanos: u64) -> Duration { - Duration { - secs: nanos / (NANOS_PER_SEC as u64), - nanos: (nanos % (NANOS_PER_SEC as u64)) as u32, - } - } - - /// Returns the number of _whole_ seconds contained by this `Duration`. - /// - /// The returned value does not include the fractional (nanosecond) part of the - /// duration, which can be obtained using [`subsec_nanos`]. - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::new(5, 730023852); - /// assert_eq!(duration.as_secs(), 5); - /// ``` - /// - /// To determine the total number of seconds represented by the `Duration`, - /// use `as_secs` in combination with [`subsec_nanos`]: - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::new(5, 730023852); - /// - /// assert_eq!(5.730023852, - /// duration.as_secs() as f64 - /// + duration.subsec_nanos() as f64 * 1e-9); - /// ``` - /// - /// [`subsec_nanos`]: #method.subsec_nanos - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn as_secs(&self) -> u64 { self.secs } - - /// Returns the fractional part of this `Duration`, in milliseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by milliseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one thousand). - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(5432); - /// assert_eq!(duration.as_secs(), 5); - /// assert_eq!(duration.subsec_millis(), 432); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } - - /// Returns the fractional part of this `Duration`, in microseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by microseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one million). - /// - /// # Examples - /// - /// ``` - /// #![feature(duration_extras, duration_from_micros)] - /// use std::time::Duration; - /// - /// let duration = Duration::from_micros(1_234_567); - /// assert_eq!(duration.as_secs(), 1); - /// assert_eq!(duration.subsec_micros(), 234_567); - /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] - #[inline] - pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } - - /// Returns the fractional part of this `Duration`, in nanoseconds. - /// - /// This method does **not** return the length of the duration when - /// represented by nanoseconds. The returned number always represents a - /// fractional portion of a second (i.e. it is less than one billion). - /// - /// # Examples - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::from_millis(5010); - /// assert_eq!(duration.as_secs(), 5); - /// assert_eq!(duration.subsec_nanos(), 10_000_000); - /// ``` - #[stable(feature = "duration", since = "1.3.0")] - #[inline] - pub fn subsec_nanos(&self) -> u32 { self.nanos } - - /// Checked `Duration` addition. Computes `self + other`, returning [`None`] - /// if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_add(self, rhs: Duration) -> Option { - if let Some(mut secs) = self.secs.checked_add(rhs.secs) { - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - if let Some(new_secs) = secs.checked_add(1) { - secs = new_secs; - } else { - return None; - } - } - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { - secs, - nanos, - }) - } else { - None - } - } - - /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] - /// if the result would be negative or if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_sub(self, rhs: Duration) -> Option { - if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { - let nanos = if self.nanos >= rhs.nanos { - self.nanos - rhs.nanos - } else { - if let Some(sub_secs) = secs.checked_sub(1) { - secs = sub_secs; - self.nanos + NANOS_PER_SEC - rhs.nanos - } else { - return None; - } - }; - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { secs: secs, nanos: nanos }) - } else { - None - } - } - - /// Checked `Duration` multiplication. Computes `self * other`, returning - /// [`None`] if overflow occurred. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); - /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_mul(self, rhs: u32) -> Option { - // Multiply nanoseconds as u64, because it cannot overflow that way. - let total_nanos = self.nanos as u64 * rhs as u64; - let extra_secs = total_nanos / (NANOS_PER_SEC as u64); - let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; - if let Some(secs) = self.secs - .checked_mul(rhs as u64) - .and_then(|s| s.checked_add(extra_secs)) { - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { - secs, - nanos, - }) - } else { - None - } - } - - /// Checked `Duration` division. Computes `self / other`, returning [`None`] - /// if `other == 0`. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::time::Duration; - /// - /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - /// assert_eq!(Duration::new(2, 0).checked_div(0), None); - /// ``` - #[stable(feature = "duration_checked_ops", since = "1.16.0")] - #[inline] - pub fn checked_div(self, rhs: u32) -> Option { - if rhs != 0 { - let secs = self.secs / (rhs as u64); - let carry = self.secs - secs * (rhs as u64); - let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); - let nanos = self.nanos / rhs + (extra_nanos as u32); - debug_assert!(nanos < NANOS_PER_SEC); - Some(Duration { secs: secs, nanos: nanos }) - } else { - None - } - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Add for Duration { - type Output = Duration; - - fn add(self, rhs: Duration) -> Duration { - self.checked_add(rhs).expect("overflow when adding durations") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for Duration { - fn add_assign(&mut self, rhs: Duration) { - *self = *self + rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Sub for Duration { - type Output = Duration; - - fn sub(self, rhs: Duration) -> Duration { - self.checked_sub(rhs).expect("overflow when subtracting durations") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for Duration { - fn sub_assign(&mut self, rhs: Duration) { - *self = *self - rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Mul for Duration { - type Output = Duration; - - fn mul(self, rhs: u32) -> Duration { - self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl MulAssign for Duration { - fn mul_assign(&mut self, rhs: u32) { - *self = *self * rhs; - } -} - -#[stable(feature = "duration", since = "1.3.0")] -impl Div for Duration { - type Output = Duration; - - fn div(self, rhs: u32) -> Duration { - self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl DivAssign for Duration { - fn div_assign(&mut self, rhs: u32) { - *self = *self / rhs; - } -} - -#[stable(feature = "duration_sum", since = "1.16.0")] -impl Sum for Duration { - fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + b) - } -} - -#[stable(feature = "duration_sum", since = "1.16.0")] -impl<'a> Sum<&'a Duration> for Duration { - fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + *b) - } -} - -#[cfg(test)] -mod tests { - use super::Duration; - - #[test] - fn creation() { - assert!(Duration::from_secs(1) != Duration::from_secs(0)); - assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), - Duration::from_secs(3)); - assert_eq!(Duration::from_millis(10) + Duration::from_secs(4), - Duration::new(4, 10 * 1_000_000)); - assert_eq!(Duration::from_millis(4000), Duration::new(4, 0)); - } - - #[test] - fn secs() { - assert_eq!(Duration::new(0, 0).as_secs(), 0); - assert_eq!(Duration::from_secs(1).as_secs(), 1); - assert_eq!(Duration::from_millis(999).as_secs(), 0); - assert_eq!(Duration::from_millis(1001).as_secs(), 1); - } - - #[test] - fn nanos() { - assert_eq!(Duration::new(0, 0).subsec_nanos(), 0); - assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); - assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); - assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); - } - - #[test] - fn add() { - assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), - Duration::new(1, 1)); - } - - #[test] - fn checked_add() { - assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), - Some(Duration::new(0, 1))); - assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), - Some(Duration::new(1, 1))); - assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); - } - - #[test] - fn sub() { - assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), - Duration::new(0, 1)); - assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), - Duration::new(0, 1)); - assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), - Duration::new(0, 999_999_999)); - } - - #[test] - fn checked_sub() { - let zero = Duration::new(0, 0); - let one_nano = Duration::new(0, 1); - let one_sec = Duration::new(1, 0); - assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); - assert_eq!(one_sec.checked_sub(one_nano), - Some(Duration::new(0, 999_999_999))); - assert_eq!(zero.checked_sub(one_nano), None); - assert_eq!(zero.checked_sub(one_sec), None); - } - - #[test] #[should_panic] - fn sub_bad1() { - Duration::new(0, 0) - Duration::new(0, 1); - } - - #[test] #[should_panic] - fn sub_bad2() { - Duration::new(0, 0) - Duration::new(1, 0); - } - - #[test] - fn mul() { - assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2)); - assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3)); - assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4)); - assert_eq!(Duration::new(0, 500_000_001) * 4000, - Duration::new(2000, 4000)); - } - - #[test] - fn checked_mul() { - assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); - assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); - assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), - Some(Duration::new(2000, 4000))); - assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); - } - - #[test] - fn div() { - assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); - assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); - assert_eq!(Duration::new(99, 999_999_000) / 100, - Duration::new(0, 999_999_990)); - } - - #[test] - fn checked_div() { - assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); - assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); - assert_eq!(Duration::new(2, 0).checked_div(0), None); - } -} diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs deleted file mode 100644 index 6ce3b3e8a00..00000000000 --- a/src/libstd/time/mod.rs +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Temporal quantification. -//! -//! Example: -//! -//! ``` -//! use std::time::Duration; -//! -//! let five_seconds = Duration::new(5, 0); -//! // both declarations are equivalent -//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); -//! ``` - -#![stable(feature = "time", since = "1.3.0")] - -use error::Error; -use fmt; -use ops::{Add, Sub, AddAssign, SubAssign}; -use sys::time; -use sys_common::FromInner; - -#[stable(feature = "time", since = "1.3.0")] -pub use self::duration::Duration; - -mod duration; - -/// A measurement of a monotonically nondecreasing clock. -/// Opaque and useful only with `Duration`. -/// -/// Instants are always guaranteed to be no less than any previously measured -/// instant when created, and are often useful for tasks such as measuring -/// benchmarks or timing how long an operation takes. -/// -/// Note, however, that instants are not guaranteed to be **steady**. In other -/// words, each tick of the underlying clock may not be the same length (e.g. -/// some seconds may be longer than others). An instant may jump forwards or -/// experience time dilation (slow down or speed up), but it will never go -/// backwards. -/// -/// Instants are opaque types that can only be compared to one another. There is -/// no method to get "the number of seconds" from an instant. Instead, it only -/// allows measuring the duration between two instants (or comparing two -/// instants). -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, Instant}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = Instant::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// // it prints '2' -/// println!("{}", now.elapsed().as_secs()); -/// } -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct Instant(time::Instant); - -/// A measurement of the system clock, useful for talking to -/// external entities like the file system or other processes. -/// -/// Distinct from the [`Instant`] type, this time measurement **is not -/// monotonic**. This means that you can save a file to the file system, then -/// save another file to the file system, **and the second file has a -/// `SystemTime` measurement earlier than the first**. In other words, an -/// operation that happens after another operation in real time may have an -/// earlier `SystemTime`! -/// -/// Consequently, comparing two `SystemTime` instances to learn about the -/// duration between them returns a [`Result`] instead of an infallible [`Duration`] -/// to indicate that this sort of time drift may happen and needs to be handled. -/// -/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`] -/// constant is provided in this module as an anchor in time to learn -/// information about a `SystemTime`. By calculating the duration from this -/// fixed point in time, a `SystemTime` can be converted to a human-readable time, -/// or perhaps some other string representation. -/// -/// [`Instant`]: ../../std/time/struct.Instant.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`Duration`]: ../../std/time/struct.Duration.html -/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html -/// -/// Example: -/// -/// ```no_run -/// use std::time::{Duration, SystemTime}; -/// use std::thread::sleep; -/// -/// fn main() { -/// let now = SystemTime::now(); -/// -/// // we sleep for 2 seconds -/// sleep(Duration::new(2, 0)); -/// match now.elapsed() { -/// Ok(elapsed) => { -/// // it prints '2' -/// println!("{}", elapsed.as_secs()); -/// } -/// Err(e) => { -/// // an error occurred! -/// println!("Error: {:?}", e); -/// } -/// } -/// } -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTime(time::SystemTime); - -/// An error returned from the `duration_since` and `elapsed` methods on -/// `SystemTime`, used to learn how far in the opposite direction a system time -/// lies. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread::sleep; -/// use std::time::{Duration, SystemTime}; -/// -/// let sys_time = SystemTime::now(); -/// sleep(Duration::from_secs(1)); -/// let new_sys_time = SystemTime::now(); -/// match sys_time.duration_since(new_sys_time) { -/// Ok(_) => {} -/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), -/// } -/// ``` -#[derive(Clone, Debug)] -#[stable(feature = "time2", since = "1.8.0")] -pub struct SystemTimeError(Duration); - -impl Instant { - /// Returns an instant corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::Instant; - /// - /// let now = Instant::now(); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn now() -> Instant { - Instant(time::Instant::now()) - } - - /// Returns the amount of time elapsed from another instant to this one. - /// - /// # Panics - /// - /// This function will panic if `earlier` is later than `self`. - /// - /// # Examples - /// - /// ```no_run - /// use std::time::{Duration, Instant}; - /// use std::thread::sleep; - /// - /// let now = Instant::now(); - /// sleep(Duration::new(1, 0)); - /// let new_now = Instant::now(); - /// println!("{:?}", new_now.duration_since(now)); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: Instant) -> Duration { - self.0.sub_instant(&earlier.0) - } - - /// Returns the amount of time elapsed since this instant was created. - /// - /// # Panics - /// - /// This function may panic if the current time is earlier than this - /// instant, which is something that can happen if an `Instant` is - /// produced synthetically. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, Instant}; - /// - /// let instant = Instant::now(); - /// let three_secs = Duration::from_secs(3); - /// sleep(three_secs); - /// assert!(instant.elapsed() >= three_secs); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Duration { - Instant::now() - *self - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for Instant { - type Output = Instant; - - fn add(self, other: Duration) -> Instant { - Instant(self.0.add_duration(&other)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for Instant { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Instant; - - fn sub(self, other: Duration) -> Instant { - Instant(self.0.sub_duration(&other)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for Instant { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for Instant { - type Output = Duration; - - fn sub(self, other: Instant) -> Duration { - self.duration_since(other) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -impl SystemTime { - /// Returns the system time corresponding to "now". - /// - /// # Examples - /// - /// ``` - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn now() -> SystemTime { - SystemTime(time::SystemTime::now()) - } - - /// Returns the amount of time elapsed from an earlier point in time. - /// - /// This function may fail because measurements taken earlier are not - /// guaranteed to always be before later measurements (due to anomalies such - /// as the system clock being adjusted either forwards or backwards). - /// - /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents - /// the amount of time elapsed from the specified measurement to this one. - /// - /// Returns an [`Err`] if `earlier` is later than `self`, and the error - /// contains how far from `self` the time is. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ``` - /// use std::time::SystemTime; - /// - /// let sys_time = SystemTime::now(); - /// let difference = sys_time.duration_since(sys_time) - /// .expect("SystemTime::duration_since failed"); - /// println!("{:?}", difference); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: SystemTime) - -> Result { - self.0.sub_time(&earlier.0).map_err(SystemTimeError) - } - - /// Returns the amount of time elapsed since this system time was created. - /// - /// This function may fail as the underlying system clock is susceptible to - /// drift and updates (e.g. the system clock could go backwards), so this - /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is - /// returned where the duration represents the amount of time elapsed from - /// this time measurement to the current time. - /// - /// Returns an [`Err`] if `self` is later than the current system time, and - /// the error contains how far from the current system time `self` is. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Duration`]: ../../std/time/struct.Duration.html - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// let one_sec = Duration::from_secs(1); - /// sleep(one_sec); - /// assert!(sys_time.elapsed().unwrap() >= one_sec); - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn elapsed(&self) -> Result { - SystemTime::now().duration_since(*self) - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Add for SystemTime { - type Output = SystemTime; - - fn add(self, dur: Duration) -> SystemTime { - SystemTime(self.0.add_duration(&dur)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for SystemTime { - fn add_assign(&mut self, other: Duration) { - *self = *self + other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Sub for SystemTime { - type Output = SystemTime; - - fn sub(self, dur: Duration) -> SystemTime { - SystemTime(self.0.sub_duration(&dur)) - } -} - -#[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for SystemTime { - fn sub_assign(&mut self, other: Duration) { - *self = *self - other; - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } -} - -/// An anchor in time which can be used to create new `SystemTime` instances or -/// learn about where in time a `SystemTime` lies. -/// -/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with -/// respect to the system clock. Using `duration_since` on an existing -/// [`SystemTime`] instance can tell how far away from this point in time a -/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a -/// [`SystemTime`] instance to represent another fixed point in time. -/// -/// [`SystemTime`]: ../../std/time/struct.SystemTime.html -/// -/// # Examples -/// -/// ```no_run -/// use std::time::{SystemTime, UNIX_EPOCH}; -/// -/// match SystemTime::now().duration_since(UNIX_EPOCH) { -/// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), -/// Err(_) => panic!("SystemTime before UNIX EPOCH!"), -/// } -/// ``` -#[stable(feature = "time2", since = "1.8.0")] -pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); - -impl SystemTimeError { - /// Returns the positive duration which represents how far forward the - /// second system time was from the first. - /// - /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`] - /// methods of [`SystemTime`] whenever the second system time represents a point later - /// in time than the `self` of the method call. - /// - /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since - /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed - /// [`SystemTime`]: ../../std/time/struct.SystemTime.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread::sleep; - /// use std::time::{Duration, SystemTime}; - /// - /// let sys_time = SystemTime::now(); - /// sleep(Duration::from_secs(1)); - /// let new_sys_time = SystemTime::now(); - /// match sys_time.duration_since(new_sys_time) { - /// Ok(_) => {} - /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), - /// } - /// ``` - #[stable(feature = "time2", since = "1.8.0")] - pub fn duration(&self) -> Duration { - self.0 - } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl Error for SystemTimeError { - fn description(&self) -> &str { "other time was not earlier than self" } -} - -#[stable(feature = "time2", since = "1.8.0")] -impl fmt::Display for SystemTimeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "second time provided was later than self") - } -} - -impl FromInner for SystemTime { - fn from_inner(time: time::SystemTime) -> SystemTime { - SystemTime(time) - } -} - -#[cfg(test)] -mod tests { - use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; - - macro_rules! assert_almost_eq { - ($a:expr, $b:expr) => ({ - let (a, b) = ($a, $b); - if a != b { - let (a, b) = if a > b {(a, b)} else {(b, a)}; - assert!(a - Duration::new(0, 100) <= b); - } - }) - } - - #[test] - fn instant_monotonic() { - let a = Instant::now(); - let b = Instant::now(); - assert!(b >= a); - } - - #[test] - fn instant_elapsed() { - let a = Instant::now(); - a.elapsed(); - } - - #[test] - fn instant_math() { - let a = Instant::now(); - let b = Instant::now(); - let dur = b.duration_since(a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - - let second = Duration::new(1, 0); - assert_almost_eq!(a - second + second, a); - } - - #[test] - #[should_panic] - fn instant_duration_panic() { - let a = Instant::now(); - (a - Duration::new(1, 0)).duration_since(a); - } - - #[test] - fn system_time_math() { - let a = SystemTime::now(); - let b = SystemTime::now(); - match b.duration_since(a) { - Ok(dur) if dur == Duration::new(0, 0) => { - assert_almost_eq!(a, b); - } - Ok(dur) => { - assert!(b > a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - } - Err(dur) => { - let dur = dur.duration(); - assert!(a > b); - assert_almost_eq!(b + dur, a); - assert_almost_eq!(a - dur, b); - } - } - - let second = Duration::new(1, 0); - assert_almost_eq!(a.duration_since(a - second).unwrap(), second); - assert_almost_eq!(a.duration_since(a + second).unwrap_err() - .duration(), second); - - assert_almost_eq!(a - second + second, a); - - // A difference of 80 and 800 years cannot fit inside a 32-bit time_t - if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 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); - assert_eq!(one_second_from_epoch, one_second_from_epoch2); - } - - #[test] - fn system_time_elapsed() { - let a = SystemTime::now(); - drop(a.elapsed()); - } - - #[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(); - assert!(b > a); - assert_eq!(b - a, Duration::new(1, 0)); - - let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; - - // Right now for CI this test is run in an emulator, and apparently the - // aarch64 emulator's sense of time is that we're still living in the - // 70s. - // - // Otherwise let's assume that we're all running computers later than - // 2000. - if !cfg!(target_arch = "aarch64") { - assert!(a > thirty_years); - } - - // let's assume that we're all running computers earlier than 2090. - // Should give us ~70 years to fix this! - let hundred_twenty_years = thirty_years * 4; - assert!(a < hundred_twenty_years); - } -} -- cgit 1.4.1-3-g733a5 From e9d70417cae7fcb08323351d9388b65b39560156 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Tue, 23 Jan 2018 14:47:30 +0000 Subject: std: use more portable error number in from_raw_os_error docs On MIPS, error number 98 is not EADDRINUSE (it is EPROTOTYPE). To fix the resulting test failure this causes, use a more portable error number in the example documentation. EINVAL shold be more reliable because it was defined in the original Unix as 22 so hopefully most derivatives have defined it the same way. --- src/libstd/io/error.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index f0b41f30251..bdd675e6e2b 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -292,8 +292,8 @@ impl Error { /// # if cfg!(target_os = "linux") { /// use std::io; /// - /// let error = io::Error::from_raw_os_error(98); - /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// let error = io::Error::from_raw_os_error(22); + /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); /// # } /// ``` /// @@ -303,8 +303,8 @@ impl Error { /// # if cfg!(windows) { /// use std::io; /// - /// let error = io::Error::from_raw_os_error(10048); - /// assert_eq!(error.kind(), io::ErrorKind::AddrInUse); + /// let error = io::Error::from_raw_os_error(10022); + /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 36695a37c52a0e6cc582247a506ab0b3c764b48f Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sun, 31 Dec 2017 16:40:34 +0000 Subject: Implement extensible syscall interface for wasm --- src/etc/wasm32-shim.js | 149 ++++++++++++++----------- src/librustc_trans/back/write.rs | 6 +- src/libstd/Cargo.toml | 1 + src/libstd/sys/wasm/args.rs | 38 +------ src/libstd/sys/wasm/mod.rs | 233 +++++++++++++++++++++++++++++++++++++-- src/libstd/sys/wasm/os.rs | 38 ++----- src/libstd/sys/wasm/stdio.rs | 35 ++---- src/libstd/sys/wasm/time.rs | 44 ++++---- 8 files changed, 346 insertions(+), 198 deletions(-) (limited to 'src/libstd') diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js index d55083e0f8e..69647f37eec 100644 --- a/src/etc/wasm32-shim.js +++ b/src/etc/wasm32-shim.js @@ -28,14 +28,76 @@ let m = new WebAssembly.Module(buffer); let memory = null; +function viewstruct(data, fields) { + return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields); +} + function copystr(a, b) { - if (memory === null) { - return null - } - let view = new Uint8Array(memory.buffer).slice(a, a + b); + let view = new Uint8Array(memory.buffer).subarray(a, a + b); return String.fromCharCode.apply(null, view); } +function syscall_write([fd, ptr, len]) { + let s = copystr(ptr, len); + switch (fd) { + case 1: process.stdout.write(s); break; + case 2: process.stderr.write(s); break; + } +} + +function syscall_exit([code]) { + process.exit(code); +} + +function syscall_args(params) { + let [ptr, len] = params; + + // Calculate total required buffer size + let totalLen = -1; + for (let i = 2; i < process.argv.length; ++i) { + totalLen += Buffer.byteLength(process.argv[i]) + 1; + } + if (totalLen < 0) { totalLen = 0; } + params[2] = totalLen; + + // If buffer is large enough, copy data + if (len >= totalLen) { + let view = new Uint8Array(memory.buffer); + for (let i = 2; i < process.argv.length; ++i) { + let value = process.argv[i]; + Buffer.from(value).copy(view, ptr); + ptr += Buffer.byteLength(process.argv[i]) + 1; + } + } +} + +function syscall_getenv(params) { + let [keyPtr, keyLen, valuePtr, valueLen] = params; + + let key = copystr(keyPtr, keyLen); + let value = process.env[key]; + + if (value == null) { + params[4] = 0xFFFFFFFF; + } else { + let view = new Uint8Array(memory.buffer); + let totalLen = Buffer.byteLength(value); + params[4] = totalLen; + if (valueLen >= totalLen) { + Buffer.from(value).copy(view, valuePtr); + } + } +} + +function syscall_time(params) { + let t = Date.now(); + let secs = Math.floor(t / 1000); + let millis = t % 1000; + params[1] = Math.floor(secs / 0x100000000); + params[2] = secs % 0x100000000; + params[3] = Math.floor(millis * 1000000); +} + let imports = {}; imports.env = { // These are generated by LLVM itself for various intrinsic calls. Hopefully @@ -48,68 +110,25 @@ imports.env = { log10: Math.log10, log10f: Math.log10, - // These are called in src/libstd/sys/wasm/stdio.rs and are used when - // debugging is enabled. - rust_wasm_write_stdout: function(a, b) { - let s = copystr(a, b); - if (s !== null) { - process.stdout.write(s); - } - }, - rust_wasm_write_stderr: function(a, b) { - let s = copystr(a, b); - if (s !== null) { - process.stderr.write(s); - } - }, - - // These are called in src/libstd/sys/wasm/args.rs and are used when - // debugging is enabled. - rust_wasm_args_count: function() { - if (memory === null) - return 0; - return process.argv.length - 2; - }, - rust_wasm_args_arg_size: function(i) { - return Buffer.byteLength(process.argv[i + 2]); - }, - rust_wasm_args_arg_fill: function(idx, ptr) { - let arg = process.argv[idx + 2]; - let view = new Uint8Array(memory.buffer); - Buffer.from(arg).copy(view, ptr); - }, - - // These are called in src/libstd/sys/wasm/os.rs and are used when - // debugging is enabled. - rust_wasm_getenv_len: function(a, b) { - let key = copystr(a, b); - if (key === null) { - return -1; + rust_wasm_syscall: function(index, data) { + switch (index) { + case 1: syscall_write(viewstruct(data, 3)); return true; + case 2: syscall_exit(viewstruct(data, 1)); return true; + case 3: syscall_args(viewstruct(data, 3)); return true; + case 4: syscall_getenv(viewstruct(data, 5)); return true; + case 6: syscall_time(viewstruct(data, 4)); return true; + default: + console.log("Unsupported syscall: " + index); + return false; } - if (!(key in process.env)) { - return -1; - } - return Buffer.byteLength(process.env[key]); - }, - rust_wasm_getenv_data: function(a, b, ptr) { - let key = copystr(a, b); - let value = process.env[key]; - let view = new Uint8Array(memory.buffer); - Buffer.from(value).copy(view, ptr); - }, -}; - -let module_imports = WebAssembly.Module.imports(m); - -for (var i = 0; i < module_imports.length; i++) { - let imp = module_imports[i]; - if (imp.module != 'env') { - continue } - if (imp.name == 'memory' && imp.kind == 'memory') { - memory = new WebAssembly.Memory({initial: 20}); - imports.env.memory = memory; - } -} +}; let instance = new WebAssembly.Instance(m, imports); +memory = instance.exports.memory; +try { + instance.exports.main(); +} catch (e) { + console.error(e); + process.exit(101); +} diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 8afa63a5e97..206c73b0174 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -824,9 +824,7 @@ fn binaryen_assemble(cgcx: &CodegenContext, if cgcx.debuginfo != config::NoDebugInfo { options.debuginfo(true); } - if cgcx.crate_types.contains(&config::CrateTypeExecutable) { - options.start("main"); - } + options.stack(1024 * 1024); options.import_memory(cgcx.wasm_import_memory); let assembled = input.and_then(|input| { @@ -1452,7 +1450,7 @@ fn start_executing_work(tcx: TyCtxt, target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen, debuginfo: tcx.sess.opts.debuginfo, - wasm_import_memory: wasm_import_memory, + wasm_import_memory, assembler_cmd, }; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 3430ecabcbe..c1fe4a89d6a 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -48,3 +48,4 @@ jemalloc = ["alloc_jemalloc"] force_alloc_system = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] +wasm_syscall = [] diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs index d2a4a7b19d5..b3c6b671e80 100644 --- a/src/libstd/sys/wasm/args.rs +++ b/src/libstd/sys/wasm/args.rs @@ -10,8 +10,8 @@ use ffi::OsString; use marker::PhantomData; -use mem; use vec; +use sys::ArgsSysCall; pub unsafe fn init(_argc: isize, _argv: *const *const u8) { // On wasm these should always be null, so there's nothing for us to do here @@ -21,38 +21,10 @@ pub unsafe fn cleanup() { } pub fn args() -> Args { - // When the runtime debugging is enabled we'll link to some extra runtime - // functions to actually implement this. These are for now just implemented - // in a node.js script but they're off by default as they're sort of weird - // in a web-wasm world. - if !super::DEBUG { - return Args { - iter: Vec::new().into_iter(), - _dont_send_or_sync_me: PhantomData, - } - } - - // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These - // are just meant for debugging and should not be relied on. - extern { - fn rust_wasm_args_count() -> usize; - fn rust_wasm_args_arg_size(a: usize) -> usize; - fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8); - } - - unsafe { - let cnt = rust_wasm_args_count(); - let mut v = Vec::with_capacity(cnt); - for i in 0..cnt { - let n = rust_wasm_args_arg_size(i); - let mut data = vec![0; n]; - rust_wasm_args_arg_fill(i, data.as_mut_ptr()); - v.push(mem::transmute::, OsString>(data)); - } - Args { - iter: v.into_iter(), - _dont_send_or_sync_me: PhantomData, - } + let v = ArgsSysCall::perform(); + Args { + iter: v.into_iter(), + _dont_send_or_sync_me: PhantomData, } } diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index ba3d6a2813a..c02e5e809c8 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -26,17 +26,11 @@ use io; use os::raw::c_char; - -// Right now the wasm backend doesn't even have the ability to print to the -// console by default. Wasm can't import anything from JS! (you have to -// explicitly provide it). -// -// Sometimes that's a real bummer, though, so this flag can be set to `true` to -// enable calling various shims defined in `src/etc/wasm32-shim.js` which should -// help receive debug output and see what's going on. In general this flag -// currently controls "will we call out to our own defined shims in node.js", -// and this flag should always be `false` for release builds. -const DEBUG: bool = false; +use ptr; +use sys::os_str::Buf; +use sys_common::{AsInner, FromInner}; +use ffi::{OsString, OsStr}; +use time::Duration; pub mod args; #[cfg(feature = "backtrace")] @@ -92,7 +86,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { } pub unsafe fn abort_internal() -> ! { - ::intrinsics::abort(); + ExitSysCall::perform(1) } // We don't have randomness yet, but I totally used a random number generator to @@ -103,3 +97,218 @@ pub unsafe fn abort_internal() -> ! { pub fn hashmap_random_keys() -> (u64, u64) { (1, 2) } + +// Implement a minimal set of system calls to enable basic IO +pub enum SysCallIndex { + Read = 0, + Write = 1, + Exit = 2, + Args = 3, + GetEnv = 4, + SetEnv = 5, + Time = 6, +} + +#[repr(C)] +pub struct ReadSysCall { + fd: usize, + ptr: *mut u8, + len: usize, + result: usize, +} + +impl ReadSysCall { + pub fn perform(fd: usize, buffer: &mut [u8]) -> usize { + let mut call_record = ReadSysCall { + fd, + len: buffer.len(), + ptr: buffer.as_mut_ptr(), + result: 0 + }; + if unsafe { syscall(SysCallIndex::Read, &mut call_record) } { + call_record.result + } else { + 0 + } + } +} + +#[repr(C)] +pub struct WriteSysCall { + fd: usize, + ptr: *const u8, + len: usize, +} + +impl WriteSysCall { + pub fn perform(fd: usize, buffer: &[u8]) { + let mut call_record = WriteSysCall { + fd, + len: buffer.len(), + ptr: buffer.as_ptr() + }; + unsafe { syscall(SysCallIndex::Write, &mut call_record); } + } +} + +#[repr(C)] +pub struct ExitSysCall { + code: usize, +} + +impl ExitSysCall { + pub fn perform(code: usize) -> ! { + let mut call_record = ExitSysCall { + code + }; + unsafe { + syscall(SysCallIndex::Exit, &mut call_record); + ::intrinsics::abort(); + } + } +} + +fn receive_buffer Result>(estimate: usize, mut f: F) + -> Result, E> +{ + let mut buffer = vec![0; estimate]; + loop { + let result = f(&mut buffer)?; + if result <= buffer.len() { + buffer.truncate(result); + break; + } + buffer.resize(result, 0); + } + Ok(buffer) +} + +#[repr(C)] +pub struct ArgsSysCall { + ptr: *mut u8, + len: usize, + result: usize +} + +impl ArgsSysCall { + pub fn perform() -> Vec { + receive_buffer(1024, |buffer| -> Result { + let mut call_record = ArgsSysCall { + len: buffer.len(), + ptr: buffer.as_mut_ptr(), + result: 0 + }; + if unsafe { syscall(SysCallIndex::Args, &mut call_record) } { + Ok(call_record.result) + } else { + Ok(0) + } + }) + .unwrap() + .split(|b| *b == 0) + .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() })) + .collect() + } +} + +#[repr(C)] +pub struct GetEnvSysCall { + key_ptr: *const u8, + key_len: usize, + value_ptr: *mut u8, + value_len: usize, + result: usize +} + +impl GetEnvSysCall { + pub fn perform(key: &OsStr) -> Option { + let key_buf = &AsInner::as_inner(key).inner; + receive_buffer(64, |buffer| { + let mut call_record = GetEnvSysCall { + key_len: key_buf.len(), + key_ptr: key_buf.as_ptr(), + value_len: buffer.len(), + value_ptr: buffer.as_mut_ptr(), + result: !0usize + }; + if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } { + if call_record.result == !0usize { + Err(()) + } else { + Ok(call_record.result) + } + } else { + Err(()) + } + }).ok().map(|s| { + FromInner::from_inner(Buf { inner: s }) + }) + } +} + +#[repr(C)] +pub struct SetEnvSysCall { + key_ptr: *const u8, + key_len: usize, + value_ptr: *const u8, + value_len: usize +} + +impl SetEnvSysCall { + pub fn perform(key: &OsStr, value: Option<&OsStr>) { + let key_buf = &AsInner::as_inner(key).inner; + let value_buf = value.map(|v| &AsInner::as_inner(v).inner); + let mut call_record = SetEnvSysCall { + key_len: key_buf.len(), + key_ptr: key_buf.as_ptr(), + value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize), + value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null()) + }; + unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); } + } +} + +pub enum TimeClock { + Monotonic = 0, + System = 1, +} + +#[repr(C)] +pub struct TimeSysCall { + clock: usize, + secs_hi: usize, + secs_lo: usize, + nanos: usize +} + +impl TimeSysCall { + pub fn perform(clock: TimeClock) -> Duration { + let mut call_record = TimeSysCall { + clock: clock as usize, + secs_hi: 0, + secs_lo: 0, + nanos: 0 + }; + if unsafe { syscall(SysCallIndex::Time, &mut call_record) } { + Duration::new( + ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64), + call_record.nanos as u32 + ) + } else { + panic!("Time system call is not implemented by WebAssembly host"); + } + } +} + +unsafe fn syscall(index: SysCallIndex, data: &mut T) -> bool { + #[cfg(feature = "wasm_syscall")] + extern { + #[no_mangle] + fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize; + } + + #[cfg(not(feature = "wasm_syscall"))] + unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 } + + rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0 +} diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs index c98030f7ebf..23ca1754719 100644 --- a/src/libstd/sys/wasm/os.rs +++ b/src/libstd/sys/wasm/os.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::intrinsics; - use error::Error as StdError; use ffi::{OsString, OsStr}; use fmt; use io; -use mem; use path::{self, PathBuf}; use str; -use sys::{unsupported, Void}; +use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall}; pub fn errno() -> i32 { 0 @@ -87,36 +84,15 @@ pub fn env() -> Env { } pub fn getenv(k: &OsStr) -> io::Result> { - // If we're debugging the runtime then we actually probe node.js to ask for - // the value of environment variables to help provide inputs to programs. - // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are - // intended for debugging only, you should not rely on them. - if !super::DEBUG { - return Ok(None) - } - - extern { - fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize; - fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8); - } - unsafe { - let k: &[u8] = mem::transmute(k); - let n = rust_wasm_getenv_len(k.as_ptr(), k.len()); - if n == -1 { - return Ok(None) - } - let mut data = vec![0; n as usize]; - rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr()); - Ok(Some(mem::transmute(data))) - } + Ok(GetEnvSysCall::perform(k)) } -pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { - unsupported() +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + Ok(SetEnvSysCall::perform(k, Some(v))) } -pub fn unsetenv(_n: &OsStr) -> io::Result<()> { - unsupported() +pub fn unsetenv(k: &OsStr) -> io::Result<()> { + Ok(SetEnvSysCall::perform(k, None)) } pub fn temp_dir() -> PathBuf { @@ -128,7 +104,7 @@ pub fn home_dir() -> Option { } pub fn exit(_code: i32) -> ! { - unsafe { intrinsics::abort() } + ExitSysCall::perform(_code as isize as usize) } pub fn getpid() -> u32 { diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs index 0f75f240251..beb19c0ed2c 100644 --- a/src/libstd/sys/wasm/stdio.rs +++ b/src/libstd/sys/wasm/stdio.rs @@ -9,19 +9,19 @@ // except according to those terms. use io; -use sys::{Void, unsupported}; +use sys::{ReadSysCall, WriteSysCall}; -pub struct Stdin(Void); +pub struct Stdin; pub struct Stdout; pub struct Stderr; impl Stdin { pub fn new() -> io::Result { - unsupported() + Ok(Stdin) } - pub fn read(&self, _data: &mut [u8]) -> io::Result { - match self.0 {} + pub fn read(&self, data: &mut [u8]) -> io::Result { + Ok(ReadSysCall::perform(0, data)) } } @@ -31,19 +31,7 @@ impl Stdout { } pub fn write(&self, data: &[u8]) -> io::Result { - // If runtime debugging is enabled at compile time we'll invoke some - // runtime functions that are defined in our src/etc/wasm32-shim.js - // debugging script. Note that this ffi function call is intended - // *purely* for debugging only and should not be relied upon. - if !super::DEBUG { - return unsupported() - } - extern { - fn rust_wasm_write_stdout(data: *const u8, len: usize); - } - unsafe { - rust_wasm_write_stdout(data.as_ptr(), data.len()) - } + WriteSysCall::perform(1, data); Ok(data.len()) } @@ -58,16 +46,7 @@ impl Stderr { } pub fn write(&self, data: &[u8]) -> io::Result { - // See comments in stdout for what's going on here. - if !super::DEBUG { - return unsupported() - } - extern { - fn rust_wasm_write_stderr(data: *const u8, len: usize); - } - unsafe { - rust_wasm_write_stderr(data.as_ptr(), data.len()) - } + WriteSysCall::perform(2, data); Ok(data.len()) } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index c269def98f6..e52435e6339 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -8,56 +8,50 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use fmt; use time::Duration; +use sys::{TimeSysCall, TimeClock}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] -pub struct Instant; +pub struct Instant(Duration); -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SystemTime; +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(Duration); -pub const UNIX_EPOCH: SystemTime = SystemTime; +pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); impl Instant { pub fn now() -> Instant { - panic!("not supported on web assembly"); + Instant(TimeSysCall::perform(TimeClock::Monotonic)) } - pub fn sub_instant(&self, _other: &Instant) -> Duration { - panic!("can't sub yet"); + pub fn sub_instant(&self, other: &Instant) -> Duration { + self.0 - other.0 } - pub fn add_duration(&self, _other: &Duration) -> Instant { - panic!("can't add yet"); + pub fn add_duration(&self, other: &Duration) -> Instant { + Instant(self.0 + *other) } - pub fn sub_duration(&self, _other: &Duration) -> Instant { - panic!("can't sub yet"); + pub fn sub_duration(&self, other: &Duration) -> Instant { + Instant(self.0 - *other) } } impl SystemTime { pub fn now() -> SystemTime { - panic!("not supported on web assembly"); + SystemTime(TimeSysCall::perform(TimeClock::System)) } - pub fn sub_time(&self, _other: &SystemTime) + pub fn sub_time(&self, other: &SystemTime) -> Result { - panic!() - } - - pub fn add_duration(&self, _other: &Duration) -> SystemTime { - panic!() + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - pub fn sub_duration(&self, _other: &Duration) -> SystemTime { - panic!() + pub fn add_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 + *other) } -} -impl fmt::Debug for SystemTime { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - panic!() + pub fn sub_duration(&self, other: &Duration) -> SystemTime { + SystemTime(self.0 - *other) } } -- cgit 1.4.1-3-g733a5 From 55b54a999bcdb0b1c1f42b6e1ae670beb0717086 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 31 Jan 2018 11:41:29 -0800 Subject: Use a range to identify SIGSEGV in stack guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the `guard::init()` and `guard::current()` functions were returning a `usize` address representing the top of the stack guard, respectively for the main thread and for spawned threads. The `SIGSEGV` handler on `unix` targets checked if a fault was within one page below that address, if so reporting it as a stack overflow. Now `unix` targets report a `Range` representing the guard memory, so it can cover arbitrary guard sizes. Non-`unix` targets which always return `None` for guards now do so with `Option`, so they don't pay any overhead. For `linux-gnu` in particular, the previous guard upper-bound was `stackaddr + guardsize`, as the protected memory was *inside* the stack. This was a glibc bug, and starting from 2.27 they are moving the guard *past* the end of the stack. However, there's no simple way for us to know where the guard page actually lies, so now we declare it as the whole range of `stackaddr ± guardsize`, and any fault therein will be called a stack overflow. This fixes #47863. --- src/libstd/sys/cloudabi/thread.rs | 5 +- src/libstd/sys/redox/thread.rs | 5 +- src/libstd/sys/unix/stack_overflow.rs | 9 +-- src/libstd/sys/unix/thread.rs | 115 +++++++++++++++++++++------------- src/libstd/sys/wasm/thread.rs | 5 +- src/libstd/sys/windows/thread.rs | 5 +- src/libstd/sys_common/thread_info.rs | 9 +-- 7 files changed, 89 insertions(+), 64 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index c980ae75261..78a3b82546e 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -111,10 +111,11 @@ impl Drop for Thread { #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option { + pub type Guard = !; + pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { + pub unsafe fn init() -> Option { None } } diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index c4aad8d86f8..c4719a94c7e 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -88,6 +88,7 @@ impl Thread { } pub mod guard { - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } + pub type Guard = !; + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 51adbc24ae0..40453f9b8a1 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -57,9 +57,6 @@ mod imp { use sys_common::thread_info; - // This is initialized in init() and only read from after - static mut PAGE_SIZE: usize = 0; - #[cfg(any(target_os = "linux", target_os = "android"))] unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize { #[repr(C)] @@ -102,12 +99,12 @@ mod imp { _data: *mut libc::c_void) { use sys_common::util::report_overflow; - let guard = thread_info::stack_guard().unwrap_or(0); + let guard = thread_info::stack_guard().unwrap_or(0..0); let addr = siginfo_si_addr(info); // If the faulting address is within the guard page, then we print a // message saying so and abort. - if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard { + if guard.start <= addr && addr < guard.end { report_overflow(); rtabort!("stack overflow"); } else { @@ -123,8 +120,6 @@ mod imp { static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); pub unsafe fn init() { - PAGE_SIZE = ::sys::os::page_size(); - let mut action: sigaction = mem::zeroed(); action.sa_flags = SA_SIGINFO | SA_ONSTACK; action.sa_sigaction = signal_handler as sighandler_t; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 525882c1e1e..72cdb9440b8 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -205,8 +205,10 @@ impl Drop for Thread { not(target_os = "solaris")))] #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } + use ops::Range; + pub type Guard = Range; + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } @@ -222,14 +224,43 @@ pub mod guard { use libc; use libc::mmap; use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; + use ops::Range; use sys::os; - #[cfg(any(target_os = "macos", - target_os = "bitrig", - target_os = "openbsd", - target_os = "solaris"))] + // This is initialized in init() and only read from after + static mut PAGE_SIZE: usize = 0; + + pub type Guard = Range; + + #[cfg(target_os = "solaris")] + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + let mut current_stack: libc::stack_t = ::mem::zeroed(); + assert_eq!(libc::stack_getbounds(&mut current_stack), 0); + Some(current_stack.ss_sp) + } + + #[cfg(target_os = "macos")] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - current().map(|s| s as *mut libc::c_void) + let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - + libc::pthread_get_stacksize_np(libc::pthread_self()); + Some(stackaddr as *mut libc::c_void) + } + + #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + let mut current_stack: libc::stack_t = ::mem::zeroed(); + assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), + &mut current_stack), 0); + + let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE; + let stackaddr = if libc::pthread_main_np() == 1 { + // main thread + current_stack.ss_sp as usize - current_stack.ss_size + extra + } else { + // new thread + current_stack.ss_sp as usize - current_stack.ss_size + }; + Some(stackaddr as *mut libc::c_void) } #[cfg(any(target_os = "android", target_os = "freebsd", @@ -253,8 +284,9 @@ pub mod guard { ret } - pub unsafe fn init() -> Option { - let psize = os::page_size(); + pub unsafe fn init() -> Option { + PAGE_SIZE = os::page_size(); + let mut stackaddr = get_stack_start()?; // Ensure stackaddr is page aligned! A parent process might @@ -263,9 +295,9 @@ pub mod guard { // stackaddr < stackaddr + stacksize, so if stackaddr is not // page-aligned, calculate the fix such that stackaddr < // new_page_aligned_stackaddr < stackaddr + stacksize - let remainder = (stackaddr as usize) % psize; + let remainder = (stackaddr as usize) % PAGE_SIZE; if remainder != 0 { - stackaddr = ((stackaddr as usize) + psize - remainder) + stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void; } @@ -280,60 +312,42 @@ pub mod guard { // Instead, we'll just note where we expect rlimit to start // faulting, so our handler can report "stack overflow", and // trust that the kernel's own stack guard will work. - Some(stackaddr as usize) + let stackaddr = stackaddr as usize; + Some(stackaddr - PAGE_SIZE..stackaddr) } else { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - let result = mmap(stackaddr, psize, PROT_NONE, + let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); if result != stackaddr || result == MAP_FAILED { panic!("failed to allocate a guard page"); } + let guardaddr = stackaddr as usize; let offset = if cfg!(target_os = "freebsd") { 2 } else { 1 }; - Some(stackaddr as usize + offset * psize) + Some(guardaddr..guardaddr + offset * PAGE_SIZE) } } - #[cfg(target_os = "solaris")] - pub unsafe fn current() -> Option { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::stack_getbounds(&mut current_stack), 0); - Some(current_stack.ss_sp as usize) - } - - #[cfg(target_os = "macos")] - pub unsafe fn current() -> Option { - Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self())) - } - - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] - pub unsafe fn current() -> Option { - let mut current_stack: libc::stack_t = ::mem::zeroed(); - assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), - &mut current_stack), 0); - - let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); - Some(if libc::pthread_main_np() == 1 { - // main thread - current_stack.ss_sp as usize - current_stack.ss_size + extra - } else { - // new thread - current_stack.ss_sp as usize - current_stack.ss_size - }) + #[cfg(any(target_os = "macos", + target_os = "bitrig", + target_os = "openbsd", + target_os = "solaris"))] + pub unsafe fn current() -> Option { + let stackaddr = get_stack_start()? as usize; + Some(stackaddr - PAGE_SIZE..stackaddr) } #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux", target_os = "netbsd", target_os = "l4re"))] - pub unsafe fn current() -> Option { + pub unsafe fn current() -> Option { let mut ret = None; let mut attr: libc::pthread_attr_t = ::mem::zeroed(); assert_eq!(libc::pthread_attr_init(&mut attr), 0); @@ -352,12 +366,23 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); + let stackaddr = stackaddr as usize; ret = if cfg!(target_os = "freebsd") { - Some(stackaddr as usize - guardsize) + // FIXME does freebsd really fault *below* the guard addr? + let guardaddr = stackaddr - guardsize; + Some(guardaddr - PAGE_SIZE..guardaddr) } else if cfg!(target_os = "netbsd") { - Some(stackaddr as usize) + Some(stackaddr - guardsize..stackaddr) + } else if cfg!(all(target_os = "linux", target_env = "gnu")) { + // glibc used to include the guard area within the stack, as noted in the BUGS + // section of `man pthread_attr_getguardsize`. This has been corrected starting + // with glibc 2.27, and in some distro backports, so the guard is now placed at the + // end (below) the stack. There's no easy way for us to know which we have at + // runtime, so we'll just match any fault in the range right above or below the + // stack base to call that fault a stack overflow. + Some(stackaddr - guardsize..stackaddr + guardsize) } else { - Some(stackaddr as usize + guardsize) + Some(stackaddr..stackaddr + guardsize) }; } assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 13980e0cc19..6a066509b49 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -43,6 +43,7 @@ impl Thread { } pub mod guard { - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } + pub type Guard = !; + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 74786d09285..43abfbb1f64 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -93,6 +93,7 @@ impl Thread { #[cfg_attr(test, allow(dead_code))] pub mod guard { - pub unsafe fn current() -> Option { None } - pub unsafe fn init() -> Option { None } + pub type Guard = !; + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } diff --git a/src/libstd/sys_common/thread_info.rs b/src/libstd/sys_common/thread_info.rs index 7970042b1d6..6a2b6742367 100644 --- a/src/libstd/sys_common/thread_info.rs +++ b/src/libstd/sys_common/thread_info.rs @@ -11,10 +11,11 @@ #![allow(dead_code)] // stack_guard isn't used right now on all platforms use cell::RefCell; +use sys::thread::guard::Guard; use thread::Thread; struct ThreadInfo { - stack_guard: Option, + stack_guard: Option, thread: Thread, } @@ -38,11 +39,11 @@ pub fn current_thread() -> Option { ThreadInfo::with(|info| info.thread.clone()) } -pub fn stack_guard() -> Option { - ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) +pub fn stack_guard() -> Option { + ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o) } -pub fn set(stack_guard: Option, thread: Thread) { +pub fn set(stack_guard: Option, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ stack_guard, -- cgit 1.4.1-3-g733a5 From e34c31bf02eb0f0ff4dd43ae72e0eae53f2ac519 Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 1 Feb 2018 18:35:51 +0000 Subject: Use constant for 180/π in to_degrees MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current `f32|f64.to_degrees` implementation uses a division to calculate 180/π, which causes a loss of precision. Using a constant is still not perfect (implementing a maximally-precise algorithm would come with a high performance cost), but improves precision with a minimal change. --- src/libcore/num/f32.rs | 4 +++- src/libcore/num/f64.rs | 3 +++ src/libstd/f32.rs | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 207df84d080..3586fa5442f 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -239,7 +239,9 @@ impl Float for f32 { /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f32 { - self * (180.0f32 / consts::PI) + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 } /// Converts to radians, assuming the number is in degrees. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 9206132e8b4..64c0d508b38 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -237,6 +237,9 @@ impl Float for f64 { /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f64 { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) self * (180.0f64 / consts::PI) } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 9810dede618..ecf68f29d6f 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1531,6 +1531,7 @@ mod tests { assert!(nan.to_degrees().is_nan()); assert_eq!(inf.to_degrees(), inf); assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); } #[test] -- cgit 1.4.1-3-g733a5 From b1b9edf5ae3c6a8a862e480174f9fefafeba7143 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Thu, 1 Feb 2018 20:18:33 -0500 Subject: This is what FileType on Windows should ideally be. --- src/libstd/sys/windows/fs.rs | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 165e1b0609b..001e7ceeb71 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -38,8 +38,9 @@ pub struct FileAttr { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum FileType { - Dir, File, SymlinkFile, SymlinkDir, ReparsePoint, MountPoint, +pub struct FileType { + attributes: c::DWORD, + reparse_tag: c::DWORD, } pub struct ReadDir { @@ -516,30 +517,28 @@ impl FilePermissions { impl FileType { fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType { - match (attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0, - attrs & c::FILE_ATTRIBUTE_REPARSE_POINT != 0, - reparse_tag) { - (false, false, _) => FileType::File, - (true, false, _) => FileType::Dir, - (false, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkFile, - (true, true, c::IO_REPARSE_TAG_SYMLINK) => FileType::SymlinkDir, - (true, true, c::IO_REPARSE_TAG_MOUNT_POINT) => FileType::MountPoint, - (_, true, _) => FileType::ReparsePoint, - // Note: if a _file_ has a reparse tag of the type IO_REPARSE_TAG_MOUNT_POINT it is - // invalid, as junctions always have to be dirs. We set the filetype to ReparsePoint - // to indicate it is something symlink-like, but not something you can follow. + FileType { + attributes: attrs, + reparse_tag: reparse_tag, } } - pub fn is_dir(&self) -> bool { *self == FileType::Dir } - pub fn is_file(&self) -> bool { *self == FileType::File } + pub fn is_dir(&self) -> bool { + self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 + } + pub fn is_file(&self) -> bool { + self.attributes & c::FILE_ATTRIBUTE_DIRECTORY == 0 + } pub fn is_symlink(&self) -> bool { - *self == FileType::SymlinkFile || - *self == FileType::SymlinkDir || - *self == FileType::MountPoint + self.is_reparse_point() && ( + self.reparse_tag == c::IO_REPARSE_TAG_SYMLINK || + self.reparse_tag == c::IO_REPARSE_TAG_MOUNT_POINT) } pub fn is_symlink_dir(&self) -> bool { - *self == FileType::SymlinkDir || *self == FileType::MountPoint + self.is_symlink() && self.is_dir() + } + pub fn is_reparse_point(&self) -> bool { + self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 } } -- cgit 1.4.1-3-g733a5 From dcf53c1590b741a16e92c7e5a306e923827ae301 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Thu, 1 Feb 2018 20:35:50 -0500 Subject: Rewrite remove_dir_all to be correct The fact that this had to be rewritten does not bode well --- src/libstd/sys/windows/fs.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 001e7ceeb71..87a09925313 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -611,9 +611,11 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { let child = child?; let child_type = child.file_type()?; if child_type.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else if child_type.is_symlink_dir() { - rmdir(&child.path())?; + if child_type.is_reparse_point() { + rmdir(&child.path())?; + } else { + remove_dir_all_recursive(&child.path())?; + } } else { unlink(&child.path())?; } -- cgit 1.4.1-3-g733a5 From 259b0329d42ea9ce971c0c8c9ff72f8496a73b9e Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Thu, 1 Feb 2018 20:42:31 -0500 Subject: This internal only method is no longer needed. --- src/libstd/sys/windows/fs.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 87a09925313..a49c3569b02 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -534,9 +534,6 @@ impl FileType { self.reparse_tag == c::IO_REPARSE_TAG_SYMLINK || self.reparse_tag == c::IO_REPARSE_TAG_MOUNT_POINT) } - pub fn is_symlink_dir(&self) -> bool { - self.is_symlink() && self.is_dir() - } pub fn is_reparse_point(&self) -> bool { self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 } -- cgit 1.4.1-3-g733a5 From 7d296c4843785f64a4246213375b21c1ab1e7462 Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Fri, 2 Feb 2018 11:17:48 -0800 Subject: Add Condvar APIs not susceptible to spurious wake Provide wait_until and wait_timeout_until helper wrappers that aren't susceptible to spurious wake. --- src/libstd/sync/condvar.rs | 207 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 56402175817..1e5beaaa342 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -14,7 +14,7 @@ use sync::{mutex, MutexGuard, PoisonError}; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; use sys_common::poison::{self, LockResult}; -use time::Duration; +use time::{Duration, Instant}; /// A type indicating whether a timed wait on a condition variable returned /// due to a time out or not. @@ -219,6 +219,61 @@ impl Condvar { } } + /// Blocks the current thread until this condition variable receives a + /// notification and the required condition is met. There are no spurious + /// wakeups when calling this. + /// + /// This function will atomically unlock the mutex specified (represented by + /// `guard`) and block the current thread. This means that any calls + /// to [`notify_one`] or [`notify_all`] which happen logically after the + /// mutex is unlocked are candidates to wake this thread up. When this + /// function call returns, the lock specified will have been re-acquired. + /// + /// # Errors + /// + /// This function will return an error if the mutex being waited on is + /// poisoned when this thread re-acquires the lock. For more information, + /// see information about [poisoning] on the [`Mutex`] type. + /// + /// [`notify_one`]: #method.notify_one + /// [`notify_all`]: #method.notify_all + /// [poisoning]: ../sync/struct.Mutex.html#poisoning + /// [`Mutex`]: ../sync/struct.Mutex.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Mutex, Condvar}; + /// use std::thread; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = pair.clone(); + /// + /// thread::spawn(move|| { + /// let &(ref lock, ref cvar) = &*pair2; + /// let mut started = lock.lock().unwrap(); + /// *started = true; + /// // We notify the condvar that the value has changed. + /// cvar.notify_one(); + /// }); + /// + /// // Wait for the thread to start up. + /// let &(ref lock, ref cvar) = &*pair; + /// // As long as the value inside the `Mutex` is false, we wait. + /// cvar.wait_until(lock.lock().unwrap(), |ref started| { started }); + /// ``` + #[stable(feature = "wait_until", since = "1.24")] + pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, + mut condition: F) + -> LockResult> + where F: FnMut(&T) -> bool { + while !condition(&*guard) { + guard = self.wait(guard)?; + } + Ok(guard) + } + + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// @@ -293,7 +348,15 @@ impl Condvar { /// /// Note that the best effort is made to ensure that the time waited is /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. + /// the system time. This function is susceptible to spurious wakeups. + /// Condition variables normally have a boolean predicate associated with + /// them, and the predicate must always be checked each time this function + /// returns to protect against spurious wakeups. Additionally, it is + /// typically desirable for the time-out to not exceed some duration in + /// spite of spurious wakes, thus the sleep-duration is decremented by the + /// amount slept. Alternatively, use the `wait_timeout_until` method + /// to wait until a condition is met with a total time-out regardless + /// of spurious wakes. /// /// The returned [`WaitTimeoutResult`] value indicates if the timeout is /// known to have elapsed. @@ -302,6 +365,7 @@ impl Condvar { /// returns, regardless of whether the timeout elapsed or not. /// /// [`wait`]: #method.wait + /// [`wait_timeout_until`]: #method.wait_timeout_until /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html /// /// # Examples @@ -353,6 +417,76 @@ impl Condvar { } } + /// Waits on this condition variable for a notification, timing out after a + /// specified duration. + /// + /// The semantics of this function are equivalent to [`wait_until`] except + /// that the thread will be blocked for roughly no longer than `dur`. This + /// method should not be used for precise timing due to anomalies such as + /// preemption or platform differences that may not cause the maximum + /// amount of time waited to be precisely `dur`. + /// + /// Note that the best effort is made to ensure that the time waited is + /// measured with a monotonic clock, and not affected by the changes made to + /// the system time. + /// + /// The returned [`WaitTimeoutResult`] value indicates if the timeout is + /// known to have elapsed without the condition being met. + /// + /// Like [`wait_until`], the lock specified will be re-acquired when this + /// function returns, regardless of whether the timeout elapsed or not. + /// + /// [`wait_until`]: #method.wait_until + /// [`wait_timeout`]: #method.wait_timeout + /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Mutex, Condvar}; + /// use std::thread; + /// use std::time::Duration; + /// + /// let pair = Arc::new((Mutex::new(false), Condvar::new())); + /// let pair2 = pair.clone(); + /// + /// thread::spawn(move|| { + /// let &(ref lock, ref cvar) = &*pair2; + /// let mut started = lock.lock().unwrap(); + /// *started = true; + /// // We notify the condvar that the value has changed. + /// cvar.notify_one(); + /// }); + /// + /// // wait for the thread to start up + /// let &(ref lock, ref cvar) = &*pair; + /// let result = cvar.wait_timeout_until(lock, Duration::from_millis(100), |started| { + /// started + /// }).unwrap(); + /// if result.1.timed_out() { + /// // timed-out without the condition ever evaluating to true. + /// } + /// // access the locked mutex via result.0 + /// ``` + #[stable(feature = "wait_timeout_until", since = "1.24")] + pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, + mut dur: Duration, mut condition: F) + -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> + where F: FnMut(&T) -> bool { + let timed_out = Duration::new(0, 0); + loop { + if !condition(&*guard) { + return Ok((guard, WaitTimeoutResult(false))); + } else if dur == timed_out { + return Ok((guard, WaitTimeoutResult(false))); + } + let wait_timer = Instant::now(); + let wait_result = self.wait_timeout(guard, dur)?; + dur = dur.checked_sub(wait_timer.elapsed()).unwrap_or(timed_out); + guard = wait_result.0; + } + } + /// Wakes up one blocked thread on this condvar. /// /// If there is a blocked thread on this condition variable, then it will @@ -546,6 +680,29 @@ mod tests { } } + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_until() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move|| { + let &(ref lock, ref cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let &(ref lock, ref cvar) = &*pair; + let guard = cvar.wait_until(lock.lock().unwrap(), |started| { + started + }); + assert!(*guard); + } + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_wait() { @@ -565,6 +722,52 @@ mod tests { } } + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_timeout_until_wait() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), || { false }).unwrap(); + // no spurious wakeups. ensure it timed-out + assert!(wait.timed_out()); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_timeout_until_instant_satisfy() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), || { true }).unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_timeout_until_wake() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair_copy = pair.clone(); + + let g = m.lock().unwrap(); + let t = thread::spawn(move || { + let &(ref lock, ref cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + thread::sleep(Duration::from_millis(1)); + started = true; + cvar.notify_one(); + }); + let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |¬ified| { + notified + }).unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); + assert!(*g2); + } + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_wake() { -- cgit 1.4.1-3-g733a5 From 404e1a67007a254ab35e4fe8a8650e9335590a76 Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Fri, 2 Feb 2018 11:52:16 -0800 Subject: Fix typo --- src/libstd/sync/condvar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 1e5beaaa342..c58f8fd2990 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -478,7 +478,7 @@ impl Condvar { if !condition(&*guard) { return Ok((guard, WaitTimeoutResult(false))); } else if dur == timed_out { - return Ok((guard, WaitTimeoutResult(false))); + return Ok((guard, WaitTimeoutResult(true))); } let wait_timer = Instant::now(); let wait_result = self.wait_timeout(guard, dur)?; -- cgit 1.4.1-3-g733a5 From e72bd6df5398dd7ee02c6057b861537c49649b4e Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Fri, 2 Feb 2018 12:07:16 -0800 Subject: Review response Make condition closure accept mut T&. Clarify spurious wakeup documentation. Cleanup doc example code. --- src/libstd/sync/condvar.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index c58f8fd2990..76b68fc4f4f 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -220,8 +220,9 @@ impl Condvar { } /// Blocks the current thread until this condition variable receives a - /// notification and the required condition is met. There are no spurious - /// wakeups when calling this. + /// notification and the required condition is met. Spurious wakeups are + /// ignored and this function will only return once the condition has been + /// met. /// /// This function will atomically unlock the mutex specified (represented by /// `guard`) and block the current thread. This means that any calls @@ -260,14 +261,14 @@ impl Condvar { /// // Wait for the thread to start up. /// let &(ref lock, ref cvar) = &*pair; /// // As long as the value inside the `Mutex` is false, we wait. - /// cvar.wait_until(lock.lock().unwrap(), |ref started| { started }); + /// cvar.wait_until(lock.lock().unwrap(), |started| { started }); /// ``` #[stable(feature = "wait_until", since = "1.24")] pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, mut condition: F) -> LockResult> - where F: FnMut(&T) -> bool { - while !condition(&*guard) { + where F: FnMut(&mut T) -> bool { + while !condition(&mut *guard) { guard = self.wait(guard)?; } Ok(guard) @@ -418,7 +419,8 @@ impl Condvar { } /// Waits on this condition variable for a notification, timing out after a - /// specified duration. + /// specified duration. Spurious wakes will not cause this function to + /// return. /// /// The semantics of this function are equivalent to [`wait_until`] except /// that the thread will be blocked for roughly no longer than `dur`. This @@ -472,10 +474,10 @@ impl Condvar { pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, mut dur: Duration, mut condition: F) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> - where F: FnMut(&T) -> bool { + where F: FnMut(&mut T) -> bool { let timed_out = Duration::new(0, 0); loop { - if !condition(&*guard) { + if !condition(&mut *guard) { return Ok((guard, WaitTimeoutResult(false))); } else if dur == timed_out { return Ok((guard, WaitTimeoutResult(true))); -- cgit 1.4.1-3-g733a5 From f4c83693f9e2445b441dfcf43838697d25d1a11f Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Sat, 3 Feb 2018 01:45:58 -0500 Subject: Go back to files directories and symlinks being mutually exclusive Be smarter about what a symlink is however --- src/libstd/sys/windows/fs.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index a49c3569b02..512c9cb838c 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -522,21 +522,27 @@ impl FileType { reparse_tag: reparse_tag, } } - pub fn is_dir(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 + !self.is_symlink() && self.is_directory() } pub fn is_file(&self) -> bool { - self.attributes & c::FILE_ATTRIBUTE_DIRECTORY == 0 + !self.is_symlink() && !self.is_directory() } pub fn is_symlink(&self) -> bool { - self.is_reparse_point() && ( - self.reparse_tag == c::IO_REPARSE_TAG_SYMLINK || - self.reparse_tag == c::IO_REPARSE_TAG_MOUNT_POINT) + self.is_reparse_point() && self.is_reparse_tag_name_surrogate() + } + pub fn is_symlink_dir(&self) -> bool { + self.is_symlink() && self.is_directory() + } + fn is_directory(&self) -> bool { + self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 } - pub fn is_reparse_point(&self) -> bool { + fn is_reparse_point(&self) -> bool { self.attributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 } + fn is_reparse_tag_name_surrogate(&self) -> bool { + self.reparse_tag & 0x20000000 != 0 + } } impl DirBuilder { @@ -607,12 +613,10 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { for child in readdir(path)? { let child = child?; let child_type = child.file_type()?; - if child_type.is_dir() { - if child_type.is_reparse_point() { - rmdir(&child.path())?; - } else { - remove_dir_all_recursive(&child.path())?; - } + if child_type.is_symlink_dir() { + rmdir(&child.path())?; + } else if child_type.is_dir() { + remove_dir_all_recursive(&child.path())?; } else { unlink(&child.path())?; } -- cgit 1.4.1-3-g733a5 From c42d76d3c80b4938e26e628706363b677fde6ca1 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Sat, 3 Feb 2018 01:52:04 -0500 Subject: Somehow this function got flipped around Unflip it --- src/libstd/sys/windows/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 512c9cb838c..7e3b16558d4 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -613,10 +613,10 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { for child in readdir(path)? { let child = child?; let child_type = child.file_type()?; - if child_type.is_symlink_dir() { - rmdir(&child.path())?; - } else if child_type.is_dir() { + if child_type.is_dir() { remove_dir_all_recursive(&child.path())?; + } else if child_type.is_symlink_dir() { + rmdir(&child.path())?; } else { unlink(&child.path())?; } -- cgit 1.4.1-3-g733a5 From d597da32672805644b6dc76cfffeca6b8c4d8e62 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 1 Feb 2018 23:36:33 -0500 Subject: Clarify shared file handler behavior of File::try_clone. Fixes https://github.com/rust-lang/rust/issues/46578. --- src/libstd/fs.rs | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index d1f3ccbd2c6..594c9d0ff5a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -482,20 +482,42 @@ impl File { self.inner.file_attr().map(Metadata) } - /// Creates a new independently owned handle to the underlying file. - /// - /// The returned `File` is a reference to the same state that this object - /// references. Both handles will read and write with the same cursor - /// position. + /// Create a new `File` instance that shares the same underlying file handle + /// as the existing `File` instance. Reads, writes, and seeks will affect + /// both `File` instances simultaneously. /// /// # Examples /// + /// Create two handles for a file named `foo.txt`: + /// /// ```no_run /// use std::fs::File; /// /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let file_copy = f.try_clone()?; + /// let mut file = File::open("foo.txt")?; + /// let file_copy = file.try_clone()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create + /// two handles, seek one of them, and read the remaining bytes from the + /// other handle: + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::SeekFrom; + /// use std::io::prelude::*; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut file_copy = file.try_clone()?; + /// + /// file.seek(SeekFrom::Start(3))?; + /// + /// let mut contents = vec![]; + /// file_copy.read_to_end(&mut contents)?; + /// assert_eq!(contents, b"def\n"); /// # Ok(()) /// # } /// ``` -- cgit 1.4.1-3-g733a5 From f168700ba6257979dd90b20e0149e1ccf53590f0 Mon Sep 17 00:00:00 2001 From: Jay Strict Date: Sun, 4 Feb 2018 16:24:18 +0100 Subject: Remove 'the this' in doc comments. --- src/librustc/mir/mod.rs | 2 +- src/libstd/fs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 3b644aa13f3..c0feb8ad020 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1825,7 +1825,7 @@ pub struct Location { /// the location is within this block pub block: BasicBlock, - /// the location is the start of the this statement; or, if `statement_index` + /// the location is the start of the statement; or, if `statement_index` /// == num-statements, then the start of the terminator. pub statement_index: usize, } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index d1f3ccbd2c6..9bf90d40256 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1001,7 +1001,7 @@ impl Metadata { self.0.accessed().map(FromInner::from_inner) } - /// Returns the creation time listed in the this metadata. + /// Returns the creation time listed in this metadata. /// /// The returned value corresponds to the `birthtime` field of `stat` on /// Unix platforms and the `ftCreationTime` field on Windows platforms. -- cgit 1.4.1-3-g733a5 From b439632a759447eb56a0190f6c838934bad1e3c7 Mon Sep 17 00:00:00 2001 From: panicbit Date: Sun, 4 Feb 2018 20:40:39 +0100 Subject: Unimplement Send/Sync for ::env::{Args,ArgsOs,Vars,VarsOs} --- src/libstd/env.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 27bf326631f..c4946b6b282 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -723,6 +723,12 @@ pub fn args_os() -> ArgsOs { ArgsOs { inner: sys::args::args() } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for Args {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for Args {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; @@ -754,6 +760,12 @@ impl fmt::Debug for Args { } } +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Send for ArgsOs {} + +#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +impl !Sync for ArgsOs {} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; -- cgit 1.4.1-3-g733a5 From 95e4dc2ad143c91d0930ea28634e6f5c54ac0812 Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Mon, 5 Feb 2018 15:11:00 -0800 Subject: Simplify wait_timeout_until & fix condition typo --- src/libstd/sync/condvar.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 76b68fc4f4f..e6a3388aa25 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -475,17 +475,16 @@ impl Condvar { mut dur: Duration, mut condition: F) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> where F: FnMut(&mut T) -> bool { - let timed_out = Duration::new(0, 0); + let start = Instant::now(); loop { - if !condition(&mut *guard) { + if condition(&mut *guard) { return Ok((guard, WaitTimeoutResult(false))); - } else if dur == timed_out { - return Ok((guard, WaitTimeoutResult(true))); } - let wait_timer = Instant::now(); - let wait_result = self.wait_timeout(guard, dur)?; - dur = dur.checked_sub(wait_timer.elapsed()).unwrap_or(timed_out); - guard = wait_result.0; + let timeout = match dur.checked_sub(start.elapsed()) { + Some(timeout) => timeout, + None => return Ok((guard, WaitTimeoutResult(true))), + } + guard = self.wait_timeout(guard, dur)?.0; } } -- cgit 1.4.1-3-g733a5 From fefd5e9bbc150273faf2ac0c4dff8e0e8a098393 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 6 Feb 2018 09:26:15 -0600 Subject: fix docs link --- src/libstd/os/raw/uint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/os/raw/uint.md b/src/libstd/os/raw/uint.md index 1e710f804c4..6f7013a8ac1 100644 --- a/src/libstd/os/raw/uint.md +++ b/src/libstd/os/raw/uint.md @@ -1,6 +1,6 @@ Equivalent to C's `unsigned int` type. -This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example. +This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example. [`int`]: type.c_int.html [`u32`]: ../../primitive.u32.html -- cgit 1.4.1-3-g733a5 From 9bc59865f1042b8c6f3a7c69f0d2643b37a41d75 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 6 Feb 2018 08:56:27 +0000 Subject: 38880 don't compute hash when searching an empty HashMap This addresses issue #38880 --- src/libstd/collections/hash/map.rs | 40 +++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 82a687ae5e4..74c4382f16a 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -397,9 +397,21 @@ pub struct HashMap { resize_policy: DefaultResizePolicy, } +/// Search for a pre-hashed key when the hash map is known to be non-empty. +#[inline] +fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) + -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool +{ + // Do not check the capacity as an extra branch could slow the lookup. + search_hashed_body(table, hash, is_match) +} + /// Search for a pre-hashed key. +/// If you don't already know the hash, use search or search_mut instead #[inline] -fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry +fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool { @@ -410,6 +422,16 @@ fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> Inter return InternalEntry::TableIsEmpty; } + search_hashed_body(table, hash, is_match) +} + +/// The body of the search_hashed[_nonempty] functions +#[inline] +fn search_hashed_body(table: M, hash: SafeHash, mut is_match: F) + -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool +{ let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; @@ -550,8 +572,12 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - let hash = self.make_hash(q); - search_hashed(&self.table, hash, |k| q.eq(k.borrow())) + if self.table.capacity() != 0 { + let hash = self.make_hash(q); + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + } else { + InternalEntry::TableIsEmpty + } } #[inline] @@ -559,8 +585,12 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - let hash = self.make_hash(q); - search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) + if self.table.capacity() != 0 { + let hash = self.make_hash(q); + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + } else { + InternalEntry::TableIsEmpty + } } // The caller should ensure that invariants by Robin Hood Hashing hold -- cgit 1.4.1-3-g733a5 From dcdd2c42d3c7f6125583bcdf0c5ed7e1ef7086db Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 6 Feb 2018 14:16:54 +0000 Subject: 38880 use search_mut function rather than search_hashed --- src/libstd/collections/hash/map.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 74c4382f16a..04c9f617d01 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1039,9 +1039,7 @@ impl HashMap pub fn entry(&mut self, key: K) -> Entry { // Gotta resize now. self.reserve(1); - let hash = self.make_hash(&key); - search_hashed(&mut self.table, hash, |q| q.eq(&key)) - .into_entry(key).expect("unreachable") + self.search_mut(&key).into_entry(key).expect("unreachable") } /// Returns the number of elements in the map. -- cgit 1.4.1-3-g733a5 From 96eed862a08f0ee1d234f4f83419dd46fe58ccef Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 09:31:22 -0500 Subject: libcore/libstd: fix commas in macro_rules! macros BREAKING CHANGE: (or perhaps, *bugfix*) In #![no_std] applications, the following calls to `panic!` used to behave differently; they now behave the same. Old behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{" New behavior: panic!("{{"); // panics with "{{" panic!("{{",); // panics with "{{" This only affects calls to `panic!` (and by proxy `assert` and `debug_assert`) with a single string literal followed by a trailing comma, and only in `#![no_std]` applications. --- src/libcore/macros.rs | 17 +++++++++++++++-- src/libstd/macros.rs | 3 +++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f00128a8147..c12edaf0b29 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -19,7 +19,10 @@ macro_rules! panic { ($msg:expr) => ({ $crate::panicking::panic(&($msg, file!(), line!(), __rust_unstable_column!())) }); - ($fmt:expr, $($arg:tt)*) => ({ + ($msg:expr,) => ( + panic!($msg) + ); + ($fmt:expr, $($arg:tt)+) => ({ $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &(file!(), line!(), __rust_unstable_column!())) }); @@ -79,6 +82,9 @@ macro_rules! assert { panic!(concat!("assertion failed: ", stringify!($cond))) } ); + ($cond:expr,) => ( + assert!($cond) + ); ($cond:expr, $($arg:tt)+) => ( if !$cond { panic!($($arg)+) @@ -359,7 +365,8 @@ macro_rules! try { $crate::result::Result::Err(err) => { return $crate::result::Result::Err($crate::convert::From::from(err)) } - }) + }); + ($expr:expr,) => (try!($expr)); } /// Write formatted data into a buffer. @@ -456,6 +463,9 @@ macro_rules! writeln { ($dst:expr) => ( write!($dst, "\n") ); + ($dst:expr,) => ( + writeln!($dst) + ); ($dst:expr, $fmt:expr) => ( write!($dst, concat!($fmt, "\n")) ); @@ -524,6 +534,9 @@ macro_rules! unreachable { ($msg:expr) => ({ unreachable!("{}", $msg) }); + ($msg:expr,) => ({ + unreachable!($msg) + }); ($fmt:expr, $($arg:tt)*) => ({ panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) }); diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index f058b1caef5..5a01674a3d0 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -68,6 +68,9 @@ macro_rules! panic { ($msg:expr) => ({ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!())) }); + ($msg:expr,) => ({ + panic!($msg) + }); ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), &(file!(), line!(), __rust_unstable_column!())) -- cgit 1.4.1-3-g733a5 From b7c6dc6c0600eaee4d149c63dd3cf1faa00a098f Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 7 Feb 2018 10:24:34 -0500 Subject: update the builtin macro doc stubs --- src/libcore/macros.rs | 25 ++++++++++++++++++++----- src/libstd/macros.rs | 25 ++++++++++++++++++++----- 2 files changed, 40 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c12edaf0b29..19bbf85cadb 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -616,7 +616,10 @@ mod builtin { #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] #[cfg(dox)] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -652,7 +655,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -728,7 +734,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -738,7 +747,10 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -768,5 +780,8 @@ mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] #[cfg(dox)] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 5a01674a3d0..a18c811d196 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -315,7 +315,10 @@ pub mod builtin { /// ``` #[stable(feature = "compile_error_macro", since = "1.20.0")] #[macro_export] - macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) } + macro_rules! compile_error { + ($msg:expr) => ({ /* compiler built-in */ }); + ($msg:expr,) => ({ /* compiler built-in */ }); + } /// The core macro for formatted string creation & output. /// @@ -403,7 +406,10 @@ pub mod builtin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + macro_rules! option_env { + ($name:expr) => ({ /* compiler built-in */ }); + ($name:expr,) => ({ /* compiler built-in */ }); + } /// Concatenate identifiers into one identifier. /// @@ -583,7 +589,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_str { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Includes a file as a reference to a byte array. /// @@ -617,7 +626,10 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include_bytes { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } /// Expands to a string that represents the current module path. /// @@ -703,7 +715,10 @@ pub mod builtin { /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] - macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } + macro_rules! include { + ($file:expr) => ({ /* compiler built-in */ }); + ($file:expr,) => ({ /* compiler built-in */ }); + } } /// A macro for defining #[cfg] if-else statements. -- cgit 1.4.1-3-g733a5 From 45d5a420ada9c11f61347fd4c63c7f0234adaea7 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 10 Feb 2018 21:20:42 +0000 Subject: Correct a few stability attributes --- src/libcore/num/mod.rs | 6 +++--- src/libcore/ptr.rs | 4 ++-- src/libcore/time.rs | 4 ++-- src/libstd/io/cursor.rs | 2 +- src/libstd/path.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c77..21d4a486b98 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2881,7 +2881,7 @@ pub enum FpCategory { issue = "32110")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.24.0")] + #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. @@ -2947,10 +2947,10 @@ pub trait Float: Sized { fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.24.0")] + #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 3d84e910fe6..b266771b818 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2573,7 +2573,7 @@ impl Clone for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] impl Copy for NonNull { } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "coerce_unsized", issue = "27732")] impl CoerceUnsized> for NonNull where T: Unsize { } #[stable(feature = "nonnull", since = "1.25.0")] @@ -2621,7 +2621,7 @@ impl hash::Hash for NonNull { } } -#[stable(feature = "nonnull", since = "1.25.0")] +#[unstable(feature = "ptr_internals", issue = "0")] impl From> for NonNull { fn from(unique: Unique) -> Self { NonNull { pointer: unique.pointer } diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 1a0208d2f25..b8d0719b9b9 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "duration_core", since = "1.24.0")] +#![stable(feature = "duration_core", since = "1.25.0")] //! Temporal quantification. //! @@ -58,7 +58,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// /// let ten_millis = Duration::from_millis(10); /// ``` -#[stable(feature = "duration_core", since = "1.24.0")] +#[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] pub struct Duration { secs: u64, diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index c8447707d5b..76bcb5fedc9 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -296,7 +296,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> { fn flush(&mut self) -> io::Result<()> { Ok(()) } } -#[unstable(feature = "cursor_mut_vec", issue = "30132")] +#[stable(feature = "cursor_mut_vec", since = "1.25.0")] impl<'a> Write for Cursor<&'a mut Vec> { fn write(&mut self, buf: &[u8]) -> io::Result { vec_write(&mut self.pos, self.inner, buf) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ed102c2949e..e03a182653e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -576,7 +576,7 @@ impl<'a> AsRef for Component<'a> { } } -#[stable(feature = "path_component_asref", since = "1.24.0")] +#[stable(feature = "path_component_asref", since = "1.25.0")] impl<'a> AsRef for Component<'a> { fn as_ref(&self) -> &Path { self.as_os_str().as_ref() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9c6520cd874..f8dbc4d0f45 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -538,7 +538,7 @@ declare_features! ( // instead of just the platforms on which it is the C ABI (accepted, abi_sysv64, "1.24.0", Some(36167)), // Allows `repr(align(16))` struct attribute (RFC 1358) - (accepted, repr_align, "1.24.0", Some(33626)), + (accepted, repr_align, "1.25.0", Some(33626)), // allow '|' at beginning of match arms (RFC 1925) (accepted, match_beginning_vert, "1.25.0", Some(44101)), // Nested groups in `use` (RFC 2128) -- cgit 1.4.1-3-g733a5 From 161e8ffda79d25ef7a570bf0c0d884201267c6cb Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Sun, 11 Feb 2018 00:56:24 +0100 Subject: typo: correct endianess to endianness (this also changes function names!) --- src/librustc_mir/interpret/memory.rs | 32 ++++++++++++++++---------------- src/libstd/f32.rs | 2 +- src/libstd/f64.rs | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 3a28eae2d1c..7cc4ba84895 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -238,7 +238,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { self.tcx.data_layout.pointer_size.bytes() } - pub fn endianess(&self) -> layout::Endian { + pub fn endianness(&self) -> layout::Endian { self.tcx.data_layout.endian } @@ -722,7 +722,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?; // Undef check happens *after* we established that the alignment is correct. // We must not return Ok() for unaligned pointers! @@ -731,9 +731,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } // Now we do the actual reading let bytes = if signed { - read_target_int(endianess, bytes).unwrap() as u128 + read_target_int(endianness, bytes).unwrap() as u128 } else { - read_target_uint(endianess, bytes).unwrap() + read_target_uint(endianness, bytes).unwrap() }; // See if we got a pointer if size != self.pointer_size() { @@ -756,7 +756,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { - let endianess = self.endianess(); + let endianness = self.endianness(); let bytes = match val { PrimVal::Ptr(val) => { @@ -788,9 +788,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { let align = self.int_align(size); let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?; if signed { - write_target_int(endianess, dst, bytes as i128).unwrap(); + write_target_int(endianness, dst, bytes as i128).unwrap(); } else { - write_target_uint(endianess, dst, bytes).unwrap(); + write_target_uint(endianness, dst, bytes).unwrap(); } } @@ -941,41 +941,41 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } //////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianess +// Methods to access integers in the target endianness //////////////////////////////////////////////////////////////////////////////// fn write_target_uint( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: u128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_uint128::(data, len), layout::Endian::Big => target.write_uint128::(data, len), } } fn write_target_int( - endianess: layout::Endian, + endianness: layout::Endian, mut target: &mut [u8], data: i128, ) -> Result<(), io::Error> { let len = target.len(); - match endianess { + match endianness { layout::Endian::Little => target.write_int128::(data, len), layout::Endian::Big => target.write_int128::(data, len), } } -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_uint128::(source.len()), layout::Endian::Big => source.read_uint128::(source.len()), } } -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { +fn read_target_int(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { layout::Endian::Little => source.read_int128::(source.len()), layout::Endian::Big => source.read_int128::(source.len()), } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ecf68f29d6f..a760922115a 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1023,7 +1023,7 @@ impl f32 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 29ba7d0dac6..6f34f176a97 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -978,7 +978,7 @@ impl f64 { /// This is currently identical to `transmute::(v)` on all platforms. /// It turns out this is incredibly portable, for two reasons: /// - /// * Floats and Ints have the same endianess on all supported platforms. + /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE-754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE-754, how -- cgit 1.4.1-3-g733a5 From 9269e83b37e8e5fd9cef12255fafbc6db6220035 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Sun, 11 Feb 2018 13:40:46 -0500 Subject: Add an unstable FileTypeExt extension trait for Windows --- src/libstd/sys/windows/ext/fs.rs | 18 ++++++++++++++++++ src/libstd/sys/windows/fs.rs | 3 +++ 2 files changed, 21 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index 24c41046f26..38bf4cca851 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -445,6 +445,24 @@ impl MetadataExt for Metadata { fn file_size(&self) -> u64 { self.as_inner().size() } } +/// Add support for the Windows specific fact that a symbolic link knows whether it is a file +/// or directory. +#[unstable(feature = "windows_file_type_ext", issue = "0")] +pub trait FileTypeExt { + /// Returns whether this file type is a symbolic link that is also a directory. + #[unstable(feature = "windows_file_type_ext", issue = "0")] + fn is_symlink_dir(&self) -> bool; + /// Returns whether this file type is a symbolic link that is also a file. + #[unstable(feature = "windows_file_type_ext", issue = "0")] + fn is_symlink_file(&self) -> bool; +} + +#[unstable(feature = "windows_file_type_ext", issue = "0")] +impl FileTypeExt for fs::FileType { + fn is_symlink_dir(&self) -> bool { self.as_inner().is_symlink_dir() } + fn is_symlink_file(&self) -> bool { self.as_inner().is_symlink_file() } +} + /// Creates a new file symbolic link on the filesystem. /// /// The `dst` path will be a file symbolic link pointing to the `src` diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 7e3b16558d4..082d4689c7b 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -534,6 +534,9 @@ impl FileType { pub fn is_symlink_dir(&self) -> bool { self.is_symlink() && self.is_directory() } + pub fn is_symlink_file(&self) -> bool { + self.is_symlink() && !self.is_directory() + } fn is_directory(&self) -> bool { self.attributes & c::FILE_ATTRIBUTE_DIRECTORY != 0 } -- cgit 1.4.1-3-g733a5 From 9931583468c197fe8b3c9e15abb793457134757f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 11 Feb 2018 22:08:32 +0100 Subject: Make primitive types docs relevant --- src/libcore/num/mod.rs | 1955 ++++++++++++++++++++++-------------------- src/libstd/primitive_docs.rs | 48 -- 2 files changed, 1017 insertions(+), 986 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 1fae88b9c77..3ad52370526 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -96,132 +96,151 @@ pub mod dec2flt; pub mod bignum; pub mod diy_float; +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr) => { - /// Returns the smallest value that can be represented by this integer type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(i8::min_value(), -128); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn min_value() -> Self { - !0 ^ ((!0 as $UnsignedT) >> 1) as Self + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr) => { + doc_comment! { + concat!("Returns the smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::min_value(), ", stringify!($Min), "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn min_value() -> Self { + !0 ^ ((!0 as $UnsignedT) >> 1) as Self + } } - /// Returns the largest value that can be represented by this integer type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(i8::max_value(), 127); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn max_value() -> Self { - !Self::min_value() + doc_comment! { + concat!("Returns the largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::max_value(), ", stringify!($Max), "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn max_value() -> Self { + !Self::min_value() + } } - /// Converts a string slice in a given base to an integer. - /// - /// The string is expected to be an optional `+` or `-` sign - /// followed by digits. - /// Leading and trailing whitespace represent an error. - /// Digits are a subset of these characters, depending on `radix`: - /// - /// * `0-9` - /// * `a-z` - /// * `A-Z` - /// - /// # Panics - /// - /// This function panics if `radix` is not in the range from 2 to 36. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(i32::from_str_radix("A", 16), Ok(10)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` or `-` sign followed by digits. +Leading and trailing whitespace represent an error. Digits are a subset of these characters, +depending on `radix`: + + * `0-9` + * `a-z` + * `a-z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10)); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } } - /// Returns the number of ones in the binary representation of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -0b1000_0000i8; - /// - /// assert_eq!(n.count_ones(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. - /// Returns the number of zeros in the binary representation of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -0b1000_0000i8; - /// - /// assert_eq!(n.count_zeros(), 7); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn count_zeros(self) -> u32 { - (!self).count_ones() +# Examples + +Basic usage: + +``` +let n = -0b1000_0000", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 1); +``` +"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } - /// Returns the number of leading zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -1i16; - /// - /// assert_eq!(n.leading_zeros(), 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = -0b1000_0000", stringify!($SelfT), "; + +assert_eq!(n.count_zeros(), 7); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn count_zeros(self) -> u32 { + (!self).count_ones() + } } - /// Returns the number of trailing zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = -4i8; - /// - /// assert_eq!(n.trailing_zeros(), 2); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_zeros(), 0); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn leading_zeros(self) -> u32 { + (self as $UnsignedT).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +let n = -4", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 2); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn trailing_zeros(self) -> u32 { + (self as $UnsignedT).trailing_zeros() + } } /// Shifts the bits to the left by a specified amount, `n`, @@ -288,947 +307,1007 @@ macro_rules! int_impl { (self as $UnsignedT).swap_bytes() as Self } - /// Converts an integer from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(i64::from_be(n), n) - /// } else { - /// assert_eq!(i64::from_be(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn from_be(x: Self) -> Self { + if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + } } - /// Converts an integer from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(i64::from_le(n), n) - /// } else { - /// assert_eq!(i64::from_le(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn from_le(x: Self) -> Self { + if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + } } - /// Converts `self` to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_be(), n) - /// } else { - /// assert_eq!(n.to_be(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_be(self) -> Self { // or not to be? + if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + } } - /// Converts `self` to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let n = 0x0123456789ABCDEFi64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_le(), n) - /// } else { - /// assert_eq!(n.to_le(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +let n = 0xA1", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +} +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_le(self) -> Self { + if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + } } - /// Checked integer addition. Computes `self + rhs`, returning `None` - /// if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(7i16.checked_add(32760), Some(32767)); - /// assert_eq!(8i16.checked_add(32760), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if b {None} else {Some(a)} - } + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. - /// Checked integer subtraction. Computes `self - rhs`, returning - /// `None` if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-127i8).checked_sub(1), Some(-128)); - /// assert_eq!((-128i8).checked_sub(1), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if b {None} else {Some(a)} - } +# Examples - /// Checked integer multiplication. Computes `self * rhs`, returning - /// `None` if overflow occurred. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(6i8.checked_mul(21), Some(126)); - /// assert_eq!(6i8.checked_mul(22), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if b {None} else {Some(a)} - } +Basic usage: - /// Checked integer division. Computes `self / rhs`, returning `None` - /// if `rhs == 0` or the division results in overflow. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-127i8).checked_div(-1), Some(127)); - /// assert_eq!((-128i8).checked_div(-1), None); - /// assert_eq!((1i8).checked_div(0), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn checked_div(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { - None - } else { - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) +``` +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), Some(", +stringify!($SelfT), "::max_value() - 1)); +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if b {None} else {Some(a)} } } - /// Checked integer remainder. Computes `self % rhs`, returning `None` - /// if `rhs == 0` or the division results in overflow. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.checked_rem(2), Some(1)); - /// assert_eq!(5i32.checked_rem(0), None); - /// assert_eq!(i32::MIN.checked_rem(-1), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_rem(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::min_value() && rhs == -1) { - None - } else { - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(1), Some(", +stringify!($SelfT), "::min_value() + 1)); +assert_eq!((", stringify!($SelfT), "::min_value() + 2).checked_sub(3), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if b {None} else {Some(a)} } } - /// Checked negation. Computes `-self`, returning `None` if `self == - /// MIN`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.checked_neg(), Some(-5)); - /// assert_eq!(i32::MIN.checked_neg(), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(1), Some(", stringify!($SelfT), +"::max_value())); +assert_eq!(", stringify!($SelfT), "::max_value().checked_mul(2), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if b {None} else {Some(a)} + } } - /// Checked shift left. Computes `self << rhs`, returning `None` - /// if `rhs` is larger than or equal to the number of bits in `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0x10i32.checked_shl(4), Some(0x100)); - /// assert_eq!(0x10i32.checked_shl(33), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` +or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), "::min_value() + 1).checked_div(-1), Some(", +stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::min_value().checked_div(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div(0), None); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn checked_div(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } } - /// Checked shift right. Computes `self >> rhs`, returning `None` - /// if `rhs` is larger than or equal to the number of bits in `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0x10i32.checked_shr(4), Some(0x1)); - /// assert_eq!(0x10i32.checked_shr(33), None); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn checked_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if b {None} else {Some(a)} + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_rem(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } } - /// Checked absolute value. Computes `self.abs()`, returning `None` if - /// `self == MIN`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!((-5i32).checked_abs(), Some(5)); - /// assert_eq!(i32::MIN.checked_abs(), None); - /// ``` - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[inline] - pub fn checked_abs(self) -> Option { - if self.is_negative() { - self.checked_neg() - } else { - Some(self) + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if b {None} else {Some(a)} } } - /// Saturating integer addition. Computes `self + rhs`, saturating at - /// the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.saturating_add(1), 101); - /// assert_eq!(100i8.saturating_add(127), 127); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn saturating_add(self, rhs: Self) -> Self { - match self.checked_add(rhs) { - Some(x) => x, - None if rhs >= 0 => Self::max_value(), - None => Self::min_value(), + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger +than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(70), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if b {None} else {Some(a)} } } - /// Saturating integer subtraction. Computes `self - rhs`, saturating - /// at the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.saturating_sub(127), -27); - /// assert_eq!((-100i8).saturating_sub(127), -128); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn saturating_sub(self, rhs: Self) -> Self { - match self.checked_sub(rhs) { - Some(x) => x, - None if rhs >= 0 => Self::min_value(), - None => Self::max_value(), + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is +larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(70), None); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn checked_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if b {None} else {Some(a)} } } - /// Saturating integer multiplication. Computes `self * rhs`, - /// saturating at the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(100i32.saturating_mul(127), 12700); - /// assert_eq!((1i32 << 23).saturating_mul(1 << 23), i32::MAX); - /// assert_eq!((-1i32 << 23).saturating_mul(1 << 23), i32::MIN); - /// ``` - #[stable(feature = "wrapping", since = "1.7.0")] - #[inline] - pub fn saturating_mul(self, rhs: Self) -> Self { - self.checked_mul(rhs).unwrap_or_else(|| { - if (self < 0 && rhs < 0) || (self > 0 && rhs > 0) { - Self::max_value() + doc_comment! { + concat!("Checked absolute value. Computes `self.abs()`, returning `None` if +`self == MIN`. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None); +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[inline] + pub fn checked_abs(self) -> Option { + if self.is_negative() { + self.checked_neg() } else { - Self::min_value() + Some(self) } - }) + } } - /// Wrapping (modular) addition. Computes `self + rhs`, - /// wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_add(27), 127); - /// assert_eq!(100i8.wrapping_add(127), -29); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_add(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_add(self, rhs) + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric +bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT), +"::max_value()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn saturating_add(self, rhs: Self) -> Self { + match self.checked_add(rhs) { + Some(x) => x, + None if rhs >= 0 => Self::max_value(), + None => Self::min_value(), + } } } - /// Wrapping (modular) subtraction. Computes `self - rhs`, - /// wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(0i8.wrapping_sub(127), -127); - /// assert_eq!((-2i8).wrapping_sub(127), 127); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_sub(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_sub(self, rhs) + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); +assert_eq!(", stringify!($SelfT), "::min_value().saturating_sub(100), ", stringify!($SelfT), +"::min_value()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn saturating_sub(self, rhs: Self) -> Self { + match self.checked_sub(rhs) { + Some(x) => x, + None if rhs >= 0 => Self::min_value(), + None => Self::max_value(), + } } } - /// Wrapping (modular) multiplication. Computes `self * - /// rhs`, wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.wrapping_mul(12), 120); - /// assert_eq!(11i8.wrapping_mul(12), -124); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn wrapping_mul(self, rhs: Self) -> Self { - unsafe { - intrinsics::overflowing_mul(self, rhs) + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(11 << 23), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(1 << 23), ", stringify!($SelfT), "::MIN); +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[inline] + pub fn saturating_mul(self, rhs: Self) -> Self { + self.checked_mul(rhs).unwrap_or_else(|| { + if (self < 0 && rhs < 0) || (self > 0 && rhs > 0) { + Self::max_value() + } else { + Self::min_value() + } + }) } } - /// Wrapping (modular) division. Computes `self / rhs`, - /// wrapping around at the boundary of the type. - /// - /// The only case where such wrapping can occur is when one - /// divides `MIN / -1` on a signed type (where `MIN` is the - /// negative minimal value for the type); this is equivalent - /// to `-MIN`, a positive value that is too large to represent - /// in the type. In such a case, this function returns `MIN` - /// itself. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100u8.wrapping_div(10), 10); - /// assert_eq!((-128i8).wrapping_div(-1), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_div(self, rhs: Self) -> Self { - self.overflowing_div(rhs).0 - } + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the +boundary of the type. - /// Wrapping (modular) remainder. Computes `self % rhs`, - /// wrapping around at the boundary of the type. - /// - /// Such wrap-around never actually occurs mathematically; - /// implementation artifacts make `x % y` invalid for `MIN / - /// -1` on a signed type (where `MIN` is the negative - /// minimal value). In such a case, this function returns `0`. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_rem(10), 0); - /// assert_eq!((-128i8).wrapping_rem(-1), 0); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_rem(self, rhs: Self) -> Self { - self.overflowing_rem(rhs).0 +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); +assert_eq!(", stringify!($SelfT), "::max_value().wrapping_add(2), ", stringify!($SelfT), +"::min_value() + 1); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_add(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_add(self, rhs) + } + } } - /// Wrapping (modular) negation. Computes `-self`, - /// wrapping around at the boundary of the type. - /// - /// The only case where such wrapping can occur is when one - /// negates `MIN` on a signed type (where `MIN` is the - /// negative minimal value for the type); this is a positive - /// value that is too large to represent in the type. In such - /// a case, this function returns `MIN` itself. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_neg(), -100); - /// assert_eq!((-128i8).wrapping_neg(), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); +assert_eq!((-2i8).wrapping_sub(", stringify!($SelfT), "::max_value()), ", +stringify!($SelfT), "::max_value()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_sub(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_sub(self, rhs) + } + } } - /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, - /// where `mask` removes any high-order bits of `rhs` that - /// would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-left; the - /// RHS of a wrapping shift-left is restricted to the range - /// of the type, rather than the bits shifted out of the LHS - /// being returned to the other end. The primitive integer - /// types all implement a `rotate_left` function, which may - /// be what you want instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-1i8).wrapping_shl(7), -128); - /// assert_eq!((-1i8).wrapping_shl(8), -1); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_shl(self, rhs: u32) -> Self { - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + doc_comment! { + concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at +the boundary of the type. + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); +assert_eq!(11i8.wrapping_mul(12), -124); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn wrapping_mul(self, rhs: Self) -> Self { + unsafe { + intrinsics::overflowing_mul(self, rhs) + } } } - /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, - /// where `mask` removes any high-order bits of `rhs` that - /// would cause the shift to exceed the bitwidth of the type. - /// - /// Note that this is *not* the same as a rotate-right; the - /// RHS of a wrapping shift-right is restricted to the range - /// of the type, rather than the bits shifted out of the LHS - /// being returned to the other end. The primitive integer - /// types all implement a `rotate_right` function, which may - /// be what you want instead. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!((-128i8).wrapping_shr(7), -1); - /// assert_eq!((-128i8).wrapping_shr(8), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline] - pub fn wrapping_shr(self, rhs: u32) -> Self { - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the +boundary of the type. + +The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where +`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value +that is too large to represent in the type. In such a case, this function returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +assert_eq!((-128i8).wrapping_div(-1), -128); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_div(self, rhs: Self) -> Self { + self.overflowing_div(rhs).0 } } - /// Wrapping (modular) absolute value. Computes `self.abs()`, - /// wrapping around at the boundary of the type. - /// - /// The only case where such wrapping can occur is when one takes - /// the absolute value of the negative minimal value for the type - /// this is a positive value that is too large to represent in the - /// type. In such a case, this function returns `MIN` itself. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(100i8.wrapping_abs(), 100); - /// assert_eq!((-100i8).wrapping_abs(), 100); - /// assert_eq!((-128i8).wrapping_abs(), -128); - /// assert_eq!((-128i8).wrapping_abs() as u8, 128); - /// ``` - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[inline] - pub fn wrapping_abs(self) -> Self { - if self.is_negative() { - self.wrapping_neg() - } else { - self + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the +boundary of the type. + +Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` +invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, +this function returns `0`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +assert_eq!((-128i8).wrapping_rem(-1), 0); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_rem(self, rhs: Self) -> Self { + self.overflowing_rem(rhs).0 } } - /// Calculates `self` + `rhs` - /// - /// Returns a tuple of the addition along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_add(2), (7, false)); - /// assert_eq!(i32::MAX.overflowing_add(1), (i32::MIN, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::add_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary +of the type. + +The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` +is the negative minimal value for the type); this is a positive value that is too large to represent +in the type. In such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); +assert_eq!(", stringify!($SelfT), "::min_value().wrapping_neg(), ", stringify!($SelfT), +"::min_value()); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } } - /// Calculates `self` - `rhs` - /// - /// Returns a tuple of the subtraction along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_sub(2), (3, false)); - /// assert_eq!(i32::MIN.overflowing_sub(1), (i32::MAX, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::sub_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes +any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to +the range of the type, rather than the bits shifted out of the LHS being returned to the other end. +The primitive integer types all implement a `rotate_left` function, which may be what you want +instead. + +# Examples + +Basic usage: + +``` +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(64), -1); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_shl(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } } - /// Calculates the multiplication of `self` and `rhs`. - /// - /// Returns a tuple of the multiplication along with a boolean - /// indicating whether an arithmetic overflow would occur. If an - /// overflow would have occurred then the wrapped value is returned. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(5i32.overflowing_mul(2), (10, false)); - /// assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = unsafe { - intrinsics::mul_with_overflow(self as $ActualT, - rhs as $ActualT) - }; - (a as Self, b) + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` +removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted +to the range of the type, rather than the bits shifted out of the LHS being returned to the other +end. The primitive integer types all implement a `rotate_right` function, which may be what you want +instead. + +# Examples + +Basic usage: + +``` +assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); +assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(64), -128); +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[inline] + pub fn wrapping_shr(self, rhs: u32) -> Self { + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } } - /// Calculates the divisor when `self` is divided by `rhs`. - /// - /// Returns a tuple of the divisor along with a boolean indicating - /// whether an arithmetic overflow would occur. If an overflow would - /// occur then self is returned. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_div(2), (2, false)); - /// assert_eq!(i32::MIN.overflowing_div(-1), (i32::MIN, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { - (self, true) - } else { - (self / rhs, false) + doc_comment! { + concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at +the boundary of the type. + +The only case where such wrapping can occur is when one takes the absolute value of the negative +minimal value for the type this is a positive value that is too large to represent in the type. In +such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); +assert_eq!(", stringify!($SelfT), "::min_value().wrapping_abs(), ", stringify!($SelfT), +"::min_value()); +assert_eq!((-128i8).wrapping_abs() as u8, 128); +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[inline] + pub fn wrapping_abs(self) -> Self { + if self.is_negative() { + self.wrapping_neg() + } else { + self + } } } - /// Calculates the remainder when `self` is divided by `rhs`. - /// - /// Returns a tuple of the remainder after dividing along with a boolean - /// indicating whether an arithmetic overflow would occur. If an - /// overflow would occur then 0 is returned. - /// - /// # Panics - /// - /// This function will panic if `rhs` is 0. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(5i32.overflowing_rem(2), (1, false)); - /// assert_eq!(i32::MIN.overflowing_rem(-1), (0, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if self == Self::min_value() && rhs == -1 { - (0, true) - } else { - (self % rhs, false) + doc_comment! { + concat!("Calculates `self` + `rhs` + +Returns a tuple of the addition along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), "::MIN, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::add_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } } - /// Negates self, overflowing if this is equal to the minimum value. - /// - /// Returns a tuple of the negated version of self along with a boolean - /// indicating whether an overflow happened. If `self` is the minimum - /// value (e.g. `i32::MIN` for values of type `i32`), then the minimum - /// value will be returned again and `true` will be returned for an - /// overflow happening. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// use std::i32; - /// - /// assert_eq!(2i32.overflowing_neg(), (-2, false)); - /// assert_eq!(i32::MIN.overflowing_neg(), (i32::MIN, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_neg(self) -> (Self, bool) { - if self == Self::min_value() { - (Self::min_value(), true) - } else { - (-self, false) + doc_comment! { + concat!("Calculates `self` - `rhs` + +Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), "::MAX, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::sub_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) } } - /// Shifts self left by `rhs` bits. - /// - /// Returns a tuple of the shifted version of self along with a boolean - /// indicating whether the shift value was larger than or equal to the - /// number of bits. If the shift value is too large, then value is - /// masked (N-1) where N is the number of bits, and this value is then - /// used to perform the shift. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(0x10i32.overflowing_shl(4), (0x100, false)); - /// assert_eq!(0x10i32.overflowing_shl(36), (0x100, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + doc_comment! { + concat!("Calculates the multiplication of `self` and `rhs`. + +Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow +would occur. If an overflow would have occurred then the wrapped value is returned. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); +assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = unsafe { + intrinsics::mul_with_overflow(self as $ActualT, + rhs as $ActualT) + }; + (a as Self, b) + } } - /// Shifts self right by `rhs` bits. - /// - /// Returns a tuple of the shifted version of self along with a boolean - /// indicating whether the shift value was larger than or equal to the - /// number of bits. If the shift value is too large, then value is - /// masked (N-1) where N is the number of bits, and this value is then - /// used to perform the shift. - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// assert_eq!(0x10i32.overflowing_shr(4), (0x1, false)); - /// assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); - /// ``` - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then self is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); +assert_eq!(i", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), +"::MIN, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_div(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (self, true) + } else { + (self / rhs, false) + } + } } - /// Computes the absolute value of `self`. - /// - /// Returns a tuple of the absolute version of self along with a - /// boolean indicating whether an overflow happened. If self is the - /// minimum value (e.g. i32::MIN for values of type i32), then the - /// minimum value will be returned again and true will be returned for - /// an overflow happening. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.overflowing_abs(), (10,false)); - /// assert_eq!((-10i8).overflowing_abs(), (10,false)); - /// assert_eq!((-128i8).overflowing_abs(), (-128,true)); - /// ``` - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[inline] - pub fn overflowing_abs(self) -> (Self, bool) { - if self.is_negative() { - self.overflowing_neg() - } else { - (self, false) + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (0, true) + } else { + (self % rhs, false) + } } } - /// Raises self to the power of `exp`, using exponentiation by squaring. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let x: i32 = 2; // or any other integer type - /// - /// assert_eq!(x.pow(4), 16); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[rustc_inherit_overflow_checks] - pub fn pow(self, mut exp: u32) -> Self { - let mut base = self; - let mut acc = 1; + doc_comment! { + concat!("Negates self, overflowing if this is equal to the minimum value. - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; +Returns a tuple of the negated version of self along with a boolean indicating whether an overflow +happened. If `self` is the minimum value (e.g. `i32::MIN` for values of type `i32`), then the +minimum value will be returned again and `true` will be returned for an overflow happening. + +# Examples + +Basic usage: + +``` +use std::", stringify!($SelfT), "; + +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), "::MIN, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_neg(self) -> (Self, bool) { + if self == Self::min_value() { + (Self::min_value(), true) + } else { + (-self, false) } - exp /= 2; - base = base * base; } + } - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - if exp == 1 { - acc = acc * base; + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shl(4), (0x100, false)); +assert_eq!(0x10i32.overflowing_shl(36), (0x100, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) } + } - acc + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } } - /// Computes the absolute value of `self`. - /// - /// # Overflow behavior - /// - /// The absolute value of `i32::min_value()` cannot be represented as an - /// `i32`, and attempting to calculate it will cause an overflow. This - /// means that code in debug mode will trigger a panic on this case and - /// optimized code will return `i32::min_value()` without a panic. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.abs(), 10); - /// assert_eq!((-10i8).abs(), 10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - #[rustc_inherit_overflow_checks] - pub fn abs(self) -> Self { - if self.is_negative() { - // Note that the #[inline] above means that the overflow - // semantics of this negation depend on the crate we're being - // inlined into. - -self - } else { - self + doc_comment! { + concat!("Computes the absolute value of `self`. + +Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow +happened. If self is the minimum value (e.g. ", stringify!($SelfT), "::MIN for values of type +", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned +for an overflow happening. + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); +assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); +assert_eq!((", stringify!($SelfT), "::min_value()).overflowing_abs(), (-", stringify!($SelfT), +"::min_value(), true)); +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[inline] + pub fn overflowing_abs(self) -> (Self, bool) { + if self.is_negative() { + self.overflowing_neg() + } else { + (self, false) + } } } - /// Returns a number representing sign of `self`. - /// - /// - `0` if the number is zero - /// - `1` if the number is positive - /// - `-1` if the number is negative - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!(10i8.signum(), 1); - /// assert_eq!(0i8.signum(), 0); - /// assert_eq!((-10i8).signum(), -1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +let x: ", stringify!($SelfT), " = 2; // or any other integer type + +assert_eq!(x.pow(4), 16); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn pow(self, mut exp: u32) -> Self { + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc * base; + } + + acc } } - /// Returns `true` if `self` is positive and `false` if the number - /// is zero or negative. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(10i8.is_positive()); - /// assert!(!(-10i8).is_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_positive(self) -> bool { self > 0 } + doc_comment! { + concat!("Computes the absolute value of `self`. - /// Returns `true` if `self` is negative and `false` if the number - /// is zero or positive. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!((-10i8).is_negative()); - /// assert!(!10i8.is_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_negative(self) -> bool { self < 0 } +# Overflow behavior + +The absolute value of `", stringify!($SelfT), "::min_value()` cannot be represented as an +`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that +code in debug mode will trigger a panic on this case and optimized code will return `", +stringify!($SelfT), "::min_value()` without a panic. + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".abs(), 10); +assert_eq!((-10", stringify!($SelfT), ").abs(), 10); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn abs(self) -> Self { + if self.is_negative() { + // Note that the #[inline] above means that the overflow + // semantics of this negation depend on the crate we're being + // inlined into. + -self + } else { + self + } + } + } + + doc_comment! { + concat!("Returns a number representing sign of `self`. + + - `0` if the number is zero + - `1` if the number is positive + - `-1` if the number is negative + +# Examples + +Basic usage: + +``` +assert_eq!(10", stringify!($SelfT), ".signum(), 1); +assert_eq!(0", stringify!($SelfT), ".signum(), 0); +assert_eq!((-10", stringify!($SelfT), ").signum(), -1); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn signum(self) -> Self { + match self { + n if n > 0 => 1, + 0 => 0, + _ => -1, + } + } + } + + doc_comment! { + concat!("Returns `true` if `self` is positive and `false` if the number is zero or +negative. + +# Examples + +Basic usage: + +``` +assert!(10", stringify!($SelfT), ".is_positive()); +assert!(!(-10", stringify!($SelfT), ").is_positive()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_positive(self) -> bool { self > 0 } + } + + doc_comment! { + concat!("Returns `true` if `self` is negative and `false` if the number is zero or +positive. + +# Examples + +Basic usage: + +``` +assert!((-10", stringify!($SelfT), ").is_negative()); +assert!(!10", stringify!($SelfT), ".is_negative()); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_negative(self) -> bool { self < 0 } + } } } #[lang = "i8"] impl i8 { - int_impl! { i8, i8, u8, 8 } + int_impl! { i8, i8, u8, 8, -128, 127 } } #[lang = "i16"] impl i16 { - int_impl! { i16, i16, u16, 16 } + int_impl! { i16, i16, u16, 16, -32768, 32767 } } #[lang = "i32"] impl i32 { - int_impl! { i32, i32, u32, 32 } + int_impl! { i32, i32, u32, 32, -2147483648, 2147483647 } } #[lang = "i64"] impl i64 { - int_impl! { i64, i64, u64, 64 } + int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807 } } #[lang = "i128"] impl i128 { - int_impl! { i128, i128, u128, 128 } + int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, 170141183460469231731687303715884105727 } } #[cfg(target_pointer_width = "16")] @@ -1246,7 +1325,7 @@ impl isize { #[cfg(target_pointer_width = "64")] #[lang = "isize"] impl isize { - int_impl! { isize, i64, u64, 64 } + int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807 } } // `Int` + `UnsignedInt` implemented for unsigned integers diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index a2caf47e8cc..358aa2c37df 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -720,10 +720,6 @@ mod prim_f64 { } /// The 8-bit signed integer type. /// /// *[See also the `std::i8` module](i8/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i64` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i8 { } @@ -732,10 +728,6 @@ mod prim_i8 { } /// The 16-bit signed integer type. /// /// *[See also the `std::i16` module](i16/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i32` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i16 { } @@ -744,10 +736,6 @@ mod prim_i16 { } /// The 32-bit signed integer type. /// /// *[See also the `std::i32` module](i32/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i16` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i32 { } @@ -756,10 +744,6 @@ mod prim_i32 { } /// The 64-bit signed integer type. /// /// *[See also the `std::i64` module](i64/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i8` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_i64 { } @@ -768,10 +752,6 @@ mod prim_i64 { } /// The 128-bit signed integer type. /// /// *[See also the `std::i128` module](i128/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `i8` in there. -/// #[unstable(feature = "i128", issue="35118")] mod prim_i128 { } @@ -780,10 +760,6 @@ mod prim_i128 { } /// The 8-bit unsigned integer type. /// /// *[See also the `std::u8` module](u8/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u64` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u8 { } @@ -792,10 +768,6 @@ mod prim_u8 { } /// The 16-bit unsigned integer type. /// /// *[See also the `std::u16` module](u16/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u32` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u16 { } @@ -804,10 +776,6 @@ mod prim_u16 { } /// The 32-bit unsigned integer type. /// /// *[See also the `std::u32` module](u32/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u16` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u32 { } @@ -816,10 +784,6 @@ mod prim_u32 { } /// The 64-bit unsigned integer type. /// /// *[See also the `std::u64` module](u64/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u8` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_u64 { } @@ -828,10 +792,6 @@ mod prim_u64 { } /// The 128-bit unsigned integer type. /// /// *[See also the `std::u128` module](u128/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `u8` in there. -/// #[unstable(feature = "i128", issue="35118")] mod prim_u128 { } @@ -844,10 +804,6 @@ mod prim_u128 { } /// and on a 64 bit target, this is 8 bytes. /// /// *[See also the `std::isize` module](isize/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `usize` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_isize { } @@ -860,10 +816,6 @@ mod prim_isize { } /// and on a 64 bit target, this is 8 bytes. /// /// *[See also the `std::usize` module](usize/index.html).* -/// -/// However, please note that examples are shared between primitive integer -/// types. So it's normal if you see usage of types like `isize` in there. -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_usize { } -- cgit 1.4.1-3-g733a5 From 29f71488bc50843b65660867ab41e6ebf1101e6e Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Mon, 12 Feb 2018 14:00:08 +0000 Subject: 38880 remove redundant extra function --- src/libstd/collections/hash/map.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 04c9f617d01..d798854927d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -397,17 +397,6 @@ pub struct HashMap { resize_policy: DefaultResizePolicy, } -/// Search for a pre-hashed key when the hash map is known to be non-empty. -#[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) - -> InternalEntry - where M: Deref>, - F: FnMut(&K) -> bool -{ - // Do not check the capacity as an extra branch could slow the lookup. - search_hashed_body(table, hash, is_match) -} - /// Search for a pre-hashed key. /// If you don't already know the hash, use search or search_mut instead #[inline] @@ -422,16 +411,19 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE return InternalEntry::TableIsEmpty; } - search_hashed_body(table, hash, is_match) + search_hashed_nonempty(table, hash, is_match) } -/// The body of the search_hashed[_nonempty] functions + +/// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] -fn search_hashed_body(table: M, hash: SafeHash, mut is_match: F) +fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool { + // Do not check the capacity as an extra branch could slow the lookup. + let size = table.size(); let mut probe = Bucket::new(table, hash); let mut displacement = 0; -- cgit 1.4.1-3-g733a5 From fd78621717e4f9f73b41256627bfe3a83aa5e660 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Mon, 12 Feb 2018 14:53:09 +0000 Subject: 38880 fixup add missing mut --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d798854927d..c4f3fdc283e 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -417,7 +417,7 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE /// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] -fn search_hashed_nonempty(table: M, hash: SafeHash, is_match: F) +fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry where M: Deref>, F: FnMut(&K) -> bool -- cgit 1.4.1-3-g733a5 From 862132be72d4de87330e31d53489b8c718a6663e Mon Sep 17 00:00:00 2001 From: hedgehog1024 Date: Mon, 12 Feb 2018 22:25:03 +0300 Subject: Stabilize 'entry_and_modify' feature for HashMap --- src/libstd/collections/hash/map.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 82a687ae5e4..80e52123a01 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2066,7 +2066,6 @@ impl<'a, K, V> Entry<'a, K, V> { /// # Examples /// /// ``` - /// #![feature(entry_and_modify)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, u32> = HashMap::new(); @@ -2081,7 +2080,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// .or_insert(42); /// assert_eq!(map["poneyland"], 43); /// ``` - #[unstable(feature = "entry_and_modify", issue = "44733")] + #[stable(feature = "entry_and_modify", since = "1.25.0")] pub fn and_modify(self, mut f: F) -> Self where F: FnMut(&mut V) { -- cgit 1.4.1-3-g733a5 From 7948afdc53cabf9330662ec894bf668839880a3c Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Sun, 11 Feb 2018 16:38:26 -0800 Subject: changed termination_trait's bound from Error to Debug; added compiletest header command and appropriate tests --- src/libstd/termination.rs | 15 +++------------ src/test/compile-fail/main-wrong-type-2.rs | 15 --------------- .../termination-trait-main-wrong-type.rs | 15 +++++++++++++++ .../termination-trait-not-satisfied.rs | 17 +++++++++++++++++ .../compile-fail/termination-trait-not-satisfied.rs | 17 ----------------- .../termination-trait-for-result-box-error_err.rs | 20 ++++++++++++++++++++ .../termination-trait-for-empty.rs | 13 +++++++++++++ .../termination-trait-for-i32.rs | 15 +++++++++++++++ .../termination-trait-for-result-box-error_ok.rs | 17 +++++++++++++++++ .../termination-trait-for-result.rs | 17 +++++++++++++++++ src/test/run-pass/termination-trait-for-empty.rs | 13 ------------- src/test/run-pass/termination-trait-for-i32.rs | 15 --------------- .../termination-trait-for-result-box-error_ok.rs | 17 +++++++++++++++++ src/test/run-pass/termination-trait-for-result.rs | 17 ----------------- src/tools/compiletest/src/header.rs | 13 +++++++++++++ src/tools/compiletest/src/runtest.rs | 13 +++++++------ 16 files changed, 154 insertions(+), 95 deletions(-) delete mode 100644 src/test/compile-fail/main-wrong-type-2.rs create mode 100644 src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs create mode 100644 src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs delete mode 100644 src/test/compile-fail/termination-trait-not-satisfied.rs create mode 100644 src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs create mode 100644 src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs create mode 100644 src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs create mode 100644 src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs create mode 100644 src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs delete mode 100644 src/test/run-pass/termination-trait-for-empty.rs delete mode 100644 src/test/run-pass/termination-trait-for-i32.rs create mode 100644 src/test/run-pass/termination-trait-for-result-box-error_ok.rs delete mode 100644 src/test/run-pass/termination-trait-for-result.rs (limited to 'src/libstd') diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs index 93a913bb540..dc7fa53aab6 100644 --- a/src/libstd/termination.rs +++ b/src/libstd/termination.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use error::Error; +use fmt::Debug; #[cfg(target_arch = "wasm32")] mod exit { pub const SUCCESS: i32 = 0; @@ -45,27 +45,18 @@ impl Termination for () { } #[unstable(feature = "termination_trait", issue = "43301")] -impl Termination for Result { +impl Termination for Result { fn report(self) -> i32 { match self { Ok(val) => val.report(), Err(err) => { - print_error(err); + eprintln!("Error: {:?}", err); exit::FAILURE } } } } -#[unstable(feature = "termination_trait", issue = "43301")] -fn print_error(err: E) { - eprintln!("Error: {}", err.description()); - - if let Some(ref err) = err.cause() { - eprintln!("Caused by: {}", err.description()); - } -} - #[unstable(feature = "termination_trait", issue = "43301")] impl Termination for ! { fn report(self) -> i32 { unreachable!(); } diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs deleted file mode 100644 index a63162cf73d..00000000000 --- a/src/test/compile-fail/main-wrong-type-2.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -#![feature(termination_trait)] - -fn main() -> char { -//~^ ERROR: the trait bound `char: std::Termination` is not satisfied - ' ' -} diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs new file mode 100644 index 00000000000..a63162cf73d --- /dev/null +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -0,0 +1,15 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(termination_trait)] + +fn main() -> char { +//~^ ERROR: the trait bound `char: std::Termination` is not satisfied + ' ' +} diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs new file mode 100644 index 00000000000..788c38c55be --- /dev/null +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] + +struct ReturnType {} + +fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied + ReturnType {} +} diff --git a/src/test/compile-fail/termination-trait-not-satisfied.rs b/src/test/compile-fail/termination-trait-not-satisfied.rs deleted file mode 100644 index 788c38c55be..00000000000 --- a/src/test/compile-fail/termination-trait-not-satisfied.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(termination_trait)] - -struct ReturnType {} - -fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied - ReturnType {} -} diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs new file mode 100644 index 00000000000..8ce27c0a062 --- /dev/null +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// must-compile-successfully +// failure-status: 1 + +#![feature(termination_trait)] + +use std::io::{Error, ErrorKind}; + +fn main() -> Result<(), Box> { + Err(Box::new(Error::new(ErrorKind::Other, "returned Box from main()"))) +} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs new file mode 100644 index 00000000000..5e534da0128 --- /dev/null +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] + +fn main() {} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs new file mode 100644 index 00000000000..fa7cb023b44 --- /dev/null +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] + +fn main() -> i32 { + 0 +} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs new file mode 100644 index 00000000000..269ac451cf4 --- /dev/null +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] + +use std::io::Error; + +fn main() -> Result<(), Box> { + Ok(()) +} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs new file mode 100644 index 00000000000..751db0fb500 --- /dev/null +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] + +use std::io::Error; + +fn main() -> Result<(), Error> { + Ok(()) +} diff --git a/src/test/run-pass/termination-trait-for-empty.rs b/src/test/run-pass/termination-trait-for-empty.rs deleted file mode 100644 index 5e534da0128..00000000000 --- a/src/test/run-pass/termination-trait-for-empty.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(termination_trait)] - -fn main() {} diff --git a/src/test/run-pass/termination-trait-for-i32.rs b/src/test/run-pass/termination-trait-for-i32.rs deleted file mode 100644 index fa7cb023b44..00000000000 --- a/src/test/run-pass/termination-trait-for-i32.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(termination_trait)] - -fn main() -> i32 { - 0 -} diff --git a/src/test/run-pass/termination-trait-for-result-box-error_ok.rs b/src/test/run-pass/termination-trait-for-result-box-error_ok.rs new file mode 100644 index 00000000000..269ac451cf4 --- /dev/null +++ b/src/test/run-pass/termination-trait-for-result-box-error_ok.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] + +use std::io::Error; + +fn main() -> Result<(), Box> { + Ok(()) +} diff --git a/src/test/run-pass/termination-trait-for-result.rs b/src/test/run-pass/termination-trait-for-result.rs deleted file mode 100644 index 751db0fb500..00000000000 --- a/src/test/run-pass/termination-trait-for-result.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(termination_trait)] - -use std::io::Error; - -fn main() -> Result<(), Error> { - Ok(()) -} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 80750f9a3fe..d4d3d6c6e9a 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -232,6 +232,7 @@ pub struct TestProps { // customized normalization rules pub normalize_stdout: Vec<(String, String)>, pub normalize_stderr: Vec<(String, String)>, + pub failure_status: i32, } impl TestProps { @@ -260,6 +261,7 @@ impl TestProps { run_pass: false, normalize_stdout: vec![], normalize_stderr: vec![], + failure_status: 101, } } @@ -383,6 +385,10 @@ impl TestProps { if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") { self.normalize_stderr.push(rule); } + + if let Some(code) = config.parse_failure_status(ln) { + self.failure_status = code; + } }); for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { @@ -488,6 +494,13 @@ impl Config { self.parse_name_directive(line, "pretty-compare-only") } + fn parse_failure_status(&self, line: &str) -> Option { + match self.parse_name_value_directive(line, "failure-status") { + Some(code) => code.trim().parse::().ok(), + _ => None, + } + } + fn parse_must_compile_successfully(&self, line: &str) -> bool { self.parse_name_directive(line, "must-compile-successfully") } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 46df211cbaf..a3b6d16270b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -295,11 +295,14 @@ impl<'test> TestCx<'test> { } fn check_correct_failure_status(&self, proc_res: &ProcRes) { - // The value the rust runtime returns on failure - const RUST_ERR: i32 = 101; - if proc_res.status.code() != Some(RUST_ERR) { + let expected_status = Some(self.props.failure_status); + let received_status = proc_res.status.code(); + + if expected_status != received_status { self.fatal_proc_rec( - &format!("failure produced the wrong error: {}", proc_res.status), + &format!("Error: expected failure status ({:?}) but received status {:?}.", + expected_status, + received_status), proc_res, ); } @@ -320,7 +323,6 @@ impl<'test> TestCx<'test> { ); let proc_res = self.exec_compiled_test(); - if !proc_res.status.success() { self.fatal_proc_rec("test run failed!", &proc_res); } @@ -499,7 +501,6 @@ impl<'test> TestCx<'test> { expected, actual ); - panic!(); } } -- cgit 1.4.1-3-g733a5 From 97df227d19791b0e9d199be28851fb924c3c1e21 Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Mon, 12 Feb 2018 21:08:14 -0800 Subject: Fix wait_timeout value --- src/libstd/sync/condvar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index e6a3388aa25..65235aa62a1 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -484,7 +484,7 @@ impl Condvar { Some(timeout) => timeout, None => return Ok((guard, WaitTimeoutResult(true))), } - guard = self.wait_timeout(guard, dur)?.0; + guard = self.wait_timeout(guard, timeout)?.0; } } -- cgit 1.4.1-3-g733a5 From a295ec1ec9d7616474a620a8acd15944aaf0c638 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 16:32:35 +0000 Subject: 38880 restore original entry(key) method --- src/libstd/collections/hash/map.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c4f3fdc283e..23a932c7aa3 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1031,7 +1031,9 @@ impl HashMap pub fn entry(&mut self, key: K) -> Entry { // Gotta resize now. self.reserve(1); - self.search_mut(&key).into_entry(key).expect("unreachable") + let hash = self.make_hash(&key); + search_hashed(&mut self.table, hash, |q| q.eq(&key)) + .into_entry(key).expect("unreachable") } /// Returns the number of elements in the map. -- cgit 1.4.1-3-g733a5 From 94c3c84b6a9c382862b1f750f782c33256fa58bd Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 16:33:00 +0000 Subject: 38880 hashmap check size=0, not just capacity=0 --- src/libstd/collections/hash/map.rs | 54 +++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 30 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 23a932c7aa3..fdc62be3dd9 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -414,7 +414,6 @@ fn search_hashed(table: M, hash: SafeHash, is_match: F) -> InternalE search_hashed_nonempty(table, hash, is_match) } - /// Search for a pre-hashed key when the hash map is known to be non-empty. #[inline] fn search_hashed_nonempty(table: M, hash: SafeHash, mut is_match: F) @@ -557,32 +556,36 @@ impl HashMap } /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, use - /// search_hashed. + /// If you already have the hash for the key lying around, or if you need an + /// InternalEntry, use search_hashed or search_hashed_nonempty. #[inline] - fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry> + fn search<'a, Q: ?Sized>(&'a self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { - if self.table.capacity() != 0 { - let hash = self.make_hash(q); - search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) - } else { - InternalEntry::TableIsEmpty + if !self.is_empty() { + return None; } + + let hash = self.make_hash(q); + search_hashed_nonempty(&self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } #[inline] - fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry> + fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) + -> Option>> where K: Borrow, Q: Eq + Hash { - if self.table.capacity() != 0 { - let hash = self.make_hash(q); - search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) - } else { - InternalEntry::TableIsEmpty + if self.is_empty() { + return None; } + + let hash = self.make_hash(q); + search_hashed_nonempty(&mut self.table, hash, |k| q.eq(k.borrow())) + .into_occupied_bucket() } // The caller should ensure that invariants by Robin Hood Hashing hold @@ -1140,7 +1143,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) + self.search(k).map(|bucket| bucket.into_refs().1) } /// Returns true if the map contains a value for the specified key. @@ -1167,7 +1170,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search(k).into_occupied_bucket().is_some() + self.search(k).is_some() } /// Returns a mutable reference to the value corresponding to the key. @@ -1196,7 +1199,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) + self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } /// Inserts a key-value pair into the map. @@ -1256,11 +1259,7 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - - self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) + self.search_mut(k).map(|bucket| pop_internal(bucket).1) } /// Removes a key from the map, returning the stored key and value if the @@ -1296,7 +1295,6 @@ impl HashMap } self.search_mut(k) - .into_occupied_bucket() .map(|bucket| { let (k, v, _) = pop_internal(bucket); (k, v) @@ -2654,15 +2652,11 @@ impl super::Recover for HashMap #[inline] fn get(&self, key: &Q) -> Option<&K> { - self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) + self.search(key).map(|bucket| bucket.into_refs().0) } fn take(&mut self, key: &Q) -> Option { - if self.table.size() == 0 { - return None; - } - - self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) + self.search_mut(key).map(|bucket| pop_internal(bucket).0) } #[inline] -- cgit 1.4.1-3-g733a5 From f3330cea7f43288362fec9b010b04e22dfbf45a2 Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 17:15:58 +0000 Subject: 38880 fix incorrect negation --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fdc62be3dd9..a8f419d6c6c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -564,7 +564,7 @@ impl HashMap where K: Borrow, Q: Eq + Hash { - if !self.is_empty() { + if self.is_empty() { return None; } -- cgit 1.4.1-3-g733a5 From 6fe2d1d765810c05ce2aa2184baa9f4aabf1a151 Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Tue, 13 Feb 2018 11:32:04 -0800 Subject: Misc fixes Switch feature guards to unstable Add missing semicolon Remove mut that's no longer necessary --- src/libstd/sync/condvar.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 65235aa62a1..98fadbd3543 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -263,7 +263,7 @@ impl Condvar { /// // As long as the value inside the `Mutex` is false, we wait. /// cvar.wait_until(lock.lock().unwrap(), |started| { started }); /// ``` - #[stable(feature = "wait_until", since = "1.24")] + #[unstable(feature = "wait_until", issue = "47960")] pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, mut condition: F) -> LockResult> @@ -470,9 +470,9 @@ impl Condvar { /// } /// // access the locked mutex via result.0 /// ``` - #[stable(feature = "wait_timeout_until", since = "1.24")] + #[unstable(feature = "wait_timeout_until", issue = "47960")] pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, - mut dur: Duration, mut condition: F) + dur: Duration, mut condition: F) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> where F: FnMut(&mut T) -> bool { let start = Instant::now(); @@ -483,7 +483,7 @@ impl Condvar { let timeout = match dur.checked_sub(start.elapsed()) { Some(timeout) => timeout, None => return Ok((guard, WaitTimeoutResult(true))), - } + }; guard = self.wait_timeout(guard, timeout)?.0; } } -- cgit 1.4.1-3-g733a5 From e034dddb32cd9814d9f71bb2b444f9863fba2dfc Mon Sep 17 00:00:00 2001 From: Shaun Steenkamp Date: Tue, 13 Feb 2018 20:25:10 +0000 Subject: 38880 remove unnecessary self.table.size check --- src/libstd/collections/hash/map.rs | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a8f419d6c6c..a82ff915093 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1290,10 +1290,6 @@ impl HashMap where K: Borrow, Q: Hash + Eq { - if self.table.size() == 0 { - return None; - } - self.search_mut(k) .map(|bucket| { let (k, v, _) = pop_internal(bucket); -- cgit 1.4.1-3-g733a5 From e1e79d3a100b78939c3461b6a257729c193b469e Mon Sep 17 00:00:00 2001 From: Ross Light Date: Thu, 15 Feb 2018 07:32:42 -0800 Subject: Remove "empty buffer" doc in read_until This appears copied from fill_buf, but the above paragraph already indicates that a lack of delimiter at the end is EOF. --- src/libstd/io/mod.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 33d11ebb350..aa07f64b678 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1437,8 +1437,6 @@ pub trait BufRead: Read { /// /// If successful, this function will return the total number of bytes read. /// - /// An empty buffer returned indicates that the stream has reached EOF. - /// /// # Errors /// /// This function will ignore all instances of [`ErrorKind::Interrupted`] and -- cgit 1.4.1-3-g733a5 From ba6a6d0f0a047bc211e69bcbf0934ae6b651f415 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Feb 2018 18:59:00 +0100 Subject: Fix condvar example --- src/libstd/sync/condvar.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 56402175817..54bb6513650 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -47,11 +47,13 @@ impl WaitTimeoutResult { /// /// thread::spawn(move|| { /// let &(ref lock, ref cvar) = &*pair2; + /// + /// // Let's wait 20 milliseconds before notifying the condvar. + /// thread::sleep(Duration::from_millis(20)); + /// /// let mut started = lock.lock().unwrap(); /// // We update the boolean value. /// *started = true; - /// // Let's wait 20 milliseconds before notifying the condvar. - /// thread::sleep(Duration::from_millis(20)); /// cvar.notify_one(); /// }); /// -- cgit 1.4.1-3-g733a5 From e9c75a889f972ca88b9c41d0ddb4b0cf487c5ebe Mon Sep 17 00:00:00 2001 From: Alexis Hunt Date: Fri, 16 Feb 2018 08:51:40 -0500 Subject: Add a warning to File about mutability. Fixes #47708. --- src/libstd/fs.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5cea389531f..1798bf4760b 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -81,9 +81,18 @@ use time::SystemTime; /// # } /// ``` /// +/// Note that, although read and write methods require a `&mut File`, because +/// of the interfaces for [`Read`] and [`Write`], it is still possible to +/// modify a file through a `&File`, either through methods that take `&File` +/// or by retrieving a raw OS filehandle and modifying the file that way. +/// Additionally, many operating systems allow concurrent modification of files +/// by different processes. Care should be taken not to assume that holding a +/// `&File` means that the file will not change. +/// /// [`Seek`]: ../io/trait.Seek.html /// [`String`]: ../string/struct.String.html /// [`Read`]: ../io/trait.Read.html +/// [`Write`]: ../io/trait.Write.html /// [`BufReader`]: ../io/struct.BufReader.html #[stable(feature = "rust1", since = "1.0.0")] pub struct File { @@ -459,6 +468,9 @@ impl File { /// # Ok(()) /// # } /// ``` + /// + /// Note that this method alters the content of the underlying file, even + /// though it takes `&self` rather than `&mut self`. #[stable(feature = "rust1", since = "1.0.0")] pub fn set_len(&self, size: u64) -> io::Result<()> { self.inner.truncate(size) @@ -557,6 +569,9 @@ impl File { /// # Ok(()) /// # } /// ``` + /// + /// Note that this method alters the permissions of the underlying file, + /// even though it takes `&self` rather than `&mut self`. #[stable(feature = "set_permissions_atomic", since = "1.16.0")] pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { self.inner.set_permissions(perm.0) -- cgit 1.4.1-3-g733a5 From b1f04a3a2e1a01ea1b77153dd8d22e7837542aa0 Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Thu, 15 Feb 2018 09:28:25 -0800 Subject: Fix unit test compilation Also fix some code snippets in documentation. --- src/libstd/sync/condvar.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 98fadbd3543..546e105deb7 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -244,6 +244,8 @@ impl Condvar { /// # Examples /// /// ``` + /// #![feature(wait_until)] + /// /// use std::sync::{Arc, Mutex, Condvar}; /// use std::thread; /// @@ -261,7 +263,7 @@ impl Condvar { /// // Wait for the thread to start up. /// let &(ref lock, ref cvar) = &*pair; /// // As long as the value inside the `Mutex` is false, we wait. - /// cvar.wait_until(lock.lock().unwrap(), |started| { started }); + /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap(); /// ``` #[unstable(feature = "wait_until", issue = "47960")] pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>, @@ -445,6 +447,8 @@ impl Condvar { /// # Examples /// /// ``` + /// #![feature(wait_timeout_until)] + /// /// use std::sync::{Arc, Mutex, Condvar}; /// use std::thread; /// use std::time::Duration; @@ -462,8 +466,8 @@ impl Condvar { /// /// // wait for the thread to start up /// let &(ref lock, ref cvar) = &*pair; - /// let result = cvar.wait_timeout_until(lock, Duration::from_millis(100), |started| { - /// started + /// let result = cvar.wait_timeout_until(lock.lock().unwrap(), Duration::from_millis(100), |started| { + /// *started /// }).unwrap(); /// if result.1.timed_out() { /// // timed-out without the condition ever evaluating to true. @@ -613,6 +617,7 @@ impl Drop for Condvar { #[cfg(test)] mod tests { + /// #![feature(wait_until)] use sync::mpsc::channel; use sync::{Condvar, Mutex, Arc}; use sync::atomic::{AtomicBool, Ordering}; @@ -699,9 +704,9 @@ mod tests { // Wait for the thread to start up. let &(ref lock, ref cvar) = &*pair; let guard = cvar.wait_until(lock.lock().unwrap(), |started| { - started + *started }); - assert!(*guard); + assert!(*guard.unwrap()); } #[test] @@ -730,7 +735,7 @@ mod tests { let c = Arc::new(Condvar::new()); let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), || { false }).unwrap(); + let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap(); // no spurious wakeups. ensure it timed-out assert!(wait.timed_out()); } @@ -742,7 +747,7 @@ mod tests { let c = Arc::new(Condvar::new()); let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), || { true }).unwrap(); + let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap(); // ensure it didn't time-out even if we were not given any time. assert!(!wait.timed_out()); } @@ -753,15 +758,16 @@ mod tests { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair_copy = pair.clone(); + let &(ref m, ref c) = &*pair; let g = m.lock().unwrap(); - let t = thread::spawn(move || { - let &(ref lock, ref cvar) = &*pair2; + let _t = thread::spawn(move || { + let &(ref lock, ref cvar) = &*pair_copy; let mut started = lock.lock().unwrap(); thread::sleep(Duration::from_millis(1)); - started = true; + *started = true; cvar.notify_one(); }); - let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |¬ified| { + let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| { notified }).unwrap(); // ensure it didn't time-out even if we were not given any time. -- cgit 1.4.1-3-g733a5 From ec905975b85d504abdd428be668346d008bc7a69 Mon Sep 17 00:00:00 2001 From: Alexis Hunt Date: Sat, 17 Feb 2018 08:47:03 -0500 Subject: Wording fixes from review for File. --- src/libstd/fs.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 1798bf4760b..292a78278ab 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -82,12 +82,12 @@ use time::SystemTime; /// ``` /// /// Note that, although read and write methods require a `&mut File`, because -/// of the interfaces for [`Read`] and [`Write`], it is still possible to -/// modify a file through a `&File`, either through methods that take `&File` -/// or by retrieving a raw OS filehandle and modifying the file that way. +/// of the interfaces for [`Read`] and [`Write`], the holder of a `&File` can +/// still modify the file, either through methods that take `&File` or by +/// retrieving the underlying OS object and modifying the file that way. /// Additionally, many operating systems allow concurrent modification of files -/// by different processes. Care should be taken not to assume that holding a -/// `&File` means that the file will not change. +/// by different processes. Avoid assuming that holding a `&File` means that the +/// file will not change. /// /// [`Seek`]: ../io/trait.Seek.html /// [`String`]: ../string/struct.String.html -- cgit 1.4.1-3-g733a5 From 4452446292086d9c92ea709eea61a31cedb55e22 Mon Sep 17 00:00:00 2001 From: Matthias Krüger Date: Fri, 16 Feb 2018 15:56:50 +0100 Subject: fix more typos found by codespell. --- RELEASES.md | 2 +- config.toml.example | 4 ++-- src/bootstrap/test.rs | 2 +- src/librustc/diagnostics.rs | 2 +- src/librustc/hir/mod.rs | 2 +- src/librustc/infer/error_reporting/mod.rs | 4 ++-- src/librustc/infer/outlives/obligations.rs | 2 +- src/librustc/infer/region_constraints/README.md | 2 +- src/librustc/middle/region.rs | 2 +- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/mir/mod.rs | 2 +- src/librustc/traits/coherence.rs | 2 +- src/librustc/traits/mod.rs | 2 +- src/librustc/ty/layout.rs | 4 ++-- src/librustc_apfloat/tests/ieee.rs | 4 ++-- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_const_eval/_match.rs | 2 +- src/librustc_data_structures/indexed_vec.rs | 2 +- src/librustc_mir/borrow_check/mod.rs | 8 ++++---- src/librustc_mir/borrow_check/nll/mod.rs | 2 +- src/librustc_mir/borrow_check/nll/region_infer/mod.rs | 2 +- .../borrow_check/nll/region_infer/values.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/dataflow/impls/borrows.rs | 4 ++-- src/librustc_mir/diagnostics.rs | 2 +- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_resolve/check_unused.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 2 +- src/librustc_trans/back/lto.rs | 4 ++-- src/librustc_trans/builder.rs | 2 +- src/librustc_trans/mir/rvalue.rs | 2 +- src/librustc_trans_utils/trans_crate.rs | 2 +- src/libstd/io/buffered.rs | 2 +- src/libstd/sync/rwlock.rs | 4 ++-- src/libstd/sys_common/backtrace.rs | 2 +- src/libstd/sys_common/poison.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/config.rs | 2 +- src/libsyntax/parse/parser.rs | 4 ++-- src/test/compile-fail/coerce-to-bang.rs | 2 +- .../macro_expanded_mod_helper/foo/bar.rs | 2 +- .../macro_expanded_mod_helper/foo/mod.rs | 2 +- src/test/compile-fail/hr-subtype.rs | 4 ++-- src/test/compile-fail/issue-20616-1.rs | 2 +- src/test/compile-fail/issue-20616-2.rs | 2 +- src/test/compile-fail/issue-20616-3.rs | 2 +- src/test/compile-fail/issue-20616-4.rs | 2 +- src/test/compile-fail/issue-20616-5.rs | 2 +- src/test/compile-fail/issue-20616-6.rs | 2 +- src/test/compile-fail/issue-20616-7.rs | 2 +- src/test/compile-fail/issue-20616-8.rs | 2 +- src/test/compile-fail/issue-20616-9.rs | 2 +- src/test/compile-fail/no_crate_type.rs | 2 +- src/test/mir-opt/README.md | 2 +- src/test/pretty/stmt_expr_attributes.rs | 2 +- src/test/run-make/hotplug_codegen_backend/Makefile | 2 +- .../run-make/hotplug_codegen_backend/the_backend.rs | 2 +- .../proc-macro/auxiliary/derive-reexport.rs | 2 +- src/test/run-pass/issue-29746.rs | 2 +- src/test/run-pass/issue-32008.rs | 2 +- src/test/run-pass/rfc1857-drop-order.rs | 18 +++++++++--------- src/test/run-pass/simd-target-feature-mixup.rs | 2 +- src/test/rustdoc/impl-parts-crosscrate.rs | 2 +- src/test/ui/explain.stdout | 2 +- .../issue-43106-gating-of-builtin-attrs.rs | 2 +- .../lifetime-errors/liveness-assign-imm-local-notes.rs | 2 +- 69 files changed, 89 insertions(+), 89 deletions(-) (limited to 'src/libstd') diff --git a/RELEASES.md b/RELEASES.md index 7a9d256be28..64e2145e0f3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -29,7 +29,7 @@ Libraries - [Copied `AsciiExt` methods onto `char`][46077] - [Remove `T: Sized` requirement on `ptr::is_null()`][46094] - [impl `From` for `{TryRecvError, RecvTimeoutError}`][45506] -- [Optimised `f32::{min, max}` to generate more efficent x86 assembly][47080] +- [Optimised `f32::{min, max}` to generate more efficient x86 assembly][47080] - [`[u8]::contains` now uses memchr which provides a 3x speed improvement][46713] Stabilized APIs diff --git a/config.toml.example b/config.toml.example index f153562a538..8d1fa3eec5c 100644 --- a/config.toml.example +++ b/config.toml.example @@ -151,8 +151,8 @@ # default. #extended = false -# Installs choosen set of extended tools if enables. By default builds all. -# If choosen tool failed to build the installation fails. +# Installs chosen set of extended tools if enables. By default builds all. +# If chosen tool failed to build the installation fails. #tools = ["cargo", "rls", "rustfmt", "analysis", "src"] # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 64ede4f4ecc..7b485662760 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -935,7 +935,7 @@ impl Step for Compiletest { } } if suite == "run-make" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite as they generally dont work without LLVM"); + println!("Ignoring run-make test suite as they generally don't work without LLVM"); return; } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 4c256556191..287516474d4 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1891,7 +1891,7 @@ is a function pointer, which is not zero-sized. This pattern should be rewritten. There are a few possible ways to do this: - change the original fn declaration to match the expected signature, - and do the cast in the fn body (the prefered option) + and do the cast in the fn body (the preferred option) - cast the fn item fo a fn pointer before calling transmute, as shown here: ``` diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 2854b9da147..bc03f7ead81 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -543,7 +543,7 @@ impl Generics { } /// Synthetic Type Parameters are converted to an other form during lowering, this allows -/// to track the original form they had. Usefull for error messages. +/// to track the original form they had. Useful for error messages. #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum SyntheticTyParamKind { ImplTrait diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 03fc40b2e39..700d06acf11 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -734,7 +734,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - // When finding T != &T, hightlight only the borrow + // When finding T != &T, highlight only the borrow (&ty::TyRef(r1, ref tnm1), _) if equals(&tnm1.ty, &t2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); push_ty_ref(&r1, tnm1, &mut values.0); @@ -946,7 +946,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let type_param = generics.type_param(param, self.tcx); let hir = &self.tcx.hir; hir.as_local_node_id(type_param.def_id).map(|id| { - // Get the `hir::TyParam` to verify wether it already has any bounds. + // Get the `hir::TyParam` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) { diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index eda2e1f7b4e..36e657f78b4 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -106,7 +106,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// done (or else an assert will fire). /// /// See the `region_obligations` field of `InferCtxt` for some - /// comments about how this funtion fits into the overall expected + /// comments about how this function fits into the overall expected /// flow of the the inferencer. The key point is that it is /// invoked after all type-inference variables have been bound -- /// towards the end of regionck. This also ensures that the diff --git a/src/librustc/infer/region_constraints/README.md b/src/librustc/infer/region_constraints/README.md index 67ad08c7530..95f9c8c8353 100644 --- a/src/librustc/infer/region_constraints/README.md +++ b/src/librustc/infer/region_constraints/README.md @@ -19,7 +19,7 @@ The constraints are always of one of three possible forms: a subregion of Rj - `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which must not be a variable) must be a subregion of the variable Ri -- `ConstrainVarSubReg(Ri, R)` states the variable Ri shoudl be less +- `ConstrainVarSubReg(Ri, R)` states the variable Ri should be less than the concrete region R. This is kind of deprecated and ought to be replaced with a verify (they essentially play the same role). diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index e5619f469e7..3ce4ab04777 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -886,7 +886,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk: // // Each of the statements within the block is a terminating // scope, and thus a temporary (e.g. the result of calling - // `bar()` in the initalizer expression for `let inner = ...;`) + // `bar()` in the initializer expression for `let inner = ...;`) // will be cleaned up immediately after its corresponding // statement (i.e. `let inner = ...;`) executes. // diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 8ffea62f6be..a80695ec9b9 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -56,7 +56,7 @@ pub struct GlobalId<'tcx> { //////////////////////////////////////////////////////////////////////////////// pub trait PointerArithmetic: layout::HasDataLayout { - // These are not supposed to be overriden. + // These are not supposed to be overridden. //// Trunace the given value to the pointer size; also return whether there was an overflow fn truncate_to_ptr(self, val: u128) -> (u64, bool) { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 439be667861..b88dea871ce 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1950,7 +1950,7 @@ pub struct GeneratorLayout<'tcx> { /// ``` /// /// here, there is one unique free region (`'a`) but it appears -/// twice. We would "renumber" each occurence to a unique vid, as follows: +/// twice. We would "renumber" each occurrence to a unique vid, as follows: /// /// ```text /// ClosureSubsts = [ diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 9de18612d81..7311b47974a 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -277,7 +277,7 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, /// is bad, because the only local type with `T` as a subtree is /// `LocalType`, and `Vec<->` is between it and the type parameter. /// - similarly, `FundamentalPair, T>` is bad, because -/// the second occurence of `T` is not a subtree of *any* local type. +/// the second occurrence of `T` is not a subtree of *any* local type. /// - however, `LocalType>` is OK, because `T` is a subtree of /// `LocalType>`, which is local and has no types between it and /// the type parameter. diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 80819a86b7c..41cc8ca601a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -621,7 +621,7 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // FIXME (@jroesch) ISSUE 26721 // I'm not sure if this is a bug or not, needs further investigation. // It appears that by reusing the fulfillment_cx here we incur more - // obligations and later trip an asssertion on regionck.rs line 337. + // obligations and later trip an assertion on regionck.rs line 337. // // The two possibilities I see is: // - normalization is not actually fully happening and we diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 63b91ff1101..c3cd65230bd 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2059,7 +2059,7 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // can however trigger recursive invocations of `layout_of`. // Therefore, we execute it *after* the main query has // completed, to avoid problems around recursive structures - // and the like. (Admitedly, I wasn't able to reproduce a problem + // and the like. (Admittedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) self.record_layout_for_printing(layout); @@ -2085,7 +2085,7 @@ impl<'a, 'tcx> LayoutOf> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx // can however trigger recursive invocations of `layout_of`. // Therefore, we execute it *after* the main query has // completed, to avoid problems around recursive structures - // and the like. (Admitedly, I wasn't able to reproduce a problem + // and the like. (Admittedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) let cx = LayoutCx { tcx: *self.tcx, diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index aff2076e038..ff46ee79c31 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -2201,12 +2201,12 @@ fn is_finite_non_zero() { assert!(!Single::ZERO.is_finite_non_zero()); assert!(!(-Single::ZERO).is_finite_non_zero()); - // Test +/- qNaN. +/- dont mean anything with qNaN but paranoia can't hurt in + // Test +/- qNaN. +/- don't mean anything with qNaN but paranoia can't hurt in // this instance. assert!(!Single::NAN.is_finite_non_zero()); assert!(!(-Single::NAN).is_finite_non_zero()); - // Test +/- sNaN. +/- dont mean anything with sNaN but paranoia can't hurt in + // Test +/- sNaN. +/- don't mean anything with sNaN but paranoia can't hurt in // this instance. assert!(!Single::snan(None).is_finite_non_zero()); assert!(!(-Single::snan(None)).is_finite_non_zero()); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 738c0d82ee1..58818d0ce80 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1111,7 +1111,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { /// Given a type, if it is an immutable reference, return a suggestion to make it mutable fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option { - // Check wether the argument is an immutable reference + // Check whether the argument is an immutable reference debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self); if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index a7c382eba50..e30f5cb4f12 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -607,7 +607,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, // be able to observe whether the types of the struct's fields are // inhabited. // - // If the field is truely inaccessible, then all the patterns + // If the field is truly inaccessible, then all the patterns // matching against it must be wildcard patterns, so its type // does not matter. // diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 753f12f400b..b11ca107af7 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -204,7 +204,7 @@ macro_rules! newtype_index { $($tokens)*); ); - // The case where no derives are added, but encodable is overriden. Don't + // The case where no derives are added, but encodable is overridden. Don't // derive serialization traits (@pub [$($pub:tt)*] @type [$type:ident] diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 650f99828ae..c6ed971f767 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -117,7 +117,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( for move_error in move_errors { let (span, kind): (Span, IllegalMoveOriginKind) = match move_error { MoveError::UnionMove { .. } => { - unimplemented!("dont know how to report union move errors yet.") + unimplemented!("don't know how to report union move errors yet.") } MoveError::IllegalMove { cannot_move_out_of: o, @@ -1424,7 +1424,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// tracked in the MoveData. /// /// An Err result includes a tag indicated why the search failed. - /// Currenly this can only occur if the place is built off of a + /// Currently this can only occur if the place is built off of a /// static variable, as we do not track those in the MoveData. fn move_path_closest_to( &mut self, @@ -1439,7 +1439,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } match *last_prefix { Place::Local(_) => panic!("should have move path for every Local"), - Place::Projection(_) => panic!("PrefixSet::All meant dont stop for Projection"), + Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"), Place::Static(_) => return Err(NoMovePathFound::ReachedStatic), } } @@ -1484,7 +1484,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { { } ProjectionElem::Subslice { .. } => { - panic!("we dont allow assignments to subslices, context: {:?}", + panic!("we don't allow assignments to subslices, context: {:?}", context); } diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 66ca74b0139..07e5091da9c 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -278,7 +278,7 @@ fn for_each_region_constraint( /// Right now, we piggy back on the `ReVar` to store our NLL inference /// regions. These are indexed with `RegionVid`. This method will -/// assert that the region is a `ReVar` and extract its interal index. +/// assert that the region is a `ReVar` and extract its internal index. /// This is reasonable because in our MIR we replace all universal regions /// with inference variables. pub trait ToRegionVid { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 9a338947f47..33c012dfad8 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -964,7 +964,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("check_universal_region: fr_minus={:?}", fr_minus); // Grow `shorter_fr` until we find a non-local - // regon. (We always will.) We'll call that + // region. (We always will.) We'll call that // `shorter_fr+` -- it's ever so slightly larger than // `fr`. let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index b2b2ca1182d..45236bbc4aa 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -150,7 +150,7 @@ pub(super) enum RegionElement { /// A point in the control-flow graph. Location(Location), - /// An in-scope, universally quantified region (e.g., a liftime parameter). + /// An in-scope, universally quantified region (e.g., a lifetime parameter). UniversalRegion(RegionVid), } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 8053a0a6948..58ce572ae8d 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Code related to match expresions. These are sufficiently complex +//! Code related to match expressions. These are sufficiently complex //! to warrant their own module and submodules. :) This main module //! includes the high-level algorithm, the submodules contain the //! details. diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index e798cc93cb0..8ab4035cf4a 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -80,14 +80,14 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> { /// tracking (phased) borrows. It computes where a borrow is reserved; /// i.e. where it can reach in the control flow starting from its /// initial `assigned = &'rgn borrowed` statement, and ending -/// whereever `'rgn` itself ends. +/// wherever `'rgn` itself ends. pub(crate) struct Reservations<'a, 'gcx: 'tcx, 'tcx: 'a>(pub(crate) Borrows<'a, 'gcx, 'tcx>); /// The `ActiveBorrows` analysis is the second of the two flow /// analyses tracking (phased) borrows. It computes where any given /// borrow `&assigned = &'rgn borrowed` is *active*, which starts at /// the first use of `assigned` after the reservation has started, and -/// ends whereever `'rgn` itself ends. +/// ends wherever `'rgn` itself ends. pub(crate) struct ActiveBorrows<'a, 'gcx: 'tcx, 'tcx: 'a>(pub(crate) Borrows<'a, 'gcx, 'tcx>); impl<'a, 'gcx, 'tcx> Reservations<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 619c0dc847e..3491faf9cda 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -365,7 +365,7 @@ with `#[derive(Clone)]`. Some types have no ownership semantics at all and are trivial to duplicate. An example is `i32` and the other number types. We don't have to call `.clone()` to clone them, because they are marked `Copy` in addition to `Clone`. Implicit -cloning is more convienient in this case. We can mark our own types `Copy` if +cloning is more convenient in this case. We can mark our own types `Copy` if all their members also are marked `Copy`. In the example below, we implement a `Point` type. Because it only stores two diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 52b87282180..3578164feb7 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -84,7 +84,7 @@ pub struct Frame<'tcx> { /// return). pub block: mir::BasicBlock, - /// The index of the currently evaluated statment. + /// The index of the currently evaluated statement. pub stmt: usize, } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 86a4dd4a31f..a5078187a57 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -68,7 +68,7 @@ pub enum InstantiationMode { /// however, our local copy may conflict with other crates also /// inlining the same function. /// - /// This flag indicates that this situation is occuring, and informs + /// This flag indicates that this situation is occurring, and informs /// symbol name calculation that some extra mangling is needed to /// avoid conflicts. Note that this may eventually go away entirely if /// ThinLTO enables us to *always* have a globally shared instance of a diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index b46882f054d..6ae04760953 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -781,7 +781,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { // Additionally, until better reachability analysis for macros 2.0 is available, // we prohibit access to private statics from other crates, this allows to give // more code internal visibility at link time. (Access to private functions - // is already prohibited by type privacy for funciton types.) + // is already prohibited by type privacy for function types.) fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: ast::NodeId, span: Span) { let def = match *qpath { hir::QPath::Resolved(_, ref path) => match path.def { diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 5a321053b7a..a757ac92df5 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -17,7 +17,7 @@ // `use` directives. // // Unused trait imports can't be checked until the method resolution. We save -// candidates here, and do the acutal check in librustc_typeck/check_unused.rs. +// candidates here, and do the actual check in librustc_typeck/check_unused.rs. use std::ops::{Deref, DerefMut}; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2da4bfedd3a..d8e03552a6a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1440,7 +1440,7 @@ impl<'a> Resolver<'a> { /// Rustdoc uses this to resolve things in a recoverable way. ResolutionError<'a> /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, - /// just that an error occured. + /// just that an error occurred. pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) -> Result { use std::iter; diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a8070c553bd..438ab3a3513 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -186,7 +186,7 @@ impl<'a> Resolver<'a> { } let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { - // `extern crate` are always usable for backwards compatability, see issue #37020. + // `extern crate` are always usable for backwards compatibility, see issue #37020. let usable = this.is_accessible(binding.vis) || binding.is_extern_crate(); if usable { Ok(binding) } else { Err(Determined) } }; diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index a3327038019..ab354a30d41 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -84,7 +84,7 @@ impl LtoModuleTranslation { } } - /// A "guage" of how costly it is to optimize this module, used to sort + /// A "gauge" of how costly it is to optimize this module, used to sort /// biggest modules first. pub fn cost(&self) -> u64 { match *self { @@ -726,7 +726,7 @@ impl ThinModule { // which was basically a resurgence of #45511 after LLVM's bug 35212 was // fixed. // - // This function below is a huge hack around tihs problem. The function + // This function below is a huge hack around this problem. The function // below is defined in `PassWrapper.cpp` and will basically "merge" // all `DICompileUnit` instances in a module. Basically it'll take all // the objects, rewrite all pointers of `DISubprogram` to point to the diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 5ab8d03b8c7..d4e05a18e3a 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -1240,7 +1240,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// on), and `ptr` is nonzero-sized, then extracts the size of `ptr` /// and the intrinsic for `lt` and passes them to `emit`, which is in /// charge of generating code to call the passed intrinsic on whatever - /// block of generated code is targetted for the intrinsic. + /// block of generated code is targeted for the intrinsic. /// /// If LLVM lifetime intrinsic support is disabled (i.e. optimizations /// off) or `ptr` is zero-sized, then no-op (does not call `emit`). diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 2e876ec118d..34ac44cec02 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -844,7 +844,7 @@ fn cast_float_to_int(bx: &Builder, // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits. // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two. // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly - // representable. Note that this only works if float_ty's exponent range is sufficently large. + // representable. Note that this only works if float_ty's exponent range is sufficiently large. // f16 or 256 bit integers would break this property. Right now the smallest float type is f32 // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127. // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index e14abdff339..9943a9bd398 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -151,7 +151,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { } } - Err("Couldnt find metadata section".to_string()) + Err("Couldn't find metadata section".to_string()) } fn get_dylib_metadata( diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 4e7db5f0826..9250c1c437b 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -293,7 +293,7 @@ impl Seek for BufReader { /// where `n` minus the internal buffer length overflows an `i64`, two /// seeks will be performed instead of one. If the second seek returns /// `Err`, the underlying reader will be left at the same position it would - /// have if you seeked to `SeekFrom::Current(0)`. + /// have if you called `seek` with `SeekFrom::Current(0)`. /// /// [`seek_relative`]: #method.seek_relative fn seek(&mut self, pos: SeekFrom) -> io::Result { diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 2edf02efc47..f7fdedc0d21 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -24,8 +24,8 @@ use sys_common::rwlock as sys; /// typically allows for read-only access (shared access). /// /// In comparison, a [`Mutex`] does not distinguish between readers or writers -/// that aquire the lock, therefore blocking any threads waiting for the lock to -/// become available. An `RwLock` will allow any number of readers to aquire the +/// that acquire the lock, therefore blocking any threads waiting for the lock to +/// become available. An `RwLock` will allow any number of readers to acquire the /// lock as long as a writer is not holding the lock. /// /// The priority policy of the lock is dependent on the underlying operating diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index a364a0392b3..1955f3ec9a2 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -136,7 +136,7 @@ pub fn __rust_begin_short_backtrace(f: F) -> T f() } -/// Controls how the backtrace should be formated. +/// Controls how the backtrace should be formatted. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrintFormat { /// Show all the frames with absolute path for files. diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index 934ac3edbf1..e74c40ae04b 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -98,7 +98,7 @@ pub struct PoisonError { } /// An enumeration of possible errors associated with a [`TryLockResult`] which -/// can occur while trying to aquire a lock, from the [`try_lock`] method on a +/// can occur while trying to acquire a lock, from the [`try_lock`] method on a /// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`]. /// /// [`Mutex`]: struct.Mutex.html diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c7ab6158256..8c1e5cf7586 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -918,7 +918,7 @@ pub struct Expr { } impl Expr { - /// Wether this expression would be valid somewhere that expects a value, for example, an `if` + /// Whether this expression would be valid somewhere that expects a value, for example, an `if` /// condition. pub fn returns(&self) -> bool { if let ExprKind::Block(ref block) = self.node { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index fc82357455b..aa360ed1bf5 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -114,7 +114,7 @@ impl<'a> StripUnconfigured<'a> { } } - // Determine if a node with the given attributes should be included in this configuation. + // Determine if a node with the given attributes should be included in this configuration. pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { // When not compiling with --test we should not compile the #[test] functions diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac582627f88..7915109ce3a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3912,7 +3912,7 @@ impl<'a> Parser<'a> { "use `=` if you meant to assign", "=".to_string()); err.emit(); - // As this was parsed successfuly, continue as if the code has been fixed for the + // As this was parsed successfully, continue as if the code has been fixed for the // rest of the file. It will still fail due to the emitted error, but we avoid // extra noise. init @@ -6571,7 +6571,7 @@ impl<'a> Parser<'a> { return Ok(Some(macro_def)); } - // Verify wether we have encountered a struct or method definition where the user forgot to + // Verify whether we have encountered a struct or method definition where the user forgot to // add the `struct` or `fn` keyword after writing `pub`: `pub S {}` if visibility == Visibility::Public && self.check_ident() && diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 2cf568777d4..b804bb2981b 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -14,7 +14,7 @@ fn foo(x: usize, y: !, z: usize) { } fn call_foo_a() { - // FIXME(#40800) -- accepted beacuse divergence happens **before** + // FIXME(#40800) -- accepted because divergence happens **before** // the coercion to `!`, but within same expression. Not clear that // these are the rules we want. foo(return, 22, 44); diff --git a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs index 9177dcba0d7..4ef92981314 100644 --- a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs +++ b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test not a test, auxillary +// ignore-test not a test, auxiliary diff --git a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs index e29c985b983..41a8c288e7c 100644 --- a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs +++ b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test not a test, auxillary +// ignore-test not a test, auxiliary mod_decl!(bar); diff --git a/src/test/compile-fail/hr-subtype.rs b/src/test/compile-fail/hr-subtype.rs index c88d74d53ce..86df2382732 100644 --- a/src/test/compile-fail/hr-subtype.rs +++ b/src/test/compile-fail/hr-subtype.rs @@ -84,7 +84,7 @@ check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), fn(Inv<'y>)) } // Somewhat surprisingly, a fn taking two distinct bound lifetimes and -// a fn taking one bound lifetime can be interchangable, but only if +// a fn taking one bound lifetime can be interchangeable, but only if // we are co- or contra-variant with respect to both lifetimes. // // The reason is: @@ -100,7 +100,7 @@ check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b> check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>, for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>) } -// If we make those lifetimes invariant, then the two types are not interchangable. +// If we make those lifetimes invariant, then the two types are not interchangeable. check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), for<'a> fn(Inv<'a>, Inv<'a>)) } check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32, diff --git a/src/test/compile-fail/issue-20616-1.rs b/src/test/compile-fail/issue-20616-1.rs index a1949df661a..3e29383d62c 100644 --- a/src/test/compile-fail/issue-20616-1.rs +++ b/src/test/compile-fail/issue-20616-1.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-2.rs b/src/test/compile-fail/issue-20616-2.rs index 87b836d6872..1ec7a74559a 100644 --- a/src/test/compile-fail/issue-20616-2.rs +++ b/src/test/compile-fail/issue-20616-2.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-3.rs b/src/test/compile-fail/issue-20616-3.rs index e5ed46d2cb3..885fd246547 100644 --- a/src/test/compile-fail/issue-20616-3.rs +++ b/src/test/compile-fail/issue-20616-3.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-4.rs b/src/test/compile-fail/issue-20616-4.rs index 9b731289e13..0dbe92fc1bc 100644 --- a/src/test/compile-fail/issue-20616-4.rs +++ b/src/test/compile-fail/issue-20616-4.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-5.rs b/src/test/compile-fail/issue-20616-5.rs index 5e3b024da9a..794e5178f4b 100644 --- a/src/test/compile-fail/issue-20616-5.rs +++ b/src/test/compile-fail/issue-20616-5.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-6.rs b/src/test/compile-fail/issue-20616-6.rs index b6ee26f9f62..fe91751a4a0 100644 --- a/src/test/compile-fail/issue-20616-6.rs +++ b/src/test/compile-fail/issue-20616-6.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-7.rs b/src/test/compile-fail/issue-20616-7.rs index fef3dd4e31d..184ad027102 100644 --- a/src/test/compile-fail/issue-20616-7.rs +++ b/src/test/compile-fail/issue-20616-7.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-8.rs b/src/test/compile-fail/issue-20616-8.rs index b7bef47c4f4..5cdec33e94b 100644 --- a/src/test/compile-fail/issue-20616-8.rs +++ b/src/test/compile-fail/issue-20616-8.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/issue-20616-9.rs b/src/test/compile-fail/issue-20616-9.rs index 5c16d24cef8..7995addb692 100644 --- a/src/test/compile-fail/issue-20616-9.rs +++ b/src/test/compile-fail/issue-20616-9.rs @@ -9,7 +9,7 @@ // except according to those terms. // We need all these 9 issue-20616-N.rs files -// becase we can only catch one parsing error at a time +// because we can only catch one parsing error at a time diff --git a/src/test/compile-fail/no_crate_type.rs b/src/test/compile-fail/no_crate_type.rs index bef909917d2..b2cc5cae697 100644 --- a/src/test/compile-fail/no_crate_type.rs +++ b/src/test/compile-fail/no_crate_type.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// regresion test for issue 11256 +// regression test for issue 11256 #![crate_type] //~ ERROR `crate_type` requires a value fn main() { diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md index b00b35aa29f..ad4932b9fb9 100644 --- a/src/test/mir-opt/README.md +++ b/src/test/mir-opt/README.md @@ -26,7 +26,7 @@ other non-matched lines before and after, but not between $expected_lines, should you want to skip lines, you must include an elision comment, of the form (as a regex) `//\s*...\s*`. The lines will be skipped lazily, that is, if there are two identical lines in the output that match the line after the elision -comment, the first one wil be matched. +comment, the first one will be matched. Examples: diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 1c443020d2e..17e6119f968 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -255,7 +255,7 @@ fn _11() { while true { let _ = #[attr] break ; } || #[attr] return; let _ = #[attr] expr_mac!(); - /* FIXME: pp bug, loosing delimiter styles + /* FIXME: pp bug, losing delimiter styles let _ = #[attr] expr_mac![]; let _ = #[attr] expr_mac!{}; */ diff --git a/src/test/run-make/hotplug_codegen_backend/Makefile b/src/test/run-make/hotplug_codegen_backend/Makefile index 9a216d1d81f..2ddf3aa5439 100644 --- a/src/test/run-make/hotplug_codegen_backend/Makefile +++ b/src/test/run-make/hotplug_codegen_backend/Makefile @@ -6,4 +6,4 @@ all: -o $(TMPDIR)/the_backend.dylib $(RUSTC) some_crate.rs --crate-name some_crate --crate-type bin -o $(TMPDIR)/some_crate \ -Z codegen-backend=$(TMPDIR)/the_backend.dylib -Z unstable-options - grep -x "This has been \"compiled\" succesfully." $(TMPDIR)/some_crate + grep -x "This has been \"compiled\" successfully." $(TMPDIR)/some_crate diff --git a/src/test/run-make/hotplug_codegen_backend/the_backend.rs b/src/test/run-make/hotplug_codegen_backend/the_backend.rs index 5972149590c..9e87268e699 100644 --- a/src/test/run-make/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make/hotplug_codegen_backend/the_backend.rs @@ -69,7 +69,7 @@ impl TransCrate for TheBackend { let output_name = out_filename(sess, crate_type, &outputs, &*crate_name.as_str()); let mut out_file = ::std::fs::File::create(output_name).unwrap(); - write!(out_file, "This has been \"compiled\" succesfully.").unwrap(); + write!(out_file, "This has been \"compiled\" successfully.").unwrap(); } Ok(()) } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs index 24865ea2709..cfaf913216a 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test not a test, auxillary +// ignore-test not a test, auxiliary #![feature(macro_reexport)] diff --git a/src/test/run-pass/issue-29746.rs b/src/test/run-pass/issue-29746.rs index 61c601ac6a9..d4463fed1a6 100644 --- a/src/test/run-pass/issue-29746.rs +++ b/src/test/run-pass/issue-29746.rs @@ -17,7 +17,7 @@ macro_rules! zip { }; // Intermediate steps to build the zipped expression, the match pattern, and - // and the output tuple of the closure, using macro hygene to repeatedly + // and the output tuple of the closure, using macro hygiene to repeatedly // introduce new variables named 'x'. ([$a:expr, $($rest:expr),*], $zip:expr, $pat:pat, [$($flat:expr),*]) => { zip!([$($rest),*], $zip.zip($a), ($pat,x), [$($flat),*, x]) diff --git a/src/test/run-pass/issue-32008.rs b/src/test/run-pass/issue-32008.rs index cb489acf1d9..95890d2e1b4 100644 --- a/src/test/run-pass/issue-32008.rs +++ b/src/test/run-pass/issue-32008.rs @@ -9,7 +9,7 @@ // except according to those terms. // Tests that binary operators allow subtyping on both the LHS and RHS, -// and as such do not introduce unnecesarily strict lifetime constraints. +// and as such do not introduce unnecessarily strict lifetime constraints. use std::ops::Add; diff --git a/src/test/run-pass/rfc1857-drop-order.rs b/src/test/run-pass/rfc1857-drop-order.rs index b2e5ff62eb8..94b2a586ddf 100644 --- a/src/test/run-pass/rfc1857-drop-order.rs +++ b/src/test/run-pass/rfc1857-drop-order.rs @@ -67,7 +67,7 @@ fn test_drop_tuple() { panic::catch_unwind(|| { (PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D")); + panic!("this panic is caught :D")); }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); } @@ -99,7 +99,7 @@ fn test_drop_struct() { TestStruct { x: PushOnDrop::new(2, cloned.clone()), y: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -111,7 +111,7 @@ fn test_drop_struct() { TestStruct { y: PushOnDrop::new(2, cloned.clone()), x: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -122,7 +122,7 @@ fn test_drop_struct() { panic::catch_unwind(|| { TestTupleStruct(PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D")); + panic!("this panic is caught :D")); }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); } @@ -154,7 +154,7 @@ fn test_drop_enum() { TestEnum::Struct { x: PushOnDrop::new(2, cloned.clone()), y: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -166,7 +166,7 @@ fn test_drop_enum() { TestEnum::Struct { y: PushOnDrop::new(2, cloned.clone()), x: PushOnDrop::new(1, cloned.clone()), - z: panic!("this panic is catched :D") + z: panic!("this panic is caught :D") }; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -177,7 +177,7 @@ fn test_drop_enum() { panic::catch_unwind(|| { TestEnum::Tuple(PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D")); + panic!("this panic is caught :D")); }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); } @@ -207,7 +207,7 @@ fn test_drop_list() { vec![ PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D") + panic!("this panic is caught :D") ]; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); @@ -219,7 +219,7 @@ fn test_drop_list() { [ PushOnDrop::new(2, cloned.clone()), PushOnDrop::new(1, cloned.clone()), - panic!("this panic is catched :D") + panic!("this panic is caught :D") ]; }).err().unwrap(); assert_eq!(*dropped_fields.borrow(), &[1, 2]); diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs index 2c9ef59709d..3c54921ac6e 100644 --- a/src/test/run-pass/simd-target-feature-mixup.rs +++ b/src/test/run-pass/simd-target-feature-mixup.rs @@ -30,7 +30,7 @@ fn main() { // We don't actually know if our computer has the requisite target features // for the test below. Testing for that will get added to libstd later so - // for now just asume sigill means this is a machine that can't run this test. + // for now just assume sigill means this is a machine that can't run this test. if is_sigill(status) { println!("sigill with {}, assuming spurious", level); continue diff --git a/src/test/rustdoc/impl-parts-crosscrate.rs b/src/test/rustdoc/impl-parts-crosscrate.rs index 5fa2e03e0a8..1d055ccbead 100644 --- a/src/test/rustdoc/impl-parts-crosscrate.rs +++ b/src/test/rustdoc/impl-parts-crosscrate.rs @@ -17,7 +17,7 @@ extern crate rustdoc_impl_parts_crosscrate; pub struct Bar { t: T } -// The output file is html embeded in javascript, so the html tags +// The output file is html embedded in javascript, so the html tags // aren't stripped by the processing script and we can't check for the // full impl string. Instead, just make sure something from each part // is mentioned. diff --git a/src/test/ui/explain.stdout b/src/test/ui/explain.stdout index 0bbbd95320a..411cdfb335b 100644 --- a/src/test/ui/explain.stdout +++ b/src/test/ui/explain.stdout @@ -45,7 +45,7 @@ is a function pointer, which is not zero-sized. This pattern should be rewritten. There are a few possible ways to do this: - change the original fn declaration to match the expected signature, - and do the cast in the fn body (the prefered option) + and do the cast in the fn body (the preferred option) - cast the fn item fo a fn pointer before calling transmute, as shown here: ``` diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 029949b2604..21950402c8c 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -509,7 +509,7 @@ mod reexport_test_harness_main { //~^ WARN unused attribute } -// Cannnot feed "2700" to `#[macro_escape]` without signaling an error. +// Cannot feed "2700" to `#[macro_escape]` without signaling an error. #[macro_escape] //~^ WARN macro_escape is a deprecated synonym for macro_use mod macro_escape { diff --git a/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs b/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs index d4ef87cdd76..20a2cbfd3aa 100644 --- a/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs +++ b/src/test/ui/lifetime-errors/liveness-assign-imm-local-notes.rs @@ -9,7 +9,7 @@ // except according to those terms. // FIXME: Change to UI Test -// Check notes are placed on an assignment that can actually preceed the current assigmnent +// Check notes are placed on an assignment that can actually precede the current assigmnent // Don't emmit a first assignment for assignment in a loop. // compile-flags: -Zborrowck=compare -- cgit 1.4.1-3-g733a5 From d549db8031a07b79009f9efe8b3233cd8900c82b Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Sat, 17 Feb 2018 09:17:58 -0800 Subject: Fix tidy violation --- src/libstd/sync/condvar.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 546e105deb7..7f9b5667628 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -466,9 +466,11 @@ impl Condvar { /// /// // wait for the thread to start up /// let &(ref lock, ref cvar) = &*pair; - /// let result = cvar.wait_timeout_until(lock.lock().unwrap(), Duration::from_millis(100), |started| { - /// *started - /// }).unwrap(); + /// let result = cvar.wait_timeout_until( + /// lock.lock().unwrap(), + /// Duration::from_millis(100), + /// |started| started, + /// ).unwrap(); /// if result.1.timed_out() { /// // timed-out without the condition ever evaluating to true. /// } -- cgit 1.4.1-3-g733a5 From 0a798bd95251acbf59fca531a8e20d8221eb1a7b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 17 Feb 2018 20:54:26 -0500 Subject: Unify 'Platform-specific behavior' documentation headings. --- src/libstd/net/tcp.rs | 8 ++++---- src/libstd/net/udp.rs | 4 ++-- src/libstd/thread/mod.rs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 78235ea1b4b..263a2c13249 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -262,7 +262,7 @@ impl TcpStream { /// indefinitely. It is an error to pass the zero `Duration` to this /// method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a read times out as /// a result of setting this option. For example Unix typically returns an @@ -293,7 +293,7 @@ impl TcpStream { /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a write times out /// as a result of setting this option. For example Unix typically returns @@ -323,7 +323,7 @@ impl TcpStream { /// /// If the timeout is [`None`], then [`read`] calls will block indefinitely. /// - /// # Note + /// # Platform-specific behavior /// /// Some platforms do not provide access to the current timeout. /// @@ -349,7 +349,7 @@ impl TcpStream { /// /// If the timeout is [`None`], then [`write`] calls will block indefinitely. /// - /// # Note + /// # Platform-specific behavior /// /// Some platforms do not provide access to the current timeout. /// diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index fc7f9205d06..5e19519b88f 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -231,7 +231,7 @@ impl UdpSocket { /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a read times out as /// a result of setting this option. For example Unix typically returns an @@ -262,7 +262,7 @@ impl UdpSocket { /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// - /// # Note + /// # Platform-specific behavior /// /// Platforms may return a different error code whenever a write times out /// as a result of setting this option. For example Unix typically returns diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index ee49bf796b8..ff121e2d7ee 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -652,7 +652,7 @@ pub fn panicking() -> bool { /// The thread may sleep longer than the duration specified due to scheduling /// specifics or platform-dependent functionality. /// -/// # Platform behavior +/// # Platform-specific behavior /// /// On Unix platforms this function will not return early due to a /// signal being received or a spurious wakeup. @@ -676,7 +676,7 @@ pub fn sleep_ms(ms: u32) { /// The thread may sleep longer than the duration specified due to scheduling /// specifics or platform-dependent functionality. /// -/// # Platform behavior +/// # Platform-specific behavior /// /// On Unix platforms this function will not return early due to a /// signal being received or a spurious wakeup. Platforms which do not support @@ -837,7 +837,7 @@ pub fn park_timeout_ms(ms: u32) { /// /// See the [park documentation][park] for more details. /// -/// # Platform behavior +/// # Platform-specific behavior /// /// Platforms which do not support nanosecond precision for sleeping will have /// `dur` rounded up to the nearest granularity of time they can sleep for. -- cgit 1.4.1-3-g733a5 From 472dcdb4ecb3fbea4b3e2b1d5952adc1d0f6cc76 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 17 Feb 2018 20:57:00 -0500 Subject: Fix broken documentation link. --- src/libstd/sys/unix/ext/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 86b0f35be92..31bdc5ea1f5 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -415,7 +415,7 @@ impl UnixStream { /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples -- cgit 1.4.1-3-g733a5 From 872c782a558891a82011d14672de5e888f6336de Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 18 Feb 2018 09:30:10 -0500 Subject: Mark doc examples w/ `extern` blocks as `ignore`. Fixes https://github.com/rust-lang/rust/issues/48218. --- src/libstd/ffi/c_str.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index e91d3a32a50..2519d830435 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -91,7 +91,7 @@ use sys; /// /// # Examples /// -/// ```no_run +/// ```ignore (extern-declaration) /// # fn main() { /// use std::ffi::CString; /// use std::os::raw::c_char; @@ -150,7 +150,7 @@ pub struct CString { /// /// Inspecting a foreign C string: /// -/// ```no_run +/// ```ignore (extern-declaration) /// use std::ffi::CStr; /// use std::os::raw::c_char; /// @@ -164,7 +164,7 @@ pub struct CString { /// /// Passing a Rust-originating C string: /// -/// ```no_run +/// ```ignore (extern-declaration) /// use std::ffi::{CString, CStr}; /// use std::os::raw::c_char; /// @@ -180,7 +180,7 @@ pub struct CString { /// /// Converting a foreign C string into a Rust [`String`]: /// -/// ```no_run +/// ```ignore (extern-declaration) /// use std::ffi::CStr; /// use std::os::raw::c_char; /// @@ -307,7 +307,7 @@ impl CString { /// /// # Examples /// - /// ```no_run + /// ```ignore (extern-declaration) /// use std::ffi::CString; /// use std::os::raw::c_char; /// @@ -389,7 +389,7 @@ impl CString { /// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake /// ownership with `from_raw`: /// - /// ```no_run + /// ```ignore (extern-declaration) /// use std::ffi::CString; /// use std::os::raw::c_char; /// @@ -882,7 +882,7 @@ impl CStr { /// /// # Examples /// - /// ```no_run + /// ```ignore (extern-declaration) /// # fn main() { /// use std::ffi::CStr; /// use std::os::raw::c_char; -- cgit 1.4.1-3-g733a5 From d17d645ad75c797a293ccf1fa3881853617f292c Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 18 Feb 2018 16:08:48 -0500 Subject: Add tests ensuring zero-Duration timeouts result in errors. Part of https://github.com/rust-lang/rust/issues/48311 --- src/libstd/net/tcp.rs | 20 ++++++++++++++++++++ src/libstd/net/udp.rs | 17 +++++++++++++++++ src/libstd/sys/unix/ext/net.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 78235ea1b4b..ee63e185ddb 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -1545,6 +1545,26 @@ mod tests { drop(listener); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&addr)); + let stream = t!(TcpStream::connect(&addr)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); + } + #[test] fn nodelay() { let addr = next_test_ip4(); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index fc7f9205d06..4163bec000b 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -1024,6 +1024,23 @@ mod tests { assert!(start.elapsed() > Duration::from_millis(400)); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let socket = t!(UdpSocket::bind(&addr)); + + let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + } + #[test] fn connect_send_recv() { let addr = next_test_ip4(); diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 86b0f35be92..f1bf8f240d3 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -1410,7 +1410,7 @@ impl IntoRawFd for UnixDatagram { #[cfg(all(test, not(target_os = "emscripten")))] mod test { use thread; - use io; + use io::{self, ErrorKind}; use io::prelude::*; use time::Duration; use sys_common::io::test::tmpdir; @@ -1613,6 +1613,27 @@ mod test { assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_unix_stream_timeout_zero_duration() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let stream = or_panic!(UnixStream::connect(&socket_path)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); + } + #[test] fn test_unix_datagram() { let dir = tmpdir(); @@ -1712,6 +1733,24 @@ mod test { thread.join().unwrap(); } + // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors + // when passed zero Durations + #[test] + fn test_unix_datagram_timeout_zero_duration() { + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let datagram = or_panic!(UnixDatagram::bind(&path)); + + let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + } + #[test] fn abstract_namespace_not_allowed() { assert!(UnixStream::connect("\0asdf").is_err()); -- cgit 1.4.1-3-g733a5 From f0a968eada509f71971e3ece02f8ec91b6f79e8a Mon Sep 17 00:00:00 2001 From: Andreas Streichardt Date: Mon, 19 Feb 2018 17:19:30 +0100 Subject: Add missing link --- src/libstd/io/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index aa07f64b678..d403bf6bfe5 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1506,6 +1506,8 @@ pub trait BufRead: Read { /// error is encountered then `buf` may contain some bytes already read in /// the event that all data read so far was valid UTF-8. /// + /// [`read_until`]: #method.read_until + /// /// # Examples /// /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In -- cgit 1.4.1-3-g733a5 From 33f5ceee1f2183b979aa0eccea7081ac7e43adfb Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 18 Feb 2018 16:57:21 -0700 Subject: stage0 cfg cleanup --- src/libcore/any.rs | 26 -------------------------- src/librustc/lib.rs | 1 - src/librustc_const_eval/lib.rs | 1 - src/librustc_driver/lib.rs | 8 -------- src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/librustc_passes/lib.rs | 1 - src/librustc_plugin/lib.rs | 1 - src/librustc_privacy/lib.rs | 1 - src/librustc_resolve/lib.rs | 1 - src/librustc_trans/lib.rs | 2 -- src/librustc_trans_utils/lib.rs | 1 - src/librustc_typeck/lib.rs | 1 - src/librustdoc/Cargo.toml | 2 -- src/libstd/lib.rs | 1 - src/libsyntax/lib.rs | 1 - 16 files changed, 50 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 566bfe2a3fb..a6ba53087ac 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -349,31 +349,6 @@ pub struct TypeId { } impl TypeId { - /// Returns the `TypeId` of the type this generic function has been - /// instantiated with. - /// - /// # Examples - /// - /// ``` - /// use std::any::{Any, TypeId}; - /// - /// fn is_string(_s: &T) -> bool { - /// TypeId::of::() == TypeId::of::() - /// } - /// - /// fn main() { - /// assert_eq!(is_string(&0), false); - /// assert_eq!(is_string(&"cookie monster".to_string()), true); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - pub fn of() -> TypeId { - TypeId { - t: unsafe { intrinsics::type_id::() }, - } - } - /// Returns the `TypeId` of the type this generic function has been /// instantiated with. /// @@ -393,7 +368,6 @@ impl TypeId { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="const_type_id")] - #[cfg(not(stage0))] pub const fn of() -> TypeId { TypeId { t: unsafe { intrinsics::type_id::() }, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a7a26195059..9520fa96856 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -179,5 +179,4 @@ fn noop() { // Build the diagnostics array at the end so that the metadata includes error use sites. -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc, DIAGNOSTICS } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index b4563f6cf2e..9d636b48bd0 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -56,5 +56,4 @@ pub fn provide(providers: &mut Providers) { } // Build the diagnostics array at the end so that the metadata includes error use sites. -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 05dcaf73135..f872fd47546 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1478,14 +1478,6 @@ pub fn monitor(f: F) { } } -#[cfg(stage0)] -pub fn diagnostics_registry() -> errors::registry::Registry { - use errors::registry::Registry; - - Registry::new(&[]) -} - -#[cfg(not(stage0))] pub fn diagnostics_registry() -> errors::registry::Registry { use errors::registry::Registry; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 33075e40432..2d015fa81f9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -59,5 +59,4 @@ pub mod cstore; pub mod dynamic_lib; pub mod locator; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 1699ad0f19c..8c15d1cf8b0 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -79,5 +79,4 @@ pub fn provide(providers: &mut Providers) { providers.const_eval = interpret::const_eval_provider; } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_mir, DIAGNOSTICS } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 73c71ec0b2f..7db1f5665fb 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -44,7 +44,6 @@ pub mod loops; mod mir_stats; pub mod static_recursion; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_passes, DIAGNOSTICS } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 38df5986ce2..c0f830f1fbe 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -82,5 +82,4 @@ pub mod registry; pub mod load; pub mod build; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_plugin, DIAGNOSTICS } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 6ae04760953..e9f970d886f 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1717,5 +1717,4 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Rc::new(visitor.access_levels) } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d8e03552a6a..a9ba278ea74 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -4183,5 +4183,4 @@ pub enum MakeGlobMap { No, } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_resolve, DIAGNOSTICS } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 908d3790170..6c281ab5e7a 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -194,7 +194,6 @@ impl TransCrate for LlvmTransCrate { llvm_util::print_version(); } - #[cfg(not(stage0))] fn diagnostics(&self) -> &[(&'static str, &'static str)] { &DIAGNOSTICS } @@ -404,5 +403,4 @@ struct CrateInfo { used_crates_dynamic: Vec<(CrateNum, LibSource)>, } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 9b7ab204492..bfecb201983 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -119,5 +119,4 @@ pub fn find_exported_symbols<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { }).collect() } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index bd7e200d620..af32738d9d0 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -383,5 +383,4 @@ pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: (principal, projections) } -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 09d0a0f610b..cfbb0a52b88 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -6,8 +6,6 @@ version = "0.0.0" [lib] name = "rustdoc" path = "lib.rs" -# SNAP/stage0(cargo) -doctest = false [dependencies] pulldown-cmark = { version = "0.1.0", default-features = false } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3c9004cdd19..854cefcb597 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -324,7 +324,6 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] -#![cfg_attr(stage0, feature(repr_align))] #![default_lib_allocator] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9181cca215c..14e39b5af42 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -152,5 +152,4 @@ pub mod ext { #[cfg(test)] mod test_snippet; -#[cfg(not(stage0))] // remove after the next snapshot __build_diagnostic_array! { libsyntax, DIAGNOSTICS } -- cgit 1.4.1-3-g733a5 From 14b403c91ab9a1e4b776e00adcd9d88153e3b736 Mon Sep 17 00:00:00 2001 From: Vitali Lovich Date: Tue, 20 Feb 2018 13:07:21 -0800 Subject: Fix doc compile error --- src/libstd/sync/condvar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 7f9b5667628..3e40cbb37e3 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -469,7 +469,7 @@ impl Condvar { /// let result = cvar.wait_timeout_until( /// lock.lock().unwrap(), /// Duration::from_millis(100), - /// |started| started, + /// |&mut started| started, /// ).unwrap(); /// if result.1.timed_out() { /// // timed-out without the condition ever evaluating to true. -- cgit 1.4.1-3-g733a5 From 0d0a470b89df7b859ce048e29873621c957e29d8 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Tue, 20 Feb 2018 18:53:56 -0500 Subject: Make signature of Path::strip_prefix un-bizarre BREAKING CHANGE: This has the potential to cause regressions in type inference. --- src/libstd/path.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index e03a182653e..527246fe1cd 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -297,10 +297,9 @@ pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP; // Iterate through `iter` while it matches `prefix`; return `None` if `prefix` // is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving // `iter` after having exhausted `prefix`. -fn iter_after(mut iter: I, mut prefix: J) -> Option - where I: Iterator + Clone, - J: Iterator, - A: PartialEq +fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option + where I: Iterator> + Clone, + J: Iterator>, { loop { let mut iter_next = iter.clone(); @@ -1865,7 +1864,7 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::Path; + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("/test/haha/foo.txt"); /// @@ -1876,16 +1875,19 @@ impl Path { /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("test").is_ok(), false); /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); + /// + /// let prefix = PathBuf::from("/test/"); + /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); /// ``` #[stable(since = "1.7.0", feature = "path_strip_prefix")] - pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P) - -> Result<&'a Path, StripPrefixError> + pub fn strip_prefix<'a, P>(&'a self, base: P) + -> Result<&'a Path, StripPrefixError> where P: AsRef { self._strip_prefix(base.as_ref()) } - fn _strip_prefix<'a>(&'a self, base: &'a Path) + fn _strip_prefix<'a>(&'a self, base: &Path) -> Result<&'a Path, StripPrefixError> { iter_after(self.components(), base.components()) .map(|c| c.as_path()) -- cgit 1.4.1-3-g733a5 From a47fd3df89c267829d96748b3bdff305f20d27d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 20 Feb 2018 13:49:54 -0500 Subject: make `#[unwind]` attribute specify expectations more clearly You can now choose between the following: - `#[unwind(allowed)]` - `#[unwind(aborts)]` Per rust-lang/rust#48251, the default is `#[unwind(allowed)]`, though I think we should change this eventually. --- src/libcore/panicking.rs | 3 ++- src/libpanic_unwind/gcc.rs | 3 ++- src/libpanic_unwind/lib.rs | 3 ++- src/libpanic_unwind/seh64_gnu.rs | 3 ++- src/libpanic_unwind/windows.rs | 9 +++++--- src/librustc_mir/build/mod.rs | 19 +++++++++++---- src/libstd/panicking.rs | 6 +++-- src/libsyntax/attr.rs | 45 ++++++++++++++++++++++++++++++++++++ src/libsyntax/diagnostic_list.rs | 27 ++++++++++++++++++++++ src/libsyntax/feature_gate.rs | 2 +- src/libunwind/libunwind.rs | 9 +++++--- src/test/codegen/extern-functions.rs | 2 +- src/test/run-pass/abort-on-c-abi.rs | 1 + 13 files changed, 113 insertions(+), 19 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 4170d91e5fc..94db0baa3f9 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -64,7 +64,8 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; } let (file, line, col) = *file_line_col; diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 63e44f71a3a..ca2fd561cad 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -286,7 +286,8 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) // See docs in the `unwind` module. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] #[lang = "eh_unwind_resume"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception); } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 92e40e8f26d..a5cebc3e4d0 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -112,7 +112,8 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 0a9fa7d9a80..090cd095380 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -108,7 +108,8 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO } #[lang = "eh_unwind_resume"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { let params = [panic_ctx as c::ULONG_PTR]; c::RaiseException(RUST_PANIC, diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs index a7e90071cea..50fba5faee7 100644 --- a/src/libpanic_unwind/windows.rs +++ b/src/libpanic_unwind/windows.rs @@ -79,18 +79,21 @@ pub enum EXCEPTION_DISPOSITION { pub use self::EXCEPTION_DISPOSITION::*; extern "system" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, lpArguments: *const ULONG_PTR); - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn RtlUnwindEx(TargetFrame: LPVOID, TargetIp: LPVOID, ExceptionRecord: *const EXCEPTION_RECORD, ReturnValue: LPVOID, OriginalContext: *const CONTEXT, HistoryTable: *const UNWIND_HISTORY_TABLE); - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 57059cd31a1..a325cfe3eaa 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -28,6 +28,7 @@ use std::mem; use std::u32; use syntax::abi::Abi; use syntax::ast; +use syntax::attr::{self, UnwindAttr}; use syntax::symbol::keywords; use syntax_pos::Span; use transform::MirSource; @@ -355,10 +356,9 @@ macro_rules! unpack { } fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_id: ast::NodeId, + fn_def_id: DefId, abi: Abi) -> bool { - // Not callable from C, so we can safely unwind through these if abi == Abi::Rust || abi == Abi::RustCall { return false; } @@ -370,9 +370,17 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // This is a special case: some functions have a C abi but are meant to // unwind anyway. Don't stop them. - if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; } + let attrs = &tcx.get_attrs(fn_def_id); + match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) { + None => { + // FIXME(rust-lang/rust#48251) -- Had to disable + // abort-on-panic for backwards compatibility reasons. + false + } - return true; + Some(UnwindAttr::Allowed) => false, + Some(UnwindAttr::Aborts) => true, + } } /////////////////////////////////////////////////////////////////////////// @@ -399,13 +407,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, safety, return_ty); + let fn_def_id = tcx.hir.local_def_id(fn_id); let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id); let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id); let mut block = START_BLOCK; let source_info = builder.source_info(span); let call_site_s = (call_site_scope, source_info); unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| { - if should_abort_on_panic(tcx, fn_id, abi) { + if should_abort_on_panic(tcx, fn_def_id, abi) { builder.schedule_abort(); } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 161c3fc7113..454ac64735c 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -55,7 +55,8 @@ extern { data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] fn __rust_start_panic(data: usize, vtable: usize) -> u32; } @@ -315,7 +316,8 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] #[lang = "panic_fmt"] -#[unwind] +#[cfg_attr(stage0, unwind)] +#[cfg_attr(not(stage0), unwind(allowed))] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index d18d6f5e6bd..d0822b69aa6 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -565,6 +565,51 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In }) } +#[derive(Copy, Clone, PartialEq)] +pub enum UnwindAttr { + Allowed, + Aborts, +} + +/// Determine what `#[unwind]` attribute is present in `attrs`, if any. +pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { + let syntax_error = |attr: &Attribute| { + mark_used(attr); + diagnostic.map(|d| { + span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute"); + }); + None + }; + + attrs.iter().fold(None, |ia, attr| { + if attr.path != "unwind" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { + MetaItemKind::Word => { + syntax_error(attr) + } + MetaItemKind::List(ref items) => { + mark_used(attr); + if items.len() != 1 { + syntax_error(attr) + } else if list_contains_name(&items[..], "allowed") { + Some(UnwindAttr::Allowed) + } else if list_contains_name(&items[..], "aborts") { + Some(UnwindAttr::Aborts) + } else { + syntax_error(attr) + } + } + _ => ia, + } + }) +} + /// True if `#[inline]` or `#[inline(always)]` is present in `attrs`. pub fn requests_inline(attrs: &[Attribute]) -> bool { match find_inline_attr(None, attrs) { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index d841281e485..84ab0336f16 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -342,6 +342,33 @@ fn main() { ``` "##, +E0633: r##" +The `unwind` attribute was malformed. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +#[unwind()] // error: expected one argument +pub extern fn something() {} + +fn main() {} +``` + +The `#[unwind]` attribute should be used as follows: + +- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function + should abort the process if it attempts to unwind. This is the safer + and preferred option. + +- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function + should be allowed to unwind. This can easily result in Undefined + Behavior (UB), so be careful. + +NB. The default behavior here is "allowed", but this is unspecified +and likely to change in the future. + +"##, + } register_diagnostics! { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3b137f9570a..f1d0a70a22c 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -233,7 +233,7 @@ declare_features! ( // allow `extern "platform-intrinsic" { ... }` (active, platform_intrinsics, "1.4.0", Some(27731)), - // allow `#[unwind]` + // allow `#[unwind(..)]` // rust runtime internal (active, unwind_attributes, "1.4.0", None), diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index e6fff7963f7..aa73b11fb38 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -83,7 +83,8 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; @@ -220,7 +221,8 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) @@ -229,7 +231,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { } else { // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() extern "C" { - #[unwind] + #[cfg_attr(stage0, unwind)] + #[cfg_attr(not(stage0), unwind(allowed))] pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } diff --git a/src/test/codegen/extern-functions.rs b/src/test/codegen/extern-functions.rs index 7ee31070b26..90ee0c75680 100644 --- a/src/test/codegen/extern-functions.rs +++ b/src/test/codegen/extern-functions.rs @@ -19,7 +19,7 @@ extern { fn extern_fn(); // CHECK-NOT: Function Attrs: nounwind // CHECK: declare void @unwinding_extern_fn - #[unwind] + #[unwind(allowed)] fn unwinding_extern_fn(); } diff --git a/src/test/run-pass/abort-on-c-abi.rs b/src/test/run-pass/abort-on-c-abi.rs index 17661c0b120..5039c334f26 100644 --- a/src/test/run-pass/abort-on-c-abi.rs +++ b/src/test/run-pass/abort-on-c-abi.rs @@ -19,6 +19,7 @@ use std::io::prelude::*; use std::io; use std::process::{Command, Stdio}; +#[unwind(aborts)] extern "C" fn panic_in_ffi() { panic!("Test"); } -- cgit 1.4.1-3-g733a5 From 1eab1b19a39f54a825c9107086f0c1752b81224d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 8 Feb 2018 17:16:39 -0500 Subject: support unit tests with return values that implement `Terminaton` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend `Termination` trait with a method to determine what happens with a unit test. This commit incorporates work by Bastian Köcher . --- src/librustc_driver/driver.rs | 3 +- src/libstd/termination.rs | 7 + src/libsyntax/lib.rs | 1 + src/libsyntax/test.rs | 170 +++++++++++++++++++------ src/test/run-pass/termination-trait-in-test.rs | 28 ++++ 5 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 src/test/run-pass/termination-trait-in-test.rs (limited to 'src/libstd') diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8a1fe99105..e4600f25ea7 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -816,7 +816,8 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, &mut resolver, sess.opts.test, krate, - sess.diagnostic()) + sess.diagnostic(), + &sess.features.borrow()) }); // If we're actually rustdoc then there's no need to actually compile diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs index dc7fa53aab6..f02fad009d8 100644 --- a/src/libstd/termination.rs +++ b/src/libstd/termination.rs @@ -37,6 +37,13 @@ pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. fn report(self) -> i32; + + /// Invoked when unit tests terminate. Should panic if the unit + /// test is considered a failure. By default, invokes `report()` + /// and checks for a `0` result. + fn assert_unit_test_successful(self) where Self: Sized { + assert_eq!(self.report(), 0); + } } #[unstable(feature = "termination_trait", issue = "43301")] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9181cca215c..53ff3ccd48a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -105,6 +105,7 @@ pub mod syntax { pub use ext; pub use parse; pub use ast; + pub use tokenstream; } pub mod abi; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e73550d0719..094de6868a5 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -32,6 +32,7 @@ use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use ext::hygiene::{Mark, SyntaxContext}; use fold::Folder; +use feature_gate::Features; use util::move_map::MoveMap; use fold; use parse::{token, ParseSess}; @@ -63,6 +64,7 @@ struct TestCtxt<'a> { reexport_test_harness_main: Option, is_libtest: bool, ctxt: SyntaxContext, + features: &'a Features, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -74,7 +76,8 @@ pub fn modify_for_testing(sess: &ParseSess, resolver: &mut Resolver, should_test: bool, krate: ast::Crate, - span_diagnostic: &errors::Handler) -> ast::Crate { + span_diagnostic: &errors::Handler, + features: &Features) -> ast::Crate { // Check for #[reexport_test_harness_main = "some_name"] which // creates a `use some_name = __test::main;`. This needs to be // unconditional, so that the attribute is still marked as used in @@ -84,7 +87,8 @@ pub fn modify_for_testing(sess: &ParseSess, "reexport_test_harness_main"); if should_test { - generate_test_harness(sess, resolver, reexport_test_harness_main, krate, span_diagnostic) + generate_test_harness(sess, resolver, reexport_test_harness_main, + krate, span_diagnostic, features) } else { krate } @@ -265,16 +269,20 @@ fn generate_test_harness(sess: &ParseSess, resolver: &mut Resolver, reexport_test_harness_main: Option, krate: ast::Crate, - sd: &errors::Handler) -> ast::Crate { + sd: &errors::Handler, + features: &Features) -> ast::Crate { // Remove the entry points let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); let mark = Mark::fresh(Mark::root()); + let mut econfig = ExpansionConfig::default("test".to_string()); + econfig.features = Some(features); + let cx = TestCtxt { span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver), + ext_cx: ExtCtxt::new(sess, econfig, resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main, @@ -282,6 +290,7 @@ fn generate_test_harness(sess: &ParseSess, is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false), toplevel_reexport: None, ctxt: SyntaxContext::empty().apply_mark(mark), + features, }; mark.set_expn_info(ExpnInfo { @@ -318,71 +327,105 @@ enum HasTestSignature { fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_test_attr = attr::contains_name(&i.attrs, "test"); - fn has_test_signature(i: &ast::Item) -> HasTestSignature { + fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { match i.node { - ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false - }; - if decl.inputs.is_empty() - && no_output - && !generics.is_parameterized() { - Yes - } else { - No + ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { + // If the termination trait is active, the compiler will check that the output + // type implements the `Termination` trait as `libtest` enforces that. + let output_matches = if cx.features.termination_trait { + true + } else { + let no_output = match decl.output { + ast::FunctionRetTy::Default(..) => true, + ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, + _ => false + }; + + no_output && !generics.is_parameterized() + }; + + if decl.inputs.is_empty() && output_matches { + Yes + } else { + No + } } - } - _ => NotEvenAFunction, + _ => NotEvenAFunction, } } - if has_test_attr { + let has_test_signature = if has_test_attr { let diag = cx.span_diagnostic; - match has_test_signature(i) { - Yes => {}, - No => diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"), - NotEvenAFunction => diag.span_err(i.span, - "only functions may be used as tests"), + match has_test_signature(cx, i) { + Yes => true, + No => { + if cx.features.termination_trait { + diag.span_err(i.span, "functions used as tests can not have any arguments"); + } else { + diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"); + } + false + }, + NotEvenAFunction => { + diag.span_err(i.span, "only functions may be used as tests"); + false + }, } - } + } else { + false + }; - has_test_attr && has_test_signature(i) == Yes + has_test_attr && has_test_signature } fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_bench_attr = attr::contains_name(&i.attrs, "bench"); - fn has_test_signature(i: &ast::Item) -> bool { + fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool { match i.node { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { let input_cnt = decl.inputs.len(); - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false + + // If the termination trait is active, the compiler will check that the output + // type implements the `Termination` trait as `libtest` enforces that. + let output_matches = if cx.features.termination_trait { + true + } else { + let no_output = match decl.output { + ast::FunctionRetTy::Default(..) => true, + ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, + _ => false + }; + let tparm_cnt = generics.params.iter() + .filter(|param| param.is_type_param()) + .count(); + + no_output && tparm_cnt == 0 }; - let tparm_cnt = generics.params.iter() - .filter(|param| param.is_type_param()) - .count(); // NB: inadequate check, but we're running // well before resolve, can't get too deep. - input_cnt == 1 - && no_output && tparm_cnt == 0 + input_cnt == 1 && output_matches } _ => false } } - if has_bench_attr && !has_test_signature(i) { + let has_bench_signature = has_bench_signature(cx, i); + + if has_bench_attr && !has_bench_signature { let diag = cx.span_diagnostic; - diag.span_err(i.span, "functions used as benches must have signature \ - `fn(&mut Bencher) -> ()`"); + + if cx.features.termination_trait { + diag.span_err(i.span, "functions used as benches must have signature \ + `fn(&mut Bencher) -> impl Termination`"); + } else { + diag.span_err(i.span, "functions used as benches must have signature \ + `fn(&mut Bencher) -> ()`"); + } } - has_bench_attr && has_test_signature(i) + has_bench_attr && has_bench_signature } fn is_ignored(i: &ast::Item) -> bool { @@ -700,9 +743,52 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { }; visible_path.extend(path); - let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + // If termination feature is enabled, create a wrapper that invokes the fn + // like this: + // + // fn wrapper() { + // assert_eq!(0, real_function().report()); + // } + // + // and then put a reference to `wrapper` into the test descriptor. Otherwise, + // just put a direct reference to `real_function`. + let fn_expr = { + let base_fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + if cx.features.termination_trait { + // ::std::Termination::assert_unit_test_successful + let assert_unit_test_successful = ecx.path_global( + span, + vec![ + ecx.ident_of("std"), + ecx.ident_of("Termination"), + ecx.ident_of("assert_unit_test_successful"), + ], + ); + // || {..} + ecx.lambda( + span, + vec![], + // ::std::Termination::assert_unit_test_successful(..) + ecx.expr_call( + span, + ecx.expr_path(assert_unit_test_successful), + vec![ + // $base_fn_expr() + ecx.expr_call( + span, + base_fn_expr, + vec![], + ) + ], + ), + ) + } else { + base_fn_expr + } + }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; + // self::test::$variant_name($fn_expr) let testfn_expr = ecx.expr_call(span, ecx.expr_path(test_path(variant_name)), vec![fn_expr]); diff --git a/src/test/run-pass/termination-trait-in-test.rs b/src/test/run-pass/termination-trait-in-test.rs new file mode 100644 index 00000000000..e67e0de5c31 --- /dev/null +++ b/src/test/run-pass/termination-trait-in-test.rs @@ -0,0 +1,28 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![feature(termination_trait)] + +use std::num::ParseIntError; + +#[test] +fn is_a_num() -> Result<(), ParseIntError> { + let _: u32 = "22".parse()?; + Ok(()) +} + +#[test] +#[should_panic] +fn not_a_num() -> Result<(), ParseIntError> { + let _: u32 = "abc".parse()?; + Ok(()) +} -- cgit 1.4.1-3-g733a5 From e446f706a89e3d5c26c01318bd70904d492ab8b2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 14 Feb 2018 10:06:12 -0500 Subject: put the "unit test" logic into libtest Also make `std::termination` module public and rename feature. The lib feature needs a different name from the language feature. --- src/libstd/lib.rs | 5 +- src/libstd/termination.rs | 23 ++++----- src/libsyntax/test.rs | 60 +++++++++------------- src/libtest/lib.rs | 9 ++++ .../termination-trait-main-wrong-type.rs | 2 +- .../termination-trait-not-satisfied.rs | 2 +- 6 files changed, 47 insertions(+), 54 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3c9004cdd19..b247d121648 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -501,11 +501,10 @@ mod memchr; // The runtime entry point and a few unstable public functions used by the // compiler pub mod rt; -// The trait to support returning arbitrary types in the main function -mod termination; +// The trait to support returning arbitrary types in the main function #[unstable(feature = "termination_trait", issue = "43301")] -pub use self::termination::Termination; +pub mod termination; // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs index f02fad009d8..203870766a9 100644 --- a/src/libstd/termination.rs +++ b/src/libstd/termination.rs @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Defines the meaning of the return value from `main`, and hence +//! controls what happens in a Rust program after `main` returns. + use fmt::Debug; + #[cfg(target_arch = "wasm32")] mod exit { pub const SUCCESS: i32 = 0; @@ -30,28 +34,21 @@ mod exit { /// The default implementations are returning `libc::EXIT_SUCCESS` to indicate /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. #[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented = "`main` can only return types that implement {Termination}, not `{Self}`"] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. fn report(self) -> i32; - - /// Invoked when unit tests terminate. Should panic if the unit - /// test is considered a failure. By default, invokes `report()` - /// and checks for a `0` result. - fn assert_unit_test_successful(self) where Self: Sized { - assert_eq!(self.report(), 0); - } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for () { fn report(self) -> i32 { exit::SUCCESS } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for Result { fn report(self) -> i32 { match self { @@ -64,19 +61,19 @@ impl Termination for Result { } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for ! { fn report(self) -> i32 { unreachable!(); } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for bool { fn report(self) -> i32 { if self { exit::SUCCESS } else { exit::FAILURE } } } -#[unstable(feature = "termination_trait", issue = "43301")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for i32 { fn report(self) -> i32 { self diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6cbb7ab393f..b48713fcf7a 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -746,48 +746,36 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { }; visible_path.extend(path); - // If termination feature is enabled, create a wrapper that invokes the fn - // like this: + // Rather than directly give the test function to the test + // harness, we create a wrapper like this: // - // fn wrapper() { - // assert_eq!(0, real_function().report()); - // } + // || test::assert_test_result(real_function()) // - // and then put a reference to `wrapper` into the test descriptor. Otherwise, - // just put a direct reference to `real_function`. + // this will coerce into a fn pointer that is specialized to the + // actual return type of `real_function` (Typically `()`, but not always). let fn_expr = { - let base_fn_expr = ecx.expr_path(ecx.path_global(span, visible_path)); - if cx.features.termination_trait { - // ::std::Termination::assert_unit_test_successful - let assert_unit_test_successful = ecx.path_global( + // construct `real_function()` (this will be inserted into the overall expr) + let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path)); + // construct path `test::assert_test_result` + let assert_test_result = test_path("assert_test_result"); + // construct `|| {..}` + ecx.lambda( + span, + vec![], + // construct `assert_test_result(..)` + ecx.expr_call( span, + ecx.expr_path(assert_test_result), vec![ - ecx.ident_of("std"), - ecx.ident_of("Termination"), - ecx.ident_of("assert_unit_test_successful"), + // construct `real_function()` + ecx.expr_call( + span, + real_function_expr, + vec![], + ) ], - ); - // || {..} - ecx.lambda( - span, - vec![], - // ::std::Termination::assert_unit_test_successful(..) - ecx.expr_call( - span, - ecx.expr_path(assert_unit_test_successful), - vec![ - // $base_fn_expr() - ecx.expr_call( - span, - base_fn_expr, - vec![], - ) - ], - ), - ) - } else { - base_fn_expr - } + ), + ) }; let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" }; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 9ea5f39b71f..932952d649b 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -40,6 +40,7 @@ #![feature(set_stdio)] #![feature(panic_unwind)] #![feature(staged_api)] +#![feature(termination_trait_lib)] extern crate getopts; extern crate term; @@ -69,6 +70,7 @@ use std::iter::repeat; use std::path::PathBuf; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; +use std::termination::Termination; use std::thread; use std::time::{Instant, Duration}; use std::borrow::Cow; @@ -322,6 +324,13 @@ pub fn test_main_static(tests: &[TestDescAndFn]) { test_main(&args, owned_tests, Options::new()) } +/// Invoked when unit tests terminate. Should panic if the unit +/// test is considered a failure. By default, invokes `report()` +/// and checks for a `0` result. +pub fn assert_test_result(result: T) { + assert_eq!(result.report(), 0); +} + #[derive(Copy, Clone, Debug)] pub enum ColorConfig { AutoColor, diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index a63162cf73d..2da51851952 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -10,6 +10,6 @@ #![feature(termination_trait)] fn main() -> char { -//~^ ERROR: the trait bound `char: std::Termination` is not satisfied +//~^ ERROR: the trait bound `char: std::termination::Termination` is not satisfied ' ' } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index 788c38c55be..fac60d6d399 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -12,6 +12,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `ReturnType: std::termination::Termination` is not satisfied ReturnType {} } -- cgit 1.4.1-3-g733a5 From 5f1e78f19ad40c6265a200b41c772c321b8b08cd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 22 Feb 2018 17:36:55 -0500 Subject: move Termination trait to std::process --- src/libstd/lib.rs | 4 -- src/libstd/process.rs | 67 ++++++++++++++++++ src/libstd/rt.rs | 2 +- src/libstd/termination.rs | 81 ---------------------- src/libtest/lib.rs | 2 +- .../termination-trait-main-wrong-type.rs | 2 +- .../termination-trait-not-satisfied.rs | 2 +- 7 files changed, 71 insertions(+), 89 deletions(-) delete mode 100644 src/libstd/termination.rs (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b247d121648..bdda7416336 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -502,10 +502,6 @@ mod memchr; // compiler pub mod rt; -// The trait to support returning arbitrary types in the main function -#[unstable(feature = "termination_trait", issue = "43301")] -pub mod termination; - // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 9b2f815b713..e25599b8bd8 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1392,6 +1392,73 @@ pub fn id() -> u32 { ::sys::os::getpid() } +#[cfg(target_arch = "wasm32")] +mod exit { + pub const SUCCESS: i32 = 0; + pub const FAILURE: i32 = 1; +} +#[cfg(not(target_arch = "wasm32"))] +mod exit { + use libc; + pub const SUCCESS: i32 = libc::EXIT_SUCCESS; + pub const FAILURE: i32 = libc::EXIT_FAILURE; +} + +/// A trait for implementing arbitrary return types in the `main` function. +/// +/// The c-main function only supports to return integers as return type. +/// So, every type implementing the `Termination` trait has to be converted +/// to an integer. +/// +/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate +/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. +#[cfg_attr(not(test), lang = "termination")] +#[unstable(feature = "termination_trait_lib", issue = "43301")] +#[rustc_on_unimplemented = + "`main` can only return types that implement {Termination}, not `{Self}`"] +pub trait Termination { + /// Is called to get the representation of the value as status code. + /// This status code is returned to the operating system. + fn report(self) -> i32; +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for () { + fn report(self) -> i32 { exit::SUCCESS } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for Result { + fn report(self) -> i32 { + match self { + Ok(val) => val.report(), + Err(err) => { + eprintln!("Error: {:?}", err); + exit::FAILURE + } + } + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for ! { + fn report(self) -> i32 { unreachable!(); } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for bool { + fn report(self) -> i32 { + if self { exit::SUCCESS } else { exit::FAILURE } + } +} + +#[unstable(feature = "termination_trait_lib", issue = "43301")] +impl Termination for i32 { + fn report(self) -> i32 { + self + } +} + #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] mod tests { use io::prelude::*; diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 9dbaf784f89..e1392762a59 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -68,7 +68,7 @@ fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), #[cfg(not(test))] #[lang = "start"] -fn lang_start +fn lang_start (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize { lang_start_internal(&move || main().report(), argc, argv) diff --git a/src/libstd/termination.rs b/src/libstd/termination.rs deleted file mode 100644 index 203870766a9..00000000000 --- a/src/libstd/termination.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Defines the meaning of the return value from `main`, and hence -//! controls what happens in a Rust program after `main` returns. - -use fmt::Debug; - -#[cfg(target_arch = "wasm32")] -mod exit { - pub const SUCCESS: i32 = 0; - pub const FAILURE: i32 = 1; -} -#[cfg(not(target_arch = "wasm32"))] -mod exit { - use libc; - pub const SUCCESS: i32 = libc::EXIT_SUCCESS; - pub const FAILURE: i32 = libc::EXIT_FAILURE; -} - -/// A trait for implementing arbitrary return types in the `main` function. -/// -/// The c-main function only supports to return integers as return type. -/// So, every type implementing the `Termination` trait has to be converted -/// to an integer. -/// -/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate -/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. -#[cfg_attr(not(test), lang = "termination")] -#[unstable(feature = "termination_trait_lib", issue = "43301")] -#[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] -pub trait Termination { - /// Is called to get the representation of the value as status code. - /// This status code is returned to the operating system. - fn report(self) -> i32; -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for () { - fn report(self) -> i32 { exit::SUCCESS } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for Result { - fn report(self) -> i32 { - match self { - Ok(val) => val.report(), - Err(err) => { - eprintln!("Error: {:?}", err); - exit::FAILURE - } - } - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for ! { - fn report(self) -> i32 { unreachable!(); } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for bool { - fn report(self) -> i32 { - if self { exit::SUCCESS } else { exit::FAILURE } - } -} - -#[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for i32 { - fn report(self) -> i32 { - self - } -} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 932952d649b..06a23cd8818 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -68,9 +68,9 @@ use std::io::prelude::*; use std::io; use std::iter::repeat; use std::path::PathBuf; +use std::process::Termination; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; -use std::termination::Termination; use std::thread; use std::time::{Instant, Duration}; use std::borrow::Cow; diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index 2da51851952..93e2561adf7 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -10,6 +10,6 @@ #![feature(termination_trait)] fn main() -> char { -//~^ ERROR: the trait bound `char: std::termination::Termination` is not satisfied +//~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied ' ' } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index fac60d6d399..e87e0ceebf1 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -12,6 +12,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::termination::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied ReturnType {} } -- cgit 1.4.1-3-g733a5 From cfad25ee8fb9866d0cbdc43e3a89a00aed13e12c Mon Sep 17 00:00:00 2001 From: jethrogb Date: Fri, 23 Feb 2018 11:57:38 -0800 Subject: Clarify interfaction between File::set_len and file cursor --- src/libstd/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 292a78278ab..db52ed67d3a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -453,6 +453,10 @@ impl File { /// will be extended to `size` and have all of the intermediate data filled /// in with 0s. /// + /// The file's cursor isn't changed. In particular, if the cursor was at the + /// end and the file is shrunk using this operation, the cursor will now be + /// past the end. + /// /// # Errors /// /// This function will return an error if the file is not opened for writing. -- cgit 1.4.1-3-g733a5 From e3e1c8f7d288b130a37b310135b19f314f4601e3 Mon Sep 17 00:00:00 2001 From: Dale Wijnand <344610+dwijnand@users.noreply.github.com> Date: Sat, 24 Feb 2018 12:31:03 +0000 Subject: Fix capitalisation in Path#file_name's docs --- src/libstd/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index e03a182653e..4bbad30a5a3 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1825,7 +1825,7 @@ impl Path { /// If the path is a normal file, this is the file name. If it's the path of a directory, this /// is the directory name. /// - /// Returns [`None`] If the path terminates in `..`. + /// Returns [`None`] if the path terminates in `..`. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// -- cgit 1.4.1-3-g733a5 From 0700bd12d0279db22da40748d86c42b92804888a Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 18 Feb 2018 14:18:56 -0500 Subject: Clarify "It is an error to..." wording for zero-duration behaviors. Documentation fix side of https://github.com/rust-lang/rust/issues/48311. --- src/libstd/net/tcp.rs | 39 ++++++++++++++++++++--- src/libstd/net/udp.rs | 38 +++++++++++++++++++--- src/libstd/sys/unix/ext/net.rs | 71 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 134 insertions(+), 14 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 263a2c13249..53f9eaafb06 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -259,8 +259,8 @@ impl TcpStream { /// Sets the read timeout to the timeout specified. /// /// If the value specified is [`None`], then [`read`] calls will block - /// indefinitely. It is an error to pass the zero `Duration` to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// /// # Platform-specific behavior /// @@ -269,9 +269,11 @@ impl TcpStream { /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock /// [`TimedOut`]: ../../std/io/enum.ErrorKind.html#variant.TimedOut + /// [`Duration`]: ../../std/time/struct.Duration.html /// /// # Examples /// @@ -282,6 +284,20 @@ impl TcpStream { /// .expect("Couldn't connect to the server..."); /// stream.set_read_timeout(None).expect("set_read_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::TcpStream; + /// use std::time::Duration; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); + /// let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_read_timeout(dur) @@ -290,8 +306,8 @@ impl TcpStream { /// Sets the write timeout to the timeout specified. /// /// If the value specified is [`None`], then [`write`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// /// # Platform-specific behavior /// @@ -300,6 +316,7 @@ impl TcpStream { /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock @@ -314,6 +331,20 @@ impl TcpStream { /// .expect("Couldn't connect to the server..."); /// stream.set_write_timeout(None).expect("set_write_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::TcpStream; + /// use std::time::Duration; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); + /// let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_write_timeout(dur) diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 5e19519b88f..0a50cee6756 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -228,8 +228,8 @@ impl UdpSocket { /// Sets the read timeout to the timeout specified. /// /// If the value specified is [`None`], then [`read`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// /// # Platform-specific behavior /// @@ -238,6 +238,7 @@ impl UdpSocket { /// error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`read`]: ../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock @@ -251,6 +252,20 @@ impl UdpSocket { /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// socket.set_read_timeout(None).expect("set_read_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_read_timeout(dur) @@ -259,8 +274,8 @@ impl UdpSocket { /// Sets the write timeout to the timeout specified. /// /// If the value specified is [`None`], then [`write`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// /// # Platform-specific behavior /// @@ -269,6 +284,7 @@ impl UdpSocket { /// an error of the kind [`WouldBlock`], but Windows may return [`TimedOut`]. /// /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`write`]: ../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../std/time/struct.Duration.html /// [`WouldBlock`]: ../../std/io/enum.ErrorKind.html#variant.WouldBlock @@ -282,6 +298,20 @@ impl UdpSocket { /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// socket.set_write_timeout(None).expect("set_write_timeout call failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "socket_timeout", since = "1.4.0")] pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { self.0.set_write_timeout(dur) diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 31bdc5ea1f5..3430512ebe8 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -387,10 +387,11 @@ impl UnixStream { /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../../../std/time/struct.Duration.html /// @@ -403,6 +404,20 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) @@ -411,10 +426,11 @@ impl UnixStream { /// Sets the write timeout for the socket. /// /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../../../std/time/struct.Duration.html /// @@ -427,6 +443,20 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) @@ -1250,10 +1280,11 @@ impl UnixDatagram { /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will - /// block indefinitely. It is an error to pass the zero [`Duration`] to this - /// method. + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] + /// is passed to this method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err /// [`recv`]: #method.recv /// [`recv_from`]: #method.recv_from /// [`Duration`]: ../../../../std/time/struct.Duration.html @@ -1267,6 +1298,20 @@ impl UnixDatagram { /// let sock = UnixDatagram::unbound().unwrap(); /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_RCVTIMEO) @@ -1275,7 +1320,7 @@ impl UnixDatagram { /// Sets the write timeout for the socket. /// /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. It is an error to pass the zero [`Duration`] to this + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None @@ -1293,6 +1338,20 @@ impl UnixDatagram { /// sock.set_write_timeout(Some(Duration::new(1, 0))) /// .expect("set_write_timeout function failed"); /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { self.0.set_timeout(timeout, libc::SO_SNDTIMEO) -- cgit 1.4.1-3-g733a5 From 5344b07addf342334470778964d863d99eec7430 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 24 Feb 2018 16:50:44 +0100 Subject: Add new warning for CStr::from_ptr --- src/libstd/ffi/c_str.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 2519d830435..c88c2bc9137 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -875,6 +875,8 @@ impl CStr { /// `ptr`. /// * There is no guarantee that the memory pointed to by `ptr` contains a /// valid nul terminator byte at the end of the string. + /// * It is not guaranteed that the memory pointed by `ptr` won't change + /// before the `CStr` has been destroyed. /// /// > **Note**: This operation is intended to be a 0-cost cast but it is /// > currently implemented with an up-front calculation of the length of -- cgit 1.4.1-3-g733a5 From 64236092e5aa8fca2b9175df5a1192fd3d46e29b Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Sat, 24 Feb 2018 23:48:51 -0600 Subject: Fixes docs for ASCII functions to no longer claim U+0021 is '@'. --- src/libcore/num/mod.rs | 2 +- src/libstd/ascii.rs | 2 +- src/libstd_unicode/char.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 43330b63f9b..7d5aa25016b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2892,7 +2892,7 @@ impl u8 { } /// Checks if the value is an ASCII graphic character: - /// U+0021 '@' ... U+007E '~'. + /// U+0021 '!' ... U+007E '~'. /// /// # Examples /// diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 82e1a3447dc..430c9df396a 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -245,7 +245,7 @@ pub trait AsciiExt { fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII graphic character: - /// U+0021 '@' ... U+007E '~'. + /// U+0021 '!' ... U+007E '~'. /// For strings, true if all characters in the string are /// ASCII graphic characters. /// diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index b4be4a96911..844ff7a3c12 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -1332,7 +1332,7 @@ impl char { } /// Checks if the value is an ASCII graphic character: - /// U+0021 '@' ... U+007E '~'. + /// U+0021 '!' ... U+007E '~'. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 0aa753ba30254631ce05f37cd2ff0dd428d931c5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 24 Feb 2018 21:06:29 -0800 Subject: 1.25.0 -> 1.26.- --- src/liballoc/btree/map.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index b98489c516a..618ef81fdd9 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -2128,7 +2128,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// .or_insert(42); /// assert_eq!(map["poneyland"], 43); /// ``` - #[stable(feature = "entry_and_modify", since = "1.25.0")] + #[stable(feature = "entry_and_modify", since = "1.26.0")] pub fn and_modify(self, mut f: F) -> Self where F: FnMut(&mut V) { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 80e52123a01..b63a45ecade 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2080,7 +2080,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// .or_insert(42); /// assert_eq!(map["poneyland"], 43); /// ``` - #[stable(feature = "entry_and_modify", since = "1.25.0")] + #[stable(feature = "entry_and_modify", since = "1.26.0")] pub fn and_modify(self, mut f: F) -> Self where F: FnMut(&mut V) { -- cgit 1.4.1-3-g733a5 From e20f7b2ea73fbe0077a565c692a3a6f2e20ff4e3 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 24 Feb 2018 00:31:33 -0800 Subject: Restrict the Termination impls to simplify stabilization Make a minimal commitment for stabilization. More impls are likely in future, but are not necessary at this time. --- src/libstd/process.rs | 24 ++++++++++++++++------ .../termination-trait-for-exitcode.rs | 18 ++++++++++++++++ .../termination-trait-for-i32.rs | 15 -------------- 3 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs delete mode 100644 src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index e25599b8bd8..e5fc33e241c 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1080,6 +1080,15 @@ impl fmt::Display for ExitStatus { } } +/// This is ridiculously unstable, as it's a completely-punted-upon part +/// of the `?`-in-`main` RFC. It's here only to allow experimenting with +/// returning a code directly from main. It will definitely change +/// drastically before being stabilized, if it doesn't just get deleted. +#[doc(hidden)] +#[derive(Clone, Copy, Debug)] +#[unstable(feature = "process_exitcode_placeholder", issue = "43301")] +pub struct ExitCode(pub i32); + impl Child { /// Forces the child to exit. This is equivalent to sending a /// SIGKILL on unix platforms. @@ -1428,7 +1437,7 @@ impl Termination for () { } #[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for Result { +impl Termination for Result<(), E> { fn report(self) -> i32 { match self { Ok(val) => val.report(), @@ -1442,20 +1451,23 @@ impl Termination for Result { #[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for ! { - fn report(self) -> i32 { unreachable!(); } + fn report(self) -> i32 { self } } #[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for bool { +impl Termination for Result { fn report(self) -> i32 { - if self { exit::SUCCESS } else { exit::FAILURE } + let Err(err) = self; + eprintln!("Error: {:?}", err); + exit::FAILURE } } #[unstable(feature = "termination_trait_lib", issue = "43301")] -impl Termination for i32 { +impl Termination for ExitCode { fn report(self) -> i32 { - self + let ExitCode(code) = self; + code } } diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs new file mode 100644 index 00000000000..30ecc4e8937 --- /dev/null +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs @@ -0,0 +1,18 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(termination_trait)] +#![feature(process_exitcode_placeholder)] + +use std::process::ExitCode; + +fn main() -> ExitCode { + ExitCode(0) +} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs deleted file mode 100644 index fa7cb023b44..00000000000 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-i32.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(termination_trait)] - -fn main() -> i32 { - 0 -} -- cgit 1.4.1-3-g733a5 From a554a2f5645f12cf42d311ac11bcaad594c91347 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 19 Feb 2018 08:45:45 -0500 Subject: Return error if timeout is zero-Duration on Redox. --- src/libstd/sys/redox/net/tcp.rs | 10 +++++++++- src/libstd/sys/redox/net/udp.rs | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index 319965ab396..b5664908479 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -9,7 +9,7 @@ // except according to those terms. use cmp; -use io::{Error, ErrorKind, Result}; +use io::{self, Error, ErrorKind, Result}; use mem; use net::{SocketAddr, Shutdown}; use path::Path; @@ -130,6 +130,10 @@ impl TcpStream { pub fn set_read_timeout(&self, duration_option: Option) -> Result<()> { let file = self.0.dup(b"read_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 @@ -143,6 +147,10 @@ impl TcpStream { pub fn set_write_timeout(&self, duration_option: Option) -> Result<()> { let file = self.0.dup(b"write_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs index 7e7666e7ef3..2ed67bd2836 100644 --- a/src/libstd/sys/redox/net/udp.rs +++ b/src/libstd/sys/redox/net/udp.rs @@ -10,7 +10,7 @@ use cell::UnsafeCell; use cmp; -use io::{Error, ErrorKind, Result}; +use io::{self, Error, ErrorKind, Result}; use mem; use net::{SocketAddr, Ipv4Addr, Ipv6Addr}; use path::Path; @@ -179,6 +179,10 @@ impl UdpSocket { pub fn set_read_timeout(&self, duration_option: Option) -> Result<()> { let file = self.0.dup(b"read_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 @@ -192,6 +196,10 @@ impl UdpSocket { pub fn set_write_timeout(&self, duration_option: Option) -> Result<()> { let file = self.0.dup(b"write_timeout")?; if let Some(duration) = duration_option { + if duration.as_secs() == 0 && duration.subsec_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } file.write(&TimeSpec { tv_sec: duration.as_secs() as i64, tv_nsec: duration.subsec_nanos() as i32 -- cgit 1.4.1-3-g733a5 From fc2e4e7833d3af20ec9cb646fff4f7f5426f10fa Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 27 Feb 2018 10:31:17 -0800 Subject: Put some thought and documentation effort into process::ExitCode --- src/libstd/process.rs | 76 +++++++++++++++------- .../termination-trait-for-exitcode.rs | 2 +- 2 files changed, 53 insertions(+), 25 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index e5fc33e241c..483e58eb0f4 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1080,15 +1080,58 @@ impl fmt::Display for ExitStatus { } } -/// This is ridiculously unstable, as it's a completely-punted-upon part -/// of the `?`-in-`main` RFC. It's here only to allow experimenting with -/// returning a code directly from main. It will definitely change -/// drastically before being stabilized, if it doesn't just get deleted. -#[doc(hidden)] +/// This type represents the status code a process can return to its +/// parent under normal termination. +/// +/// Numeric values used in this type don't have portable meanings, and +/// different platforms may mask different amounts of them. +/// +/// For the platform's canonical successful and unsuccessful codes, see +/// the [`SUCCESS`] and [`FAILURE`] associated items. +/// +/// [`SUCCESS`]: #constant.SUCCESS +/// [`FAILURE`]: #constant.FAILURE +/// +/// **Warning**: While various forms of this were discussed in [RFC #1937], +/// it was ultimately cut from that RFC, and thus this type is more subject +/// to change even than the usual unstable item churn. +/// +/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 #[derive(Clone, Copy, Debug)] #[unstable(feature = "process_exitcode_placeholder", issue = "43301")] pub struct ExitCode(pub i32); +#[cfg(target_arch = "wasm32")] +mod rawexit { + pub const SUCCESS: i32 = 0; + pub const FAILURE: i32 = 1; +} +#[cfg(not(target_arch = "wasm32"))] +mod rawexit { + use libc; + pub const SUCCESS: i32 = libc::EXIT_SUCCESS; + pub const FAILURE: i32 = libc::EXIT_FAILURE; +} + +#[unstable(feature = "process_exitcode_placeholder", issue = "43301")] +impl ExitCode { + /// The canonical ExitCode for successful termination on this platform. + /// + /// Note that a `()`-returning `main` implicitly results in a successful + /// termination, so there's no need to return this from `main` unless + /// you're also returning other possible codes. + #[unstable(feature = "process_exitcode_placeholder", issue = "43301")] + pub const SUCCESS: ExitCode = ExitCode(rawexit::SUCCESS); + + /// The canonical ExitCode for unsuccessful termination on this platform. + /// + /// If you're only returning this and `SUCCESS` from `main`, consider + /// instead returning `Err(_)` and `Ok(())` respectively, which will + /// return the same codes (but will also `eprintln!` the error). + #[unstable(feature = "process_exitcode_placeholder", issue = "43301")] + pub const FAILURE: ExitCode = ExitCode(rawexit::FAILURE); +} + impl Child { /// Forces the child to exit. This is equivalent to sending a /// SIGKILL on unix platforms. @@ -1401,18 +1444,6 @@ pub fn id() -> u32 { ::sys::os::getpid() } -#[cfg(target_arch = "wasm32")] -mod exit { - pub const SUCCESS: i32 = 0; - pub const FAILURE: i32 = 1; -} -#[cfg(not(target_arch = "wasm32"))] -mod exit { - use libc; - pub const SUCCESS: i32 = libc::EXIT_SUCCESS; - pub const FAILURE: i32 = libc::EXIT_FAILURE; -} - /// A trait for implementing arbitrary return types in the `main` function. /// /// The c-main function only supports to return integers as return type. @@ -1433,18 +1464,15 @@ pub trait Termination { #[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for () { - fn report(self) -> i32 { exit::SUCCESS } + fn report(self) -> i32 { ExitCode::SUCCESS.report() } } #[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for Result<(), E> { fn report(self) -> i32 { match self { - Ok(val) => val.report(), - Err(err) => { - eprintln!("Error: {:?}", err); - exit::FAILURE - } + Ok(()) => ().report(), + Err(err) => Err::(err).report(), } } } @@ -1459,7 +1487,7 @@ impl Termination for Result { fn report(self) -> i32 { let Err(err) = self; eprintln!("Error: {:?}", err); - exit::FAILURE + ExitCode::FAILURE.report() } } diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs index 30ecc4e8937..80fa4d17b61 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs @@ -14,5 +14,5 @@ use std::process::ExitCode; fn main() -> ExitCode { - ExitCode(0) + ExitCode::SUCCESS } -- cgit 1.4.1-3-g733a5 From c99f4c4c5b9f968b82037cf643b6662b140d9b1f Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Tue, 27 Feb 2018 17:00:01 +0100 Subject: Stabilize LocalKey::try_with --- src/libstd/io/stdio.rs | 5 ++++- src/libstd/thread/local.rs | 28 +++++++++++++++------------- src/libstd/thread/mod.rs | 5 ++++- src/test/run-pass/tls-init-on-init.rs | 1 + 4 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 831688bb73d..f01ca18851d 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -17,7 +17,9 @@ use io::{self, Initializer, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; -use thread::{LocalKey, LocalKeyState}; +use thread::LocalKey; +#[allow(deprecated)] +use thread::LocalKeyState; /// Stdout used by print! and println! macros thread_local! { @@ -668,6 +670,7 @@ pub fn set_print(sink: Option>) -> Option> { /// thread, it will just fall back to the global stream. /// /// However, if the actual I/O causes an error, this function does panic. +#[allow(deprecated)] fn print_to(args: fmt::Arguments, local_s: &'static LocalKey>>>, global_s: fn() -> T, diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index fcbca38a98f..b6dbcf8914c 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -199,6 +199,7 @@ macro_rules! __thread_local_inner { #[unstable(feature = "thread_local_state", reason = "state querying was recently added", issue = "27716")] +#[rustc_deprecated(since = "1.26.0", reason = "use `LocalKey::try_with` instead")] #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum LocalKeyState { /// All keys are in this state whenever a thread starts. Keys will @@ -234,25 +235,19 @@ pub enum LocalKeyState { } /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] +#[stable(feature = "thread_local_try_with", since = "1.26.0")] pub struct AccessError { _private: (), } -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] +#[stable(feature = "thread_local_try_with", since = "1.26.0")] impl fmt::Debug for AccessError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("AccessError").finish() } } -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] +#[stable(feature = "thread_local_try_with", since = "1.26.0")] impl fmt::Display for AccessError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt("already destroyed", f) @@ -341,6 +336,8 @@ impl LocalKey { #[unstable(feature = "thread_local_state", reason = "state querying was recently added", issue = "27716")] + #[rustc_deprecated(since = "1.26.0", reason = "use `LocalKey::try_with` instead")] + #[allow(deprecated)] pub fn state(&'static self) -> LocalKeyState { unsafe { match (self.inner)() { @@ -365,11 +362,11 @@ impl LocalKey { /// /// This function will still `panic!()` if the key is uninitialized and the /// key's initializer panics. - #[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] + #[stable(feature = "thread_local_try_with", since = "1.26.0")] pub fn try_with(&'static self, f: F) -> Result - where F: FnOnce(&T) -> R { + where + F: FnOnce(&T) -> R, + { unsafe { let slot = (self.inner)().ok_or(AccessError { _private: (), @@ -530,6 +527,7 @@ pub mod os { mod tests { use sync::mpsc::{channel, Sender}; use cell::{Cell, UnsafeCell}; + #[allow(deprecated)] use super::LocalKeyState; use thread; @@ -565,6 +563,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn states() { struct Foo; impl Drop for Foo { @@ -602,6 +601,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn circular() { struct S1; struct S2; @@ -642,6 +642,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn self_referential() { struct S1; thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); @@ -663,6 +664,7 @@ mod tests { // test on macOS. #[test] #[cfg_attr(target_os = "macos", ignore)] + #[allow(deprecated)] fn dtors_in_dtors_in_dtors() { struct S1(Sender<()>); thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index ff121e2d7ee..01898679bdc 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -191,7 +191,10 @@ use time::Duration; #[macro_use] mod local; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::local::{LocalKey, LocalKeyState, AccessError}; +pub use self::local::{LocalKey, AccessError}; +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +pub use self::local::LocalKeyState; // The types used by the thread_local! macro to access TLS keys. Note that there // are two types, the "OS" type and the "fast" type. The OS thread local key diff --git a/src/test/run-pass/tls-init-on-init.rs b/src/test/run-pass/tls-init-on-init.rs index b44c535d3a4..b5b9fb561ae 100644 --- a/src/test/run-pass/tls-init-on-init.rs +++ b/src/test/run-pass/tls-init-on-init.rs @@ -11,6 +11,7 @@ // ignore-emscripten no threads support #![feature(thread_local_state)] +#![allow(deprecated)] use std::thread::{self, LocalKeyState}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; -- cgit 1.4.1-3-g733a5 From b9e9b4a1461e3a49b68db56413324dc1b6a2ed60 Mon Sep 17 00:00:00 2001 From: Tobias Stolzmann Date: Wed, 28 Feb 2018 15:29:16 +0100 Subject: Add std::path::Path::ancestors Squashed commit of the following: commit 1b5d55e26f667b1a25c83c5db0cbb072013a5122 Author: Tobias Stolzmann Date: Wed Feb 28 00:06:15 2018 +0100 Bugfix commit 4265c2db0b0aaa66fdeace5d329665fd2d13903a Author: Tobias Stolzmann Date: Tue Feb 27 22:59:12 2018 +0100 Rename std::path::Path::parents into std::path::Path::ancestors commit 2548e4b14d377d20adad0f08304a0dd6f8e48e23 Author: Tobias Stolzmann Date: Tue Feb 27 12:50:37 2018 +0100 Add tracking issue commit 3e2ce51a6eea0e39af05849f76dd2cefd5035e86 Author: Tobias Stolzmann Date: Mon Feb 26 15:05:15 2018 +0100 impl FusedIterator for Parents commit a7e096420809740311e19d963d4aba6df77be2f9 Author: Tobias Stolzmann Date: Mon Feb 26 14:38:41 2018 +0100 Clarify that the iterator returned will yield at least one value commit 796a36ea203cd197cc4c810eebd21c7e3433e6f1 Author: Tobias Stolzmann Date: Thu Feb 22 14:01:21 2018 +0100 Fix examples commit e279383b21f11c97269cb355a5b2a0ecdb65bb0c Author: Tobias Stolzmann Date: Thu Feb 22 04:47:24 2018 +0100 Add std::path::Path::parents --- src/libstd/path.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 4bbad30a5a3..1608a752a46 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1035,6 +1035,50 @@ impl<'a> cmp::Ord for Components<'a> { } } +/// An iterator over [`Path`] and its ancestors. +/// +/// This `struct` is created by the [`ancestors`] method on [`Path`]. +/// See its documentation for more. +/// +/// # Examples +/// +/// ``` +/// #![feature(path_ancestors)] +/// +/// use std::path::Path; +/// +/// let path = Path::new("/foo/bar"); +/// +/// for ancestor in path.ancestors() { +/// println!("{}", ancestor.display()); +/// } +/// ``` +/// +/// [`ancestors`]: struct.Path.html#method.ancestors +/// [`Path`]: struct.Path.html +#[derive(Copy, Clone, Debug)] +#[unstable(feature = "path_ancestors", issue = "48581")] +pub struct Ancestors<'a> { + next: Option<&'a Path>, +} + +#[unstable(feature = "path_ancestors", issue = "48581")] +impl<'a> Iterator for Ancestors<'a> { + type Item = &'a Path; + + fn next(&mut self) -> Option { + let next = self.next; + self.next = match next { + Some(path) => path.parent(), + None => None, + }; + next + } +} + +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for Ancestors<'a> {} + //////////////////////////////////////////////////////////////////////////////// // Basic types and traits //////////////////////////////////////////////////////////////////////////////// @@ -1820,6 +1864,37 @@ impl Path { }) } + /// Produces an iterator over `Path` and its ancestors. + /// + /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero + /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`, + /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns + /// [`None`], the iterator will do likewise. The iterator will always yield at least one value, + /// namely `&self`. + /// + /// # Examples + /// + /// ``` + /// #![feature(path_ancestors)] + /// + /// use std::path::Path; + /// + /// let mut ancestors = Path::new("/foo/bar").ancestors(); + /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar"))); + /// assert_eq!(ancestors.next(), Some(Path::new("/foo"))); + /// assert_eq!(ancestors.next(), Some(Path::new("/"))); + /// assert_eq!(ancestors.next(), None); + /// ``` + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`parent`]: struct.Path.html#method.parent + #[unstable(feature = "path_ancestors", issue = "48581")] + pub fn ancestors(&self) -> Ancestors { + Ancestors { + next: Some(&self), + } + } + /// Returns the final component of the `Path`, if there is one. /// /// If the path is a normal file, this is the file name. If it's the path of a directory, this -- cgit 1.4.1-3-g733a5 From 27fae2b24af48041ceea6e04c7f217d3db372164 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Wed, 28 Feb 2018 18:59:12 +0100 Subject: Remove thread_local_state --- src/libstd/io/stdio.rs | 39 ++++++++-------- src/libstd/thread/local.rs | 111 +++------------------------------------------ src/libstd/thread/mod.rs | 3 -- 3 files changed, 26 insertions(+), 127 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index f01ca18851d..b8fb83ad465 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,8 +18,6 @@ use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use thread::LocalKey; -#[allow(deprecated)] -use thread::LocalKeyState; /// Stdout used by print! and println! macros thread_local! { @@ -670,25 +668,26 @@ pub fn set_print(sink: Option>) -> Option> { /// thread, it will just fall back to the global stream. /// /// However, if the actual I/O causes an error, this function does panic. -#[allow(deprecated)] -fn print_to(args: fmt::Arguments, - local_s: &'static LocalKey>>>, - global_s: fn() -> T, - label: &str) where T: Write { - let result = match local_s.state() { - LocalKeyState::Uninitialized | - LocalKeyState::Destroyed => global_s().write_fmt(args), - LocalKeyState::Valid => { - local_s.with(|s| { - if let Ok(mut borrowed) = s.try_borrow_mut() { - if let Some(w) = borrowed.as_mut() { - return w.write_fmt(args); - } - } - global_s().write_fmt(args) - }) +fn print_to( + args: fmt::Arguments, + local_s: &'static LocalKey>>>, + global_s: fn() -> T, + label: &str, +) +where + T: Write, +{ + let result = local_s.try_with(|s| { + if let Ok(mut borrowed) = s.try_borrow_mut() { + if let Some(w) = borrowed.as_mut() { + return w.write_fmt(args); + } } - }; + global_s().write_fmt(args) + }).unwrap_or_else(|_| { + global_s().write_fmt(args) + }); + if let Err(e) = result { panic!("failed printing to {}: {}", label, e); } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index b6dbcf8914c..25fedcb2772 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -195,45 +195,6 @@ macro_rules! __thread_local_inner { } } -/// Indicator of the state of a thread local storage key. -#[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] -#[rustc_deprecated(since = "1.26.0", reason = "use `LocalKey::try_with` instead")] -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -pub enum LocalKeyState { - /// All keys are in this state whenever a thread starts. Keys will - /// transition to the `Valid` state once the first call to [`with`] happens - /// and the initialization expression succeeds. - /// - /// Keys in the `Uninitialized` state will yield a reference to the closure - /// passed to [`with`] so long as the initialization routine does not panic. - /// - /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with - Uninitialized, - - /// Once a key has been accessed successfully, it will enter the `Valid` - /// state. Keys in the `Valid` state will remain so until the thread exits, - /// at which point the destructor will be run and the key will enter the - /// `Destroyed` state. - /// - /// Keys in the `Valid` state will be guaranteed to yield a reference to the - /// closure passed to [`with`]. - /// - /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with - Valid, - - /// When a thread exits, the destructors for keys will be run (if - /// necessary). While a destructor is running, and possibly after a - /// destructor has run, a key is in the `Destroyed` state. - /// - /// Keys in the `Destroyed` states will trigger a panic when accessed via - /// [`with`]. - /// - /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with - Destroyed, -} - /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). #[stable(feature = "thread_local_try_with", since = "1.26.0")] pub struct AccessError { @@ -307,51 +268,6 @@ impl LocalKey { (*ptr).as_ref().unwrap() } - /// Query the current state of this key. - /// - /// A key is initially in the `Uninitialized` state whenever a thread - /// starts. It will remain in this state up until the first call to [`with`] - /// within a thread has run the initialization expression successfully. - /// - /// Once the initialization expression succeeds, the key transitions to the - /// `Valid` state which will guarantee that future calls to [`with`] will - /// succeed within the thread. Some keys might skip the `Uninitialized` - /// state altogether and start in the `Valid` state as an optimization - /// (e.g. keys initialized with a constant expression), but no guarantees - /// are made. - /// - /// When a thread exits, each key will be destroyed in turn, and as keys are - /// destroyed they will enter the `Destroyed` state just before the - /// destructor starts to run. Keys may remain in the `Destroyed` state after - /// destruction has completed. Keys without destructors (e.g. with types - /// that are [`Copy`]), may never enter the `Destroyed` state. - /// - /// Keys in the `Uninitialized` state can be accessed so long as the - /// initialization does not panic. Keys in the `Valid` state are guaranteed - /// to be able to be accessed. Keys in the `Destroyed` state will panic on - /// any call to [`with`]. - /// - /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with - /// [`Copy`]: ../../std/marker/trait.Copy.html - #[unstable(feature = "thread_local_state", - reason = "state querying was recently added", - issue = "27716")] - #[rustc_deprecated(since = "1.26.0", reason = "use `LocalKey::try_with` instead")] - #[allow(deprecated)] - pub fn state(&'static self) -> LocalKeyState { - unsafe { - match (self.inner)() { - Some(cell) => { - match *cell.get() { - Some(..) => LocalKeyState::Valid, - None => LocalKeyState::Uninitialized, - } - } - None => LocalKeyState::Destroyed, - } - } - } - /// Acquires a reference to the value in this TLS key. /// /// This will lazily initialize the value if this thread has not referenced @@ -527,8 +443,6 @@ pub mod os { mod tests { use sync::mpsc::{channel, Sender}; use cell::{Cell, UnsafeCell}; - #[allow(deprecated)] - use super::LocalKeyState; use thread; struct Foo(Sender<()>); @@ -563,26 +477,21 @@ mod tests { } #[test] - #[allow(deprecated)] fn states() { struct Foo; impl Drop for Foo { fn drop(&mut self) { - assert!(FOO.state() == LocalKeyState::Destroyed); + assert!(FOO.try_with(|_| ()).is_err()); } } fn foo() -> Foo { - assert!(FOO.state() == LocalKeyState::Uninitialized); + assert!(FOO.try_with(|_| ()).is_err()); Foo } thread_local!(static FOO: Foo = foo()); thread::spawn(|| { - assert!(FOO.state() == LocalKeyState::Uninitialized); - FOO.with(|_| { - assert!(FOO.state() == LocalKeyState::Valid); - }); - assert!(FOO.state() == LocalKeyState::Valid); + assert!(FOO.try_with(|_| ()).is_ok()); }).join().ok().unwrap(); } @@ -601,7 +510,6 @@ mod tests { } #[test] - #[allow(deprecated)] fn circular() { struct S1; struct S2; @@ -612,8 +520,7 @@ mod tests { impl Drop for S1 { fn drop(&mut self) { unsafe { - HITS += 1; - if K2.state() == LocalKeyState::Destroyed { + if K2.try_with(|_| ()).is_err() { assert_eq!(HITS, 3); } else { if HITS == 1 { @@ -629,7 +536,7 @@ mod tests { fn drop(&mut self) { unsafe { HITS += 1; - assert!(K1.state() != LocalKeyState::Destroyed); + assert!(K1.try_with(|_| ()).is_ok()); assert_eq!(HITS, 2); K1.with(|s| *s.get() = Some(S1)); } @@ -642,14 +549,13 @@ mod tests { } #[test] - #[allow(deprecated)] fn self_referential() { struct S1; thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); impl Drop for S1 { fn drop(&mut self) { - assert!(K1.state() == LocalKeyState::Destroyed); + assert!(K1.try_with(|_| ()).is_err()); } } @@ -664,7 +570,6 @@ mod tests { // test on macOS. #[test] #[cfg_attr(target_os = "macos", ignore)] - #[allow(deprecated)] fn dtors_in_dtors_in_dtors() { struct S1(Sender<()>); thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); @@ -674,9 +579,7 @@ mod tests { fn drop(&mut self) { let S1(ref tx) = *self; unsafe { - if K2.state() != LocalKeyState::Destroyed { - K2.with(|s| *s.get() = Some(Foo(tx.clone()))); - } + let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone()))); } } } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 01898679bdc..71aee673cfe 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -192,9 +192,6 @@ use time::Duration; #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{LocalKey, AccessError}; -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use self::local::LocalKeyState; // The types used by the thread_local! macro to access TLS keys. Note that there // are two types, the "OS" type and the "fast" type. The OS thread local key -- cgit 1.4.1-3-g733a5 From cb56b2d1522e83c5bb0613abcf78b686e994df9e Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 1 Mar 2018 00:07:27 +0100 Subject: Fix a bug introduced in previous commit --- src/libstd/io/stdio.rs | 4 ++-- src/libstd/thread/local.rs | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index b8fb83ad465..1f73054e3be 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -663,8 +663,8 @@ pub fn set_print(sink: Option>) -> Option> { /// /// This function is used to print error messages, so it takes extra /// care to avoid causing a panic when `local_stream` is unusable. -/// For instance, if the TLS key for the local stream is uninitialized -/// or already destroyed, or if the local stream is locked by another +/// For instance, if the TLS key for the local stream is +/// already destroyed, or if the local stream is locked by another /// thread, it will just fall back to the global stream. /// /// However, if the actual I/O causes an error, this function does panic. diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 25fedcb2772..99479bc56ef 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -272,7 +272,7 @@ impl LocalKey { /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. If the key has been destroyed (which may happen if this is called - /// in a destructor), this function will return a ThreadLocalError. + /// in a destructor), this function will return a `ThreadLocalError`. /// /// # Panics /// @@ -484,11 +484,7 @@ mod tests { assert!(FOO.try_with(|_| ()).is_err()); } } - fn foo() -> Foo { - assert!(FOO.try_with(|_| ()).is_err()); - Foo - } - thread_local!(static FOO: Foo = foo()); + thread_local!(static FOO: Foo = Foo); thread::spawn(|| { assert!(FOO.try_with(|_| ()).is_ok()); @@ -520,6 +516,7 @@ mod tests { impl Drop for S1 { fn drop(&mut self) { unsafe { + HITS += 1; if K2.try_with(|_| ()).is_err() { assert_eq!(HITS, 3); } else { -- cgit 1.4.1-3-g733a5 From 11696acd6d070a90e8dd386a3c9ae877740fb0e2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 18:13:45 -0800 Subject: Support posix_spawn() when possible. --- src/libstd/sys/unix/process/process_unix.rs | 102 ++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 189280a4ba9..d66c2375140 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -24,6 +24,7 @@ impl Command { -> io::Result<(Process, StdioPipes)> { use sys; + const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; let envp = self.capture_env(); @@ -34,6 +35,11 @@ impl Command { } let (ours, theirs) = self.setup_io(default, needs_stdin)?; + + if let Some(ret) = self.posix_spawn(&theirs, envp.as_ref())? { + return Ok((ret, ours)) + } + let (input, output) = sys::pipe::anon_pipe()?; let pid = unsafe { @@ -229,6 +235,102 @@ impl Command { libc::execvp(self.get_argv()[0], self.get_argv().as_ptr()); io::Error::last_os_error() } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] + fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) + -> io::Result> + { + Ok(None) + } + + #[cfg(any(target_os = "linux", target_os = "macos"))] + fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) + -> io::Result> + { + use mem; + use sys; + + if self.get_cwd().is_some() || + self.get_gid().is_some() || + self.get_uid().is_some() || + self.get_closures().len() != 0 { + return Ok(None) + } + + let mut p = Process { pid: 0, status: None }; + + struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t); + + impl Drop for PosixSpawnFileActions { + fn drop(&mut self) { + unsafe { + libc::posix_spawn_file_actions_destroy(&mut self.0); + } + } + } + + struct PosixSpawnattr(libc::posix_spawnattr_t); + + impl Drop for PosixSpawnattr { + fn drop(&mut self) { + unsafe { + libc::posix_spawnattr_destroy(&mut self.0); + } + } + } + + unsafe { + let mut file_actions = PosixSpawnFileActions(mem::zeroed()); + let mut attrs = PosixSpawnattr(mem::zeroed()); + + libc::posix_spawnattr_init(&mut attrs.0); + libc::posix_spawn_file_actions_init(&mut file_actions.0); + + if let Some(fd) = stdio.stdin.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDIN_FILENO))?; + } + if let Some(fd) = stdio.stdout.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDOUT_FILENO))?; + } + if let Some(fd) = stdio.stderr.fd() { + cvt(libc::posix_spawn_file_actions_adddup2(&mut file_actions.0, + fd, + libc::STDERR_FILENO))?; + } + + let mut set: libc::sigset_t = mem::zeroed(); + cvt(libc::sigemptyset(&mut set))?; + cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0, + &set))?; + cvt(libc::sigaddset(&mut set, libc::SIGPIPE))?; + cvt(libc::posix_spawnattr_setsigdefault(&mut attrs.0, + &set))?; + + let flags = libc::POSIX_SPAWN_SETSIGDEF | + libc::POSIX_SPAWN_SETSIGMASK; + cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?; + + let envp = envp.map(|c| c.as_ptr()) + .unwrap_or(sys::os::environ() as *const _); + let ret = libc::posix_spawnp( + &mut p.pid, + self.get_argv()[0], + &file_actions.0, + &attrs.0, + self.get_argv().as_ptr() as *const _, + envp as *const _, + ); + if ret == 0 { + Ok(Some(p)) + } else { + Err(io::Error::last_os_error()) + } + } + } } //////////////////////////////////////////////////////////////////////////////// -- cgit 1.4.1-3-g733a5 From f4633865d37dea15a88220e886e77839aa1fd1ba Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 17:33:44 -0800 Subject: Avoid error for unused variables --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index d66c2375140..05b4b9b085b 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -237,7 +237,7 @@ impl Command { } #[cfg(not(any(target_os = "linux", target_os = "macos")))] - fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) + fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) -> io::Result> { Ok(None) -- cgit 1.4.1-3-g733a5 From 94630e4ca509f9b37e4c066eee94f40da12cba51 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 20:23:46 -0800 Subject: No need to zero when an initializer for the object is already used. --- src/libstd/sys/unix/process/process_unix.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 05b4b9b085b..b394d5ff41a 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -280,8 +280,8 @@ impl Command { } unsafe { - let mut file_actions = PosixSpawnFileActions(mem::zeroed()); - let mut attrs = PosixSpawnattr(mem::zeroed()); + let mut file_actions = PosixSpawnFileActions(mem::uninitialized()); + let mut attrs = PosixSpawnattr(mem::uninitialized()); libc::posix_spawnattr_init(&mut attrs.0); libc::posix_spawn_file_actions_init(&mut file_actions.0); @@ -302,7 +302,7 @@ impl Command { libc::STDERR_FILENO))?; } - let mut set: libc::sigset_t = mem::zeroed(); + let mut set: libc::sigset_t = mem::uninitialized(); cvt(libc::sigemptyset(&mut set))?; cvt(libc::posix_spawnattr_setsigmask(&mut attrs.0, &set))?; -- cgit 1.4.1-3-g733a5 From 8e3fa0d3c450051d6445aa82682416eb307b2d5b Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 23:51:19 -0800 Subject: Pass proper pointer for envp. --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index b394d5ff41a..9765ff37e9b 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -315,7 +315,7 @@ impl Command { cvt(libc::posix_spawnattr_setflags(&mut attrs.0, flags as _))?; let envp = envp.map(|c| c.as_ptr()) - .unwrap_or(sys::os::environ() as *const _); + .unwrap_or(*sys::os::environ() as *const _); let ret = libc::posix_spawnp( &mut p.pid, self.get_argv()[0], -- cgit 1.4.1-3-g733a5 From b3ecf5f57ca9d34d10ffd9d064a027ce3f4888ac Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 26 Feb 2018 23:51:39 -0800 Subject: Remove excess newline --- src/libstd/sys/unix/process/process_unix.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 9765ff37e9b..fa66245abb6 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -24,7 +24,6 @@ impl Command { -> io::Result<(Process, StdioPipes)> { use sys; - const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; let envp = self.capture_env(); -- cgit 1.4.1-3-g733a5 From 85b82f254e28f5e50b25d8e096af0f01e4441ef7 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Tue, 27 Feb 2018 14:12:52 -0800 Subject: Support posix_spawn() for FreeBSD. spawn() is expected to return an error if the specified file could not be executed. FreeBSD's posix_spawn() supports returning ENOENT/ENOEXEC if the exec() fails, which not all platforms support. This brings a very significant performance improvement for FreeBSD, involving heavy use of Command in threads, due to fork() invoking jemalloc fork handlers and causing lock contention. FreeBSD's posix_spawn() avoids this problem due to using vfork() internally. --- src/libstd/sys/unix/process/process_unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index fa66245abb6..c7841a861ce 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -235,14 +235,14 @@ impl Command { io::Error::last_os_error() } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(not(any(target_os = "freebsd")))] fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) -> io::Result> { Ok(None) } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "freebsd"))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> { -- cgit 1.4.1-3-g733a5 From a9ea876960a06f3ae00049515bf9ef706cca806b Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Wed, 28 Feb 2018 22:16:35 -0800 Subject: posix_spawn() always returns its error rather than setting errno. --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index c7841a861ce..c5dda6273ef 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -326,7 +326,7 @@ impl Command { if ret == 0 { Ok(Some(p)) } else { - Err(io::Error::last_os_error()) + Err(io::Error::from_raw_os_error(ret)) } } } -- cgit 1.4.1-3-g733a5 From 2ce2b40ee5f847f02d6da1b81f3303b8e8b23531 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Wed, 28 Feb 2018 23:34:20 -0800 Subject: Fix linkchecker --- src/libstd/process.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 483e58eb0f4..5a06bf45aaa 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1089,8 +1089,8 @@ impl fmt::Display for ExitStatus { /// For the platform's canonical successful and unsuccessful codes, see /// the [`SUCCESS`] and [`FAILURE`] associated items. /// -/// [`SUCCESS`]: #constant.SUCCESS -/// [`FAILURE`]: #constant.FAILURE +/// [`SUCCESS`]: #associatedconstant.SUCCESS +/// [`FAILURE`]: #associatedconstant.FAILURE /// /// **Warning**: While various forms of this were discussed in [RFC #1937], /// it was ultimately cut from that RFC, and thus this type is more subject -- cgit 1.4.1-3-g733a5 From 2e2d9260f9425cd700199383096d8201190737de Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Thu, 1 Mar 2018 09:17:49 -0800 Subject: posix_spawn() on OSX supports returning ENOENT. --- src/libstd/sys/unix/process/process_unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index c5dda6273ef..dcf0278b4aa 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -235,14 +235,14 @@ impl Command { io::Error::last_os_error() } - #[cfg(not(any(target_os = "freebsd")))] + #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) -> io::Result> { Ok(None) } - #[cfg(any(target_os = "freebsd"))] + #[cfg(any(target_os = "macos", target_os = "freebsd"))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> { -- cgit 1.4.1-3-g733a5 From ef73b3ae2eac3a03f5b966a4f8b2a568e3619d51 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Thu, 1 Mar 2018 09:18:16 -0800 Subject: Add comment explaining when posix_spawn() can be supported. --- src/libstd/sys/unix/process/process_unix.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index dcf0278b4aa..bd6a8d3f64b 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -242,6 +242,8 @@ impl Command { Ok(None) } + // Only support platforms for which posix_spawn() can return ENOENT + // directly. #[cfg(any(target_os = "macos", target_os = "freebsd"))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> -- cgit 1.4.1-3-g733a5 From 99b50efb6eb048297cda699ad017821822591d7a Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Fri, 2 Mar 2018 08:50:37 -0800 Subject: Use _ --- src/libstd/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index bd6a8d3f64b..51ae0aa7315 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -236,7 +236,7 @@ impl Command { } #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] - fn posix_spawn(&mut self, _stdio: &ChildPipes, _envp: Option<&CStringArray>) + fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>) -> io::Result> { Ok(None) -- cgit 1.4.1-3-g733a5 From 5ba6b3a728fb50cd65237b8eeac2f2df05c3c77f Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Fri, 2 Mar 2018 12:50:07 -0800 Subject: Move glibc version lookup handling to sys::os and add a simpler glibc_version() --- src/libstd/sys/unix/net.rs | 33 +++++---------------------------- src/libstd/sys/unix/os.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 28 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 3f65975e608..04d9f0b06d3 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -383,12 +383,12 @@ impl IntoInner for Socket { // believe it's thread-safe). #[cfg(target_env = "gnu")] fn on_resolver_failure() { + use sys; + // If the version fails to parse, we treat it the same as "not glibc". - if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { - if let Some(version) = parse_glibc_version(version_str) { - if version < (2, 26) { - unsafe { libc::res_init() }; - } + if let Some(version) = sys::os::glibc_version() { + if version < (2, 26) { + unsafe { libc::res_init() }; } } } @@ -396,29 +396,6 @@ fn on_resolver_failure() { #[cfg(not(target_env = "gnu"))] fn on_resolver_failure() {} -#[cfg(target_env = "gnu")] -fn glibc_version_cstr() -> Option<&'static CStr> { - weak! { - fn gnu_get_libc_version() -> *const libc::c_char - } - if let Some(f) = gnu_get_libc_version.get() { - unsafe { Some(CStr::from_ptr(f())) } - } else { - None - } -} - -// Returns Some((major, minor)) if the string is a valid "x.y" version, -// ignoring any extra dot-separated parts. Otherwise return None. -#[cfg(target_env = "gnu")] -fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split(".").map(str::parse::).fuse(); - match (parsed_ints.next(), parsed_ints.next()) { - (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), - _ => None - } -} - #[cfg(all(test, taget_env = "gnu"))] mod test { use super::*; diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index a46e855b4a6..4c86fddee4b 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -546,3 +546,35 @@ pub fn getpid() -> u32 { pub fn getppid() -> u32 { unsafe { libc::getppid() as u32 } } + +#[cfg(target_env = "gnu")] +pub fn glibc_version() -> Option<(usize, usize)> { + if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { + parse_glibc_version(version_str) + } else { + None + } +} + +#[cfg(target_env = "gnu")] +fn glibc_version_cstr() -> Option<&'static CStr> { + weak! { + fn gnu_get_libc_version() -> *const libc::c_char + } + if let Some(f) = gnu_get_libc_version.get() { + unsafe { Some(CStr::from_ptr(f())) } + } else { + None + } +} + +// Returns Some((major, minor)) if the string is a valid "x.y" version, +// ignoring any extra dot-separated parts. Otherwise return None. +#[cfg(target_env = "gnu")] +fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { + let mut parsed_ints = version.split(".").map(str::parse::).fuse(); + match (parsed_ints.next(), parsed_ints.next()) { + (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), + _ => None + } +} -- cgit 1.4.1-3-g733a5 From d740083fc8981ee933dc48a6b3dcee21b82c993e Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Fri, 2 Mar 2018 13:02:38 -0800 Subject: Support posix_spawn() for Linux glibc 2.24+. The relevant support was added in https://sourceware.org/bugzilla/show_bug.cgi?id=10354#c12 --- src/libstd/sys/unix/process/process_unix.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 51ae0aa7315..29e33ee822e 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -235,7 +235,8 @@ impl Command { io::Error::last_os_error() } - #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] + #[cfg(not(any(target_os = "macos", target_os = "freebsd", + all(target_os = "linux", target_env = "gnu"))))] fn posix_spawn(&mut self, _: &ChildPipes, _: Option<&CStringArray>) -> io::Result> { @@ -244,7 +245,8 @@ impl Command { // Only support platforms for which posix_spawn() can return ENOENT // directly. - #[cfg(any(target_os = "macos", target_os = "freebsd"))] + #[cfg(any(target_os = "macos", target_os = "freebsd", + all(target_os = "linux", target_env = "gnu")))] fn posix_spawn(&mut self, stdio: &ChildPipes, envp: Option<&CStringArray>) -> io::Result> { @@ -258,6 +260,18 @@ impl Command { return Ok(None) } + // Only glibc 2.24+ posix_spawn() supports returning ENOENT directly. + #[cfg(all(target_os = "linux", target_env = "gnu"))] + { + if let Some(version) = sys::os::glibc_version() { + if version < (2, 24) { + return Ok(None) + } + } else { + return Ok(None) + } + } + let mut p = Process { pid: 0, status: None }; struct PosixSpawnFileActions(libc::posix_spawn_file_actions_t); -- cgit 1.4.1-3-g733a5 From c72537f20442c9afd0f2f90999163adb43f34953 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 17 Feb 2018 17:23:19 -0800 Subject: std: Add `arch` and `simd` modules This commit imports the `stdsimd` crate into the standard library, creating an `arch` and `simd` module inside of both libcore and libstd. Both of these modules are **unstable** and will continue to be so until RFC 2335 is stabilized. As a brief recap, the modules are organized as so: * `arch` contains all current architectures with intrinsics, for example `std::arch::x86`, `std::arch::x86_64`, `std::arch::arm`, etc. These modules contain all of the intrinsics defined for the platform, like `_mm_set1_epi8`. * In the standard library, the `arch` module also exports a `is_target_feature_detected` macro which performs runtime detection to determine whether a target feature is available at runtime. * The `simd` module contains experimental versions of strongly-typed lane-aware SIMD primitives, to be fully fleshed out in a future RFC. The main purpose of this commit is to start pulling in all these intrinsics and such into the standard library on nightly and allow testing and such. This'll help allow users to easily kick the tires and see if intrinsics work as well as allow us to test out all the infrastructure for moving the intrinsics into the standard library. --- .gitmodules | 3 +++ src/libcore/lib.rs | 33 +++++++++++++++++++++++++++++---- src/libstd/lib.rs | 30 ++++++++++++++++++++++++++++++ src/stdsimd | 1 + src/tools/tidy/src/lib.rs | 1 + 5 files changed, 64 insertions(+), 4 deletions(-) create mode 160000 src/stdsimd (limited to 'src/libstd') diff --git a/.gitmodules b/.gitmodules index fc2f8bbc8a3..5b7fd481299 100644 --- a/.gitmodules +++ b/.gitmodules @@ -50,3 +50,6 @@ [submodule "src/llvm-emscripten"] path = src/llvm-emscripten url = https://github.com/rust-lang/llvm +[submodule "src/stdsimd"] + path = src/stdsimd + url = https://github.com/rust-lang-nursery/stdsimd diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 3dd30ee1c69..1efd605112d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -68,16 +68,21 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_type_defaults)] +#![feature(attr_literals)] #![feature(cfg_target_feature)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(doc_spotlight)] #![feature(fundamental)] #![feature(i128_type)] #![feature(inclusive_range_syntax)] #![feature(intrinsics)] +#![feature(iterator_flatten)] +#![feature(iterator_repeat_with)] #![feature(lang_items)] +#![feature(link_llvm_intrinsics)] #![feature(never_type)] #![feature(no_core)] #![feature(on_unimplemented)] @@ -85,15 +90,17 @@ #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] +#![feature(rustc_const_unstable)] +#![feature(simd_ffi)] #![feature(specialization)] #![feature(staged_api)] +#![feature(stmt_expr_attributes)] +#![feature(target_feature)] #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![feature(doc_spotlight)] -#![feature(rustc_const_unstable)] -#![feature(iterator_repeat_with)] -#![feature(iterator_flatten)] + +#![cfg_attr(stage0, allow(unused_attributes))] #[prelude_import] #[allow(unused)] @@ -179,3 +186,21 @@ mod char_private; mod iter_private; mod tuple; mod unit; + +// Pull in the the `coresimd` crate directly into libcore. This is where all the +// architecture-specific (and vendor-specific) intrinsics are defined. AKA +// things like SIMD and such. Note that the actual source for all this lies in a +// different repository, rust-lang-nursery/stdsimd. That's why the setup here is +// a bit wonky. +#[path = "../stdsimd/coresimd/mod.rs"] +#[allow(missing_docs, missing_debug_implementations, dead_code)] +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 +mod coresimd; + +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(not(stage0))] +pub use coresimd::simd; +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(not(stage0))] +pub use coresimd::arch; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d7d856fe3ad..a7e1c0ce732 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -299,6 +299,7 @@ #![feature(rand)] #![feature(raw)] #![feature(rustc_attrs)] +#![feature(stdsimd)] #![feature(sip_hash_13)] #![feature(slice_bytes)] #![feature(slice_concat_ext)] @@ -501,6 +502,35 @@ mod memchr; // compiler pub mod rt; +// Pull in the the `stdsimd` crate directly into libstd. This is the same as +// libcore's arch/simd modules where the source of truth here is in a different +// repository, but we pull things in here manually to get it into libstd. +// +// Note that the #[cfg] here is intended to do two things. First it allows us to +// change the rustc implementation of intrinsics in stage0 by not compiling simd +// intrinsics in stage0. Next it doesn't compile anything in test mode as +// stdsimd has tons of its own tests which we don't want to run. +#[path = "../stdsimd/stdsimd/mod.rs"] +#[allow(missing_debug_implementations, missing_docs, dead_code)] +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(all(not(stage0), not(test)))] +mod stdsimd; + +// A "fake" module needed by the `stdsimd` module to compile, not actually +// exported though. +#[cfg(not(stage0))] +mod coresimd { + pub use core::arch; + pub use core::simd; +} + +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(all(not(stage0), not(test)))] +pub use stdsimd::simd; +#[unstable(feature = "stdsimd", issue = "48556")] +#[cfg(all(not(stage0), not(test)))] +pub use stdsimd::arch; + // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/stdsimd b/src/stdsimd new file mode 160000 index 00000000000..678cbd325c8 --- /dev/null +++ b/src/stdsimd @@ -0,0 +1 @@ +Subproject commit 678cbd325c84070c9dbe4303969fbd2734c0b4ee diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 4d89008d5ca..1def3048ce0 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -71,6 +71,7 @@ fn filter_dirs(path: &Path) -> bool { "src/librustc/mir/interpret", "src/librustc_mir/interpret", "src/target", + "src/stdsimd", ]; skip.iter().any(|p| path.ends_with(p)) } -- cgit 1.4.1-3-g733a5 From bc651cac8d671aee9be876b71d0fa86f94f56b0f Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Mon, 15 Jan 2018 19:59:10 +0100 Subject: core: Stabilize FusedIterator FusedIterator is a marker trait that promises that the implementing iterator continues to return `None` from `.next()` once it has returned `None` once (and/or `.next_back()`, if implemented). The effects of FusedIterator are already widely available through `.fuse()`, but with stable `FusedIterator`, stable Rust users can implement this trait for their iterators when appropriate. --- src/liballoc/binary_heap.rs | 6 +++--- src/liballoc/boxed.rs | 2 +- src/liballoc/btree/map.rs | 16 +++++++-------- src/liballoc/btree/set.rs | 14 ++++++------- src/liballoc/lib.rs | 3 +-- src/liballoc/linked_list.rs | 6 +++--- src/liballoc/str.rs | 2 +- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 4 ++-- src/liballoc/vec_deque.rs | 8 ++++---- src/libcore/char.rs | 8 ++++---- src/libcore/iter/mod.rs | 42 +++++++++++++++++++------------------- src/libcore/iter/range.rs | 6 +++--- src/libcore/iter/sources.rs | 6 +++--- src/libcore/iter/traits.rs | 4 ++-- src/libcore/option.rs | 6 +++--- src/libcore/result.rs | 6 +++--- src/libcore/slice/mod.rs | 24 +++++++++++----------- src/libcore/str/mod.rs | 14 ++++++------- src/libstd/ascii.rs | 2 +- src/libstd/collections/hash/map.rs | 14 ++++++------- src/libstd/collections/hash/set.rs | 14 ++++++------- src/libstd/lib.rs | 1 - src/libstd/path.rs | 4 ++-- src/libstd_unicode/char.rs | 4 ++-- src/libstd_unicode/lib.rs | 1 - src/libstd_unicode/u_str.rs | 4 ++-- src/test/run-pass/issue-36053.rs | 1 - 28 files changed, 110 insertions(+), 114 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index 3041f85cd4c..a5694a90dbc 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -964,7 +964,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. @@ -1019,7 +1019,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `BinaryHeap`. @@ -1065,7 +1065,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 75a59de337c..6b000b6fa91 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -722,7 +722,7 @@ impl ExactSizeIterator for Box { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Box {} diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 618ef81fdd9..7b7a6374db9 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1156,7 +1156,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1235,7 +1235,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1365,7 +1365,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1395,7 +1395,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1432,7 +1432,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1482,7 +1482,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} @@ -1561,7 +1561,7 @@ impl<'a, K, V> Range<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Range<'a, K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -1630,7 +1630,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 327eaaf4651..34cb7a08ed7 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -946,7 +946,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -971,7 +971,7 @@ impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -997,7 +997,7 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Range<'a, T> {} /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None @@ -1044,7 +1044,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1078,7 +1078,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1116,7 +1116,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1150,5 +1150,5 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d250cfe1880..2212b62dfd8 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -96,7 +96,6 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![feature(fused)] #![feature(generic_param_attrs)] #![feature(i128_type)] #![feature(inclusive_range)] @@ -125,7 +124,7 @@ #![feature(on_unimplemented)] #![feature(exact_chunks)] -#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))] +#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] // Allow testing this library diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index ec579e3fd68..87939fddfc8 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -897,7 +897,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -946,7 +946,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} impl<'a, T> IterMut<'a, T> { @@ -1117,7 +1117,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index a00e3d17dd0..1a431bb2694 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -171,7 +171,7 @@ impl<'a> Iterator for EncodeUtf16<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for EncodeUtf16<'a> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 409d2ab287e..1fcabd8a427 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2254,5 +2254,5 @@ impl<'a> DoubleEndedIterator for Drain<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Drain<'a> {} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 3c9b6b94b44..03c9750fb39 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2389,7 +2389,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2495,7 +2495,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Drain<'a, T> {} /// A place for insertion at the back of a `Vec`. diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 8b686365e69..3d7549abe6f 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -1991,7 +1991,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -2084,7 +2084,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. @@ -2140,7 +2140,7 @@ impl ExactSizeIterator for IntoIter { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `VecDeque`. @@ -2247,7 +2247,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 7215bd2a476..3ff31a7a928 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -643,7 +643,7 @@ impl ExactSizeIterator for EscapeUnicode { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeUnicode {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -756,7 +756,7 @@ impl ExactSizeIterator for EscapeDefault { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -790,7 +790,7 @@ impl Iterator for EscapeDebug { #[stable(feature = "char_escape_debug", since = "1.20.0")] impl ExactSizeIterator for EscapeDebug { } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeDebug {} #[stable(feature = "char_escape_debug", since = "1.20.0")] @@ -904,5 +904,5 @@ impl> Iterator for DecodeUtf8 { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 257d7d6caaa..9a8f7fc4e6a 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -344,7 +344,7 @@ pub use self::sources::{Once, once}; pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Sum, Product}; -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] pub use self::traits::FusedIterator; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; @@ -506,7 +506,7 @@ impl ExactSizeIterator for Rev } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} @@ -589,7 +589,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, I, T: 'a> FusedIterator for Cloned where I: FusedIterator, T: Clone {} @@ -662,7 +662,7 @@ impl Iterator for Cycle where I: Clone + Iterator { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Cycle where I: Clone + Iterator {} /// An iterator for stepping iterators by a custom amount. @@ -1002,7 +1002,7 @@ impl DoubleEndedIterator for Chain where } // Note: *both* must be fused to handle double-ended iterators. -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Chain where A: FusedIterator, B: FusedIterator, @@ -1262,7 +1262,7 @@ unsafe impl TrustedRandomAccess for Zip } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Zip where A: FusedIterator, B: FusedIterator, {} @@ -1404,7 +1404,7 @@ impl ExactSizeIterator for Map } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Map where F: FnMut(I::Item) -> B {} @@ -1553,7 +1553,7 @@ impl DoubleEndedIterator for Filter } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} @@ -1663,7 +1663,7 @@ impl DoubleEndedIterator for FilterMap } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} @@ -1818,7 +1818,7 @@ unsafe impl TrustedRandomAccess for Enumerate } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Enumerate where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1938,7 +1938,7 @@ impl Iterator for Peekable { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Peekable {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Peekable {} impl Peekable { @@ -2072,7 +2072,7 @@ impl Iterator for SkipWhile } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for SkipWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2151,7 +2151,7 @@ impl Iterator for TakeWhile } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for TakeWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2290,7 +2290,7 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Skip where I: FusedIterator {} /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -2371,7 +2371,7 @@ impl Iterator for Take where I: Iterator{ #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Take where I: ExactSizeIterator {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Take where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2517,7 +2517,7 @@ impl DoubleEndedIterator for FlatMap } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for FlatMap where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} @@ -2605,7 +2605,7 @@ impl DoubleEndedIterator for Flatten } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} @@ -2765,7 +2765,7 @@ pub struct Fuse { done: bool } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Fuse where I: Iterator {} #[stable(feature = "rust1", since = "1.0.0")] @@ -2896,7 +2896,7 @@ unsafe impl TrustedRandomAccess for Fuse } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl Iterator for Fuse where I: FusedIterator { #[inline] fn next(&mut self) -> Option<::Item> { @@ -2938,7 +2938,7 @@ impl Iterator for Fuse where I: FusedIterator { } } -#[unstable(feature = "fused", reason = "recently added", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator + FusedIterator { @@ -3082,6 +3082,6 @@ impl ExactSizeIterator for Inspect } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 65b38c94dda..7f3b227e8b7 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -295,7 +295,7 @@ impl DoubleEndedIterator for ops::Range { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ops::Range {} #[stable(feature = "rust1", since = "1.0.0")] @@ -322,7 +322,7 @@ impl Iterator for ops::RangeFrom { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ops::RangeFrom {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -463,5 +463,5 @@ impl DoubleEndedIterator for ops::RangeInclusive { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ops::RangeInclusive {} diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index dfd42f3e733..149dff83bc0 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -41,7 +41,7 @@ impl DoubleEndedIterator for Repeat { fn next_back(&mut self) -> Option { Some(self.element.clone()) } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Repeat {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -259,7 +259,7 @@ impl ExactSizeIterator for Empty { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Empty {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Empty {} // not #[derive] because that adds a Clone bound on T, @@ -340,7 +340,7 @@ impl ExactSizeIterator for Once { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Once {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 860742d9eab..a86f4e74706 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -959,10 +959,10 @@ impl Product> for Result /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse /// [`Fuse`]: ../../std/iter/struct.Fuse.html -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] pub trait FusedIterator: Iterator {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// An iterator that reports an accurate length using size_hint. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index b8fe28d0f0d..99c1d7d9b36 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1051,7 +1051,7 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for Iter<'a, A> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, A> FusedIterator for Iter<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1096,7 +1096,7 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} @@ -1133,7 +1133,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 3801db94e15..5131fc837ef 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1038,7 +1038,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1082,7 +1082,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1125,7 +1125,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index a43ed65907f..02207f1738f 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1461,7 +1461,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1589,7 +1589,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1737,7 +1737,7 @@ impl<'a, T, P> SplitIter for Split<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the subslices of the vector which are separated @@ -1835,7 +1835,7 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over subslices separated by elements that match a predicate @@ -1892,7 +1892,7 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -//#[unstable(feature = "fused", issue = "35602")] +//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} @@ -1951,7 +1951,7 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where } } -//#[unstable(feature = "fused", issue = "35602")] +//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} @@ -2088,7 +2088,7 @@ macro_rules! forward_iterator { } } - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.25.0")] impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} } @@ -2194,7 +2194,7 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Windows<'a, T> {} #[doc(hidden)] @@ -2313,7 +2313,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for Chunks<'a, T> {} #[doc(hidden)] @@ -2429,7 +2429,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for ChunksMut<'a, T> {} #[doc(hidden)] @@ -2539,7 +2539,7 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for ExactChunks<'a, T> {} #[doc(hidden)] @@ -2636,7 +2636,7 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {} #[doc(hidden)] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 765b369e4b2..7e919b653f2 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -609,7 +609,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Chars<'a> {} impl<'a> Chars<'a> { @@ -702,7 +702,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for CharIndices<'a> {} impl<'a> CharIndices<'a> { @@ -817,7 +817,7 @@ impl<'a> ExactSizeIterator for Bytes<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Bytes<'a> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -977,10 +977,10 @@ macro_rules! generate_pattern_iterators { } } - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.25.0")] impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - #[unstable(feature = "fused", issue = "35602")] + #[stable(feature = "fused", since = "1.25.0")] impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P> where P::Searcher: ReverseSearcher<'a> {} @@ -1337,7 +1337,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Lines<'a> {} /// Created with the method [`lines_any`]. @@ -1403,7 +1403,7 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] #[allow(deprecated)] impl<'a> FusedIterator for LinesAny<'a> {} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 430c9df396a..ce3e38de7eb 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -590,7 +590,7 @@ impl DoubleEndedIterator for EscapeDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4dfdc23ebee..9e48efeb113 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1750,7 +1750,7 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1773,7 +1773,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1808,7 +1808,7 @@ impl ExactSizeIterator for IntoIter { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1840,7 +1840,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1863,7 +1863,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1886,7 +1886,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1921,7 +1921,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { self.inner.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e9427fb40a0..7a46603b2db 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1097,7 +1097,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1124,7 +1124,7 @@ impl ExactSizeIterator for IntoIter { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1155,7 +1155,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { self.iter.len() } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1208,7 +1208,7 @@ impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1244,7 +1244,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for Difference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1283,7 +1283,7 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1307,7 +1307,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a, T, S> FusedIterator for Union<'a, T, S> where T: Eq + Hash, S: BuildHasher diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d7d856fe3ad..82c4443a45e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -266,7 +266,6 @@ #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] -#![feature(fused)] #![feature(generic_param_attrs)] #![feature(hashmap_hasher)] #![feature(heap_api)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 1608a752a46..0c54fb00d2d 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -905,7 +905,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Iter<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1008,7 +1008,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for Components<'a> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 844ff7a3c12..2bbbf6c0655 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -70,7 +70,7 @@ impl Iterator for ToLowercase { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ToLowercase {} /// Returns an iterator that yields the uppercase equivalent of a `char`. @@ -92,7 +92,7 @@ impl Iterator for ToUppercase { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for ToUppercase {} #[derive(Debug)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index dcae7d0af40..f155b62e3cc 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -36,7 +36,6 @@ #![feature(str_internals)] #![feature(decode_utf8)] #![feature(fn_traits)] -#![feature(fused)] #![feature(lang_items)] #![feature(non_exhaustive)] #![feature(staged_api)] diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index 5d1611acb7e..ed2f205b580 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -127,7 +127,7 @@ impl Iterator for Utf16Encoder } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Utf16Encoder where I: FusedIterator {} @@ -186,5 +186,5 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[stable(feature = "fused", since = "1.25.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/test/run-pass/issue-36053.rs b/src/test/run-pass/issue-36053.rs index 2411996cf05..ece58eedc56 100644 --- a/src/test/run-pass/issue-36053.rs +++ b/src/test/run-pass/issue-36053.rs @@ -14,7 +14,6 @@ // `FusedIterator` in std but I was not able to isolate that into an // external crate. -#![feature(fused)] use std::iter::FusedIterator; struct Thing<'a>(&'a str); -- cgit 1.4.1-3-g733a5 From c7c23fe9482c129855a667909ff58969f6efe1f6 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sat, 3 Mar 2018 14:15:28 +0100 Subject: core: Update stability attributes for FusedIterator --- src/liballoc/binary_heap.rs | 6 +++--- src/liballoc/boxed.rs | 2 +- src/liballoc/btree/map.rs | 16 +++++++-------- src/liballoc/btree/set.rs | 14 ++++++------- src/liballoc/linked_list.rs | 6 +++--- src/liballoc/str.rs | 2 +- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 4 ++-- src/liballoc/vec_deque.rs | 8 ++++---- src/libcore/char.rs | 8 ++++---- src/libcore/iter/mod.rs | 42 +++++++++++++++++++------------------- src/libcore/iter/range.rs | 6 +++--- src/libcore/iter/sources.rs | 8 ++++---- src/libcore/iter/traits.rs | 4 ++-- src/libcore/option.rs | 6 +++--- src/libcore/result.rs | 6 +++--- src/libcore/slice/mod.rs | 22 +++++++++----------- src/libcore/str/mod.rs | 14 ++++++------- src/libstd/ascii.rs | 2 +- src/libstd/collections/hash/map.rs | 14 ++++++------- src/libstd/collections/hash/set.rs | 14 ++++++------- src/libstd/path.rs | 6 +++--- src/libstd_unicode/char.rs | 4 ++-- src/libstd_unicode/u_str.rs | 3 +-- 24 files changed, 108 insertions(+), 111 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index a5694a90dbc..8aaac5d6e08 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -964,7 +964,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. @@ -1019,7 +1019,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `BinaryHeap`. @@ -1065,7 +1065,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6b000b6fa91..b776556d59f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -722,7 +722,7 @@ impl ExactSizeIterator for Box { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Box {} diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 7b7a6374db9..ed9c8c18f0d 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1156,7 +1156,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1235,7 +1235,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1365,7 +1365,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1395,7 +1395,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1432,7 +1432,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1482,7 +1482,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} @@ -1561,7 +1561,7 @@ impl<'a, K, V> Range<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Range<'a, K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -1630,7 +1630,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 34cb7a08ed7..2e3157147a0 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -946,7 +946,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { fn len(&self) -> usize { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -971,7 +971,7 @@ impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "btree_range", since = "1.17.0")] @@ -997,7 +997,7 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Range<'a, T> {} /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None @@ -1044,7 +1044,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1078,7 +1078,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1116,7 +1116,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1150,5 +1150,5 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 87939fddfc8..097d2e414f5 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -897,7 +897,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -946,7 +946,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} impl<'a, T> IterMut<'a, T> { @@ -1117,7 +1117,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 1a431bb2694..82f8476d670 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -171,7 +171,7 @@ impl<'a> Iterator for EncodeUtf16<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for EncodeUtf16<'a> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 1fcabd8a427..370fb6b4e89 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2254,5 +2254,5 @@ impl<'a> DoubleEndedIterator for Drain<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Drain<'a> {} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 03c9750fb39..9e5672ef148 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2389,7 +2389,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2495,7 +2495,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Drain<'a, T> {} /// A place for insertion at the back of a `Vec`. diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 3d7549abe6f..68add3cbd51 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -1991,7 +1991,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} @@ -2084,7 +2084,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. @@ -2140,7 +2140,7 @@ impl ExactSizeIterator for IntoIter { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} /// A draining iterator over the elements of a `VecDeque`. @@ -2247,7 +2247,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 3ff31a7a928..c90cca7dbe4 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -643,7 +643,7 @@ impl ExactSizeIterator for EscapeUnicode { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeUnicode {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -756,7 +756,7 @@ impl ExactSizeIterator for EscapeDefault { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "char_struct_display", since = "1.16.0")] @@ -790,7 +790,7 @@ impl Iterator for EscapeDebug { #[stable(feature = "char_escape_debug", since = "1.20.0")] impl ExactSizeIterator for EscapeDebug { } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDebug {} #[stable(feature = "char_escape_debug", since = "1.20.0")] @@ -904,5 +904,5 @@ impl> Iterator for DecodeUtf8 { } } -#[stable(feature = "fused", since = "1.25.0")] +#[unstable(feature = "decode_utf8", issue = "33906")] impl> FusedIterator for DecodeUtf8 {} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 9a8f7fc4e6a..a6802d606ca 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -344,7 +344,7 @@ pub use self::sources::{Once, once}; pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Sum, Product}; -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] pub use self::traits::FusedIterator; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; @@ -506,7 +506,7 @@ impl ExactSizeIterator for Rev } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} @@ -589,7 +589,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, I, T: 'a> FusedIterator for Cloned where I: FusedIterator, T: Clone {} @@ -662,7 +662,7 @@ impl Iterator for Cycle where I: Clone + Iterator { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Cycle where I: Clone + Iterator {} /// An iterator for stepping iterators by a custom amount. @@ -1002,7 +1002,7 @@ impl DoubleEndedIterator for Chain where } // Note: *both* must be fused to handle double-ended iterators. -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Chain where A: FusedIterator, B: FusedIterator, @@ -1262,7 +1262,7 @@ unsafe impl TrustedRandomAccess for Zip } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Zip where A: FusedIterator, B: FusedIterator, {} @@ -1404,7 +1404,7 @@ impl ExactSizeIterator for Map } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Map where F: FnMut(I::Item) -> B {} @@ -1553,7 +1553,7 @@ impl DoubleEndedIterator for Filter } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} @@ -1663,7 +1663,7 @@ impl DoubleEndedIterator for FilterMap } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} @@ -1818,7 +1818,7 @@ unsafe impl TrustedRandomAccess for Enumerate } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Enumerate where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1938,7 +1938,7 @@ impl Iterator for Peekable { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Peekable {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Peekable {} impl Peekable { @@ -2072,7 +2072,7 @@ impl Iterator for SkipWhile } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for SkipWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2151,7 +2151,7 @@ impl Iterator for TakeWhile } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for TakeWhile where I: FusedIterator, P: FnMut(&I::Item) -> bool {} @@ -2290,7 +2290,7 @@ impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSize } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Skip where I: FusedIterator {} /// An iterator that only iterates over the first `n` iterations of `iter`. @@ -2371,7 +2371,7 @@ impl Iterator for Take where I: Iterator{ #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Take where I: ExactSizeIterator {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Take where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -2517,7 +2517,7 @@ impl DoubleEndedIterator for FlatMap } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FlatMap where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} @@ -2605,7 +2605,7 @@ impl DoubleEndedIterator for Flatten } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} @@ -2765,7 +2765,7 @@ pub struct Fuse { done: bool } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Fuse where I: Iterator {} #[stable(feature = "rust1", since = "1.0.0")] @@ -2896,7 +2896,7 @@ unsafe impl TrustedRandomAccess for Fuse } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl Iterator for Fuse where I: FusedIterator { #[inline] fn next(&mut self) -> Option<::Item> { @@ -2938,7 +2938,7 @@ impl Iterator for Fuse where I: FusedIterator { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator + FusedIterator { @@ -3082,6 +3082,6 @@ impl ExactSizeIterator for Inspect } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 7f3b227e8b7..9a3fd215dcf 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -295,7 +295,7 @@ impl DoubleEndedIterator for ops::Range { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::Range {} #[stable(feature = "rust1", since = "1.0.0")] @@ -322,7 +322,7 @@ impl Iterator for ops::RangeFrom { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeFrom {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -463,5 +463,5 @@ impl DoubleEndedIterator for ops::RangeInclusive { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 149dff83bc0..0fc1a3aa8ac 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -41,7 +41,7 @@ impl DoubleEndedIterator for Repeat { fn next_back(&mut self) -> Option { Some(self.element.clone()) } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Repeat {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -135,7 +135,7 @@ impl A> DoubleEndedIterator for RepeatWith { fn next_back(&mut self) -> Option { self.next() } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "iterator_repeat_with", issue = "48169")] impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -259,7 +259,7 @@ impl ExactSizeIterator for Empty { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Empty {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Empty {} // not #[derive] because that adds a Clone bound on T, @@ -340,7 +340,7 @@ impl ExactSizeIterator for Once { #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Once {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index a86f4e74706..0267fcd3754 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -959,10 +959,10 @@ impl Product> for Result /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse /// [`Fuse`]: ../../std/iter/struct.Fuse.html -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] pub trait FusedIterator: Iterator {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} /// An iterator that reports an accurate length using size_hint. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 99c1d7d9b36..b66aad246fe 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1051,7 +1051,7 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for Iter<'a, A> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, A> FusedIterator for Iter<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1096,7 +1096,7 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} @@ -1133,7 +1133,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 5131fc837ef..c152d4979b9 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1038,7 +1038,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Iter<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1082,7 +1082,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1125,7 +1125,7 @@ impl DoubleEndedIterator for IntoIter { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 02207f1738f..4f1ee2d9491 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1461,7 +1461,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Iter<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1589,7 +1589,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for IterMut<'a, T> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -1737,7 +1737,7 @@ impl<'a, T, P> SplitIter for Split<'a, T, P> where P: FnMut(&T) -> bool { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the subslices of the vector which are separated @@ -1835,7 +1835,7 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over subslices separated by elements that match a predicate @@ -1892,7 +1892,6 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} @@ -1951,7 +1950,6 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where } } -//#[stable(feature = "fused", since = "1.25.0")] #[unstable(feature = "slice_rsplit", issue = "41020")] impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} @@ -2088,7 +2086,7 @@ macro_rules! forward_iterator { } } - #[stable(feature = "fused", since = "1.25.0")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} } @@ -2194,7 +2192,7 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Windows<'a, T> {} #[doc(hidden)] @@ -2313,7 +2311,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Chunks<'a, T> {} #[doc(hidden)] @@ -2429,7 +2427,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for ChunksMut<'a, T> {} #[doc(hidden)] @@ -2539,7 +2537,7 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunks<'a, T> {} #[doc(hidden)] @@ -2636,7 +2634,7 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {} #[doc(hidden)] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e919b653f2..e225c9522bc 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -609,7 +609,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Chars<'a> {} impl<'a> Chars<'a> { @@ -702,7 +702,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for CharIndices<'a> {} impl<'a> CharIndices<'a> { @@ -817,7 +817,7 @@ impl<'a> ExactSizeIterator for Bytes<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Bytes<'a> {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -977,10 +977,10 @@ macro_rules! generate_pattern_iterators { } } - #[stable(feature = "fused", since = "1.25.0")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - #[stable(feature = "fused", since = "1.25.0")] + #[stable(feature = "fused", since = "1.26.0")] impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P> where P::Searcher: ReverseSearcher<'a> {} @@ -1337,7 +1337,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Lines<'a> {} /// Created with the method [`lines_any`]. @@ -1403,7 +1403,7 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] #[allow(deprecated)] impl<'a> FusedIterator for LinesAny<'a> {} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index ce3e38de7eb..d5bf9e9bb2f 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -590,7 +590,7 @@ impl DoubleEndedIterator for EscapeDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for EscapeDefault {} -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EscapeDefault {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 9e48efeb113..e86264569a0 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1750,7 +1750,7 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1773,7 +1773,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1808,7 +1808,7 @@ impl ExactSizeIterator for IntoIter { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1840,7 +1840,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1863,7 +1863,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1886,7 +1886,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1921,7 +1921,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { self.inner.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 7a46603b2db..f41b7a62918 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -1097,7 +1097,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Iter<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1124,7 +1124,7 @@ impl ExactSizeIterator for IntoIter { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1155,7 +1155,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> { self.iter.len() } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, K> FusedIterator for Drain<'a, K> {} #[stable(feature = "std_debug", since = "1.16.0")] @@ -1208,7 +1208,7 @@ impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1244,7 +1244,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Difference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1283,7 +1283,7 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> where T: Eq + Hash, S: BuildHasher @@ -1307,7 +1307,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a, T, S> FusedIterator for Union<'a, T, S> where T: Eq + Hash, S: BuildHasher diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0c54fb00d2d..cd2af99d6ac 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -905,7 +905,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Iter<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1008,7 +1008,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for Components<'a> {} #[stable(feature = "rust1", since = "1.0.0")] @@ -1076,7 +1076,7 @@ impl<'a> Iterator for Ancestors<'a> { } } -#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "path_ancestors", issue = "48581")] impl<'a> FusedIterator for Ancestors<'a> {} //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 2bbbf6c0655..8d3df749ed7 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -70,7 +70,7 @@ impl Iterator for ToLowercase { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToLowercase {} /// Returns an iterator that yields the uppercase equivalent of a `char`. @@ -92,7 +92,7 @@ impl Iterator for ToUppercase { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ToUppercase {} #[derive(Debug)] diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index ed2f205b580..a72e1210d93 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -127,7 +127,6 @@ impl Iterator for Utf16Encoder } } -#[stable(feature = "fused", since = "1.25.0")] impl FusedIterator for Utf16Encoder where I: FusedIterator {} @@ -186,5 +185,5 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { } } -#[stable(feature = "fused", since = "1.25.0")] +#[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} -- cgit 1.4.1-3-g733a5 From 74c5c6e6cb0425284f57fece6fbf248e827ea06d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 3 Mar 2018 18:29:30 -0800 Subject: Move process::ExitCode internals to sys Now begins the saga of fixing compilation errors on other platforms... --- src/libstd/process.rs | 29 ++++++++------------------- src/libstd/sys/cloudabi/shims/process.rs | 12 +++++++++++ src/libstd/sys/redox/process.rs | 13 ++++++++++++ src/libstd/sys/unix/process/mod.rs | 2 +- src/libstd/sys/unix/process/process_common.rs | 14 ++++++++++++- src/libstd/sys/wasm/process.rs | 12 +++++++++++ src/libstd/sys/windows/process.rs | 14 ++++++++++++- 7 files changed, 72 insertions(+), 24 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 5a06bf45aaa..d5ac2d19e83 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1098,38 +1098,26 @@ impl fmt::Display for ExitStatus { /// /// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 #[derive(Clone, Copy, Debug)] -#[unstable(feature = "process_exitcode_placeholder", issue = "43301")] -pub struct ExitCode(pub i32); +#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] +pub struct ExitCode(imp::ExitCode); -#[cfg(target_arch = "wasm32")] -mod rawexit { - pub const SUCCESS: i32 = 0; - pub const FAILURE: i32 = 1; -} -#[cfg(not(target_arch = "wasm32"))] -mod rawexit { - use libc; - pub const SUCCESS: i32 = libc::EXIT_SUCCESS; - pub const FAILURE: i32 = libc::EXIT_FAILURE; -} - -#[unstable(feature = "process_exitcode_placeholder", issue = "43301")] +#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] impl ExitCode { /// The canonical ExitCode for successful termination on this platform. /// /// Note that a `()`-returning `main` implicitly results in a successful /// termination, so there's no need to return this from `main` unless /// you're also returning other possible codes. - #[unstable(feature = "process_exitcode_placeholder", issue = "43301")] - pub const SUCCESS: ExitCode = ExitCode(rawexit::SUCCESS); + #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] + pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS); /// The canonical ExitCode for unsuccessful termination on this platform. /// /// If you're only returning this and `SUCCESS` from `main`, consider /// instead returning `Err(_)` and `Ok(())` respectively, which will /// return the same codes (but will also `eprintln!` the error). - #[unstable(feature = "process_exitcode_placeholder", issue = "43301")] - pub const FAILURE: ExitCode = ExitCode(rawexit::FAILURE); + #[unstable(feature = "process_exitcode_placeholder", issue = "48711")] + pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE); } impl Child { @@ -1494,8 +1482,7 @@ impl Termination for Result { #[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for ExitCode { fn report(self) -> i32 { - let ExitCode(code) = self; - code + self.0.as_i32() } } diff --git a/src/libstd/sys/cloudabi/shims/process.rs b/src/libstd/sys/cloudabi/shims/process.rs index 52e8c82e2b2..fcd40c15c17 100644 --- a/src/libstd/sys/cloudabi/shims/process.rs +++ b/src/libstd/sys/cloudabi/shims/process.rs @@ -126,6 +126,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + pub struct Process(Void); impl Process { diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 3fd54973896..d0b94e14f54 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -13,6 +13,7 @@ use ffi::OsStr; use os::unix::ffi::OsStrExt; use fmt; use io::{self, Error, ErrorKind}; +use libc::{EXIT_SUCCESS, EXIT_FAILURE}; use path::{Path, PathBuf}; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; @@ -480,6 +481,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(u8); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); + pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + /// The unique id of the process (this should never be negative). pub struct Process { pid: usize, diff --git a/src/libstd/sys/unix/process/mod.rs b/src/libstd/sys/unix/process/mod.rs index 2a331069bc2..d8ac26c45b1 100644 --- a/src/libstd/sys/unix/process/mod.rs +++ b/src/libstd/sys/unix/process/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::process_common::{Command, ExitStatus, Stdio, StdioPipes}; +pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::Process; mod process_common; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 7e057401fab..d0486f06a14 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -13,7 +13,7 @@ use os::unix::prelude::*; use ffi::{OsString, OsStr, CString, CStr}; use fmt; use io; -use libc::{self, c_int, gid_t, uid_t, c_char}; +use libc::{self, c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE}; use ptr; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; @@ -393,6 +393,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(u8); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); + pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + #[cfg(all(test, not(target_os = "emscripten")))] mod tests { use super::*; diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs index f3f5de350f1..433e9cec7c8 100644 --- a/src/libstd/sys/wasm/process.rs +++ b/src/libstd/sys/wasm/process.rs @@ -129,6 +129,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + pub struct Process(Void); impl Process { diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index c93179869a6..f1ab9c47609 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -18,7 +18,7 @@ use ffi::{OsString, OsStr}; use fmt; use fs; use io::{self, Error, ErrorKind}; -use libc::c_void; +use libc::{c_void, EXIT_SUCCESS, EXIT_FAILURE}; use mem; use os::windows::ffi::OsStrExt; use path::Path; @@ -408,6 +408,18 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(c::DWORD); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); + pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + fn zeroed_startupinfo() -> c::STARTUPINFO { c::STARTUPINFO { cb: 0, -- cgit 1.4.1-3-g733a5 From 05a9acc3b844ff284a3e3d85dde2d9798abfb215 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sun, 18 Feb 2018 00:36:57 +0900 Subject: Implement FromStr for PathBuf --- src/libstd/path.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index e03a182653e..a41f76228a9 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -87,6 +87,7 @@ use io; use iter::{self, FusedIterator}; use ops::{self, Deref}; use rc::Rc; +use str::FromStr; use sync::Arc; use ffi::{OsStr, OsString}; @@ -1397,6 +1398,32 @@ impl From for PathBuf { } } +/// Error returned from [`PathBuf::from_str`][`from_str`]. +/// +/// Note that parsing a path will never fail. This error is just a placeholder +/// for implementing `FromStr` for `PathBuf`. +/// +/// [`from_str`]: struct.PathBuf.html#method.from_str +#[derive(Debug, Clone, PartialEq, Eq)] +#[stable(feature = "path_from_str", since = "1.26.0")] +pub enum ParsePathError {} + +#[stable(feature = "path_from_str", since = "1.26.0")] +impl fmt::Display for ParsePathError { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + match *self {} + } +} + +#[stable(feature = "path_from_str", since = "1.26.0")] +impl FromStr for PathBuf { + type Err = ParsePathError; + + fn from_str(s: &str) -> Result { + Ok(PathBuf::from(s)) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl> iter::FromIterator

(&self, base: P) + -> Result<&Path, StripPrefixError> where P: AsRef { self._strip_prefix(base.as_ref()) } - fn _strip_prefix<'a>(&'a self, base: &Path) - -> Result<&'a Path, StripPrefixError> { + fn _strip_prefix(&self, base: &Path) + -> Result<&Path, StripPrefixError> { iter_after(self.components(), base.components()) .map(|c| c.as_path()) .ok_or(StripPrefixError(())) -- cgit 1.4.1-3-g733a5 From e85c9227c2e913b71f0d7b6cc2322d7897f28554 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Tue, 27 Feb 2018 16:51:12 +0900 Subject: rustc_driver: get rid of extra thread on Unix --- src/librustc_driver/lib.rs | 51 ++++++++++++++++++++++++++++++------ src/libstd/sys_common/thread_info.rs | 4 +++ src/libstd/thread/mod.rs | 8 ++++++ 3 files changed, 55 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f1f3a0519bb..8605764497a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,6 +24,7 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(set_stdio)] +#![feature(rustc_stack_internals)] extern crate arena; extern crate getopts; @@ -1461,16 +1462,50 @@ pub fn in_rustc_thread(f: F) -> Result> // Temporarily have stack size set to 16MB to deal with nom-using crates failing const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB - let mut cfg = thread::Builder::new().name("rustc".to_string()); + #[cfg(unix)] + let spawn_thread = unsafe { + // Fetch the current resource limits + let mut rlim = libc::rlimit { + rlim_cur: 0, + rlim_max: 0, + }; + if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 { + let err = io::Error::last_os_error(); + error!("in_rustc_thread: error calling getrlimit: {}", err); + true + } else if rlim.rlim_max < STACK_SIZE as libc::rlim_t { + true + } else { + rlim.rlim_cur = STACK_SIZE as libc::rlim_t; + if libc::setrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 { + let err = io::Error::last_os_error(); + error!("in_rustc_thread: error calling setrlimit: {}", err); + true + } else { + std::thread::update_stack_guard(); + false + } + } + }; - // FIXME: Hacks on hacks. If the env is trying to override the stack size - // then *don't* set it explicitly. - if env::var_os("RUST_MIN_STACK").is_none() { - cfg = cfg.stack_size(STACK_SIZE); - } + #[cfg(not(unix))] + let spawn_thread = true; + + // The or condition is added from backward compatibility. + if spawn_thread || env::var_os("RUST_MIN_STACK").is_some() { + let mut cfg = thread::Builder::new().name("rustc".to_string()); + + // FIXME: Hacks on hacks. If the env is trying to override the stack size + // then *don't* set it explicitly. + if env::var_os("RUST_MIN_STACK").is_none() { + cfg = cfg.stack_size(STACK_SIZE); + } - let thread = cfg.spawn(f); - thread.unwrap().join() + let thread = cfg.spawn(f); + thread.unwrap().join() + } else { + Ok(f()) + } } /// Get a list of extra command-line flags provided by the user, as strings. diff --git a/src/libstd/sys_common/thread_info.rs b/src/libstd/sys_common/thread_info.rs index 6a2b6742367..d75cbded734 100644 --- a/src/libstd/sys_common/thread_info.rs +++ b/src/libstd/sys_common/thread_info.rs @@ -50,3 +50,7 @@ pub fn set(stack_guard: Option, thread: Thread) { thread, })); } + +pub fn reset_guard(stack_guard: Option) { + THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard); +} diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 71aee673cfe..b686ddc205e 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -208,6 +208,14 @@ pub use self::local::{LocalKey, AccessError}; #[unstable(feature = "libstd_thread_internals", issue = "0")] #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; +/// Function used for resetting the main stack guard address after setrlimit(). +/// This is POSIX specific and unlikely to be directly stabilized. +#[unstable(feature = "rustc_stack_internals", issue = "0")] +pub unsafe fn update_stack_guard() { + let main_guard = imp::guard::init(); + thread_info::reset_guard(main_guard); +} + //////////////////////////////////////////////////////////////////////////////// // Builder //////////////////////////////////////////////////////////////////////////////// -- cgit 1.4.1-3-g733a5 From a23f685296b2edd59acc998411340184b958ec82 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 18 Mar 2018 16:58:38 +0100 Subject: num::NonZero* types now have their own tracking issue: #49137 Fixes #27730 --- src/libcore/nonzero.rs | 7 +------ src/libcore/num/mod.rs | 4 ++-- src/libstd/num.rs | 4 ++-- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 59aaef9d66a..19836d98844 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -9,9 +9,7 @@ // except according to those terms. //! Exposes the NonZero lang item which provides optimization hints. -#![unstable(feature = "nonzero", - reason = "deprecated", - issue = "27730")] +#![unstable(feature = "nonzero", reason = "deprecated", issue = "49137")] #![rustc_deprecated(reason = "use `std::ptr::NonNull` or `std::num::NonZero*` instead", since = "1.26.0")] #![allow(deprecated)] @@ -70,9 +68,6 @@ pub struct NonZero(pub(crate) T); impl NonZero { /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". - #[unstable(feature = "nonzero", - reason = "needs an RFC to flesh out the design", - issue = "27730")] #[inline] pub const unsafe fn new_unchecked(inner: T) -> Self { NonZero(inner) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 84f6ab9b764..2ffcb9e95e2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -92,7 +92,7 @@ macro_rules! nonzero_integers { } nonzero_integers! { - #[unstable(feature = "nonzero", issue = "27730")] + #[unstable(feature = "nonzero", issue = "49137")] NonZeroU8(u8); NonZeroI8(i8); NonZeroU16(u16); NonZeroI16(i16); NonZeroU32(u32); NonZeroI32(i32); @@ -103,7 +103,7 @@ nonzero_integers! { nonzero_integers! { // Change this to `#[unstable(feature = "i128", issue = "35118")]` // if other NonZero* integer types are stabilizied before 128-bit integers - #[unstable(feature = "nonzero", issue = "27730")] + #[unstable(feature = "nonzero", issue = "49137")] NonZeroU128(u128); NonZeroI128(i128); } diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 5e0406ca220..0c618370ac2 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,7 +21,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; -#[unstable(feature = "nonzero", issue = "27730")] +#[unstable(feature = "nonzero", issue = "49137")] pub use core::num::{ NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroUsize, NonZeroIsize, @@ -29,7 +29,7 @@ pub use core::num::{ // Change this to `#[unstable(feature = "i128", issue = "35118")]` // if other NonZero* integer types are stabilizied before 128-bit integers -#[unstable(feature = "nonzero", issue = "27730")] +#[unstable(feature = "nonzero", issue = "49137")] pub use core::num::{NonZeroU128, NonZeroI128}; #[cfg(test)] use fmt; -- cgit 1.4.1-3-g733a5 From 16da5d4bb2d65a4d533d1da2a4e0d288d3a474c5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 18 Mar 2018 09:18:18 -0700 Subject: Add BufReader::buffer This subsumes the need for an explicit is_empty function, and provides access to the buffered data itself which has been requested from time to time. --- src/libstd/io/buffered.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 9250c1c437b..ccaa19acc83 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -168,8 +168,36 @@ impl BufReader { /// # } /// ``` #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")] + #[rustc_deprecated(since = "1.26.0", reason = "use .buffer().is_empty() instead")] pub fn is_empty(&self) -> bool { - self.pos == self.cap + self.buffer().is_empty() + } + + /// Returns a reference to the internally buffered data. + /// + /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty. + /// + /// # Examples + /// + /// ``` + /// # #![feature(bufreader_buffer)] + /// use std::io::{BufReader, BufRead}; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// assert!(reader.buffer().is_empty()); + /// + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.buffer().is_empty()); + /// } + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "bufreader_buffer", issue = "45323")] + pub fn buffer(&self) -> &[u8] { + &self.buf[self.pos..self.cap] } /// Unwraps this `BufReader`, returning the underlying reader. -- cgit 1.4.1-3-g733a5 From a185b56b7caca17c7aa9d6f702fe1b2209c82e4e Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 18 Mar 2018 23:02:06 +0900 Subject: Address review comments --- src/librustc_driver/lib.rs | 8 +++++--- src/libstd/rt.rs | 15 +++++++++++++++ src/libstd/sys/unix/thread.rs | 20 +++++++++++++++++++- src/libstd/thread/mod.rs | 8 -------- 4 files changed, 39 insertions(+), 12 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 76179723941..e39a2c2f5dc 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1476,13 +1476,15 @@ pub fn in_rustc_thread(f: F) -> Result> } else if rlim.rlim_max < STACK_SIZE as libc::rlim_t { true } else { + std::rt::deinit_stack_guard(); rlim.rlim_cur = STACK_SIZE as libc::rlim_t; if libc::setrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 { let err = io::Error::last_os_error(); - error!("in_rustc_thread: error calling setrlimit: {}", err); - true + // We have already deinited the stack. Further corruption is + // not allowed. + panic!("in_rustc_thread: error calling setrlimit: {}", err); } else { - std::thread::update_stack_guard(); + std::rt::update_stack_guard(); false } } diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index e1392762a59..8f945470b7e 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -73,3 +73,18 @@ fn lang_start { lang_start_internal(&move || main().report(), argc, argv) } + +/// Function used for reverting changes to the main stack before setrlimit(). +/// This is POSIX (non-Linux) specific and unlikely to be directly stabilized. +#[unstable(feature = "rustc_stack_internals", issue = "0")] +pub unsafe fn deinit_stack_guard() { + ::sys::thread::guard::deinit(); +} + +/// Function used for resetting the main stack guard address after setrlimit(). +/// This is POSIX specific and unlikely to be directly stabilized. +#[unstable(feature = "rustc_stack_internals", issue = "0")] +pub unsafe fn update_stack_guard() { + let main_guard = ::sys::thread::guard::init(); + ::sys_common::thread_info::reset_guard(main_guard); +} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 72cdb9440b8..d94e11a5207 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -222,7 +222,7 @@ pub mod guard { #[cfg_attr(test, allow(dead_code))] pub mod guard { use libc; - use libc::mmap; + use libc::{mmap, munmap}; use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; use ops::Range; use sys::os; @@ -336,6 +336,24 @@ pub mod guard { } } + pub unsafe fn deinit() { + if !cfg!(target_os = "linux") { + if let Some(mut stackaddr) = get_stack_start() { + // Ensure address is aligned. Same as above. + let remainder = (stackaddr as usize) % PAGE_SIZE; + if remainder != 0 { + stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder) + as *mut libc::c_void; + } + + // Undo the guard page mapping. + if munmap(stackaddr, PAGE_SIZE) != 0 { + panic!("unable to deallocate the guard page"); + } + } + } + } + #[cfg(any(target_os = "macos", target_os = "bitrig", target_os = "openbsd", diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index b686ddc205e..71aee673cfe 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -208,14 +208,6 @@ pub use self::local::{LocalKey, AccessError}; #[unstable(feature = "libstd_thread_internals", issue = "0")] #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; -/// Function used for resetting the main stack guard address after setrlimit(). -/// This is POSIX specific and unlikely to be directly stabilized. -#[unstable(feature = "rustc_stack_internals", issue = "0")] -pub unsafe fn update_stack_guard() { - let main_guard = imp::guard::init(); - thread_info::reset_guard(main_guard); -} - //////////////////////////////////////////////////////////////////////////////// // Builder //////////////////////////////////////////////////////////////////////////////// -- cgit 1.4.1-3-g733a5 From 97b3bf99f667736c3220a91b72a587eafe4cda49 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Mon, 19 Mar 2018 01:31:04 -0500 Subject: Stabilize termination_trait This stabilizes `main` with non-() return types; see #48453. --- src/librustc_typeck/check/mod.rs | 35 ++++++++++------------ src/librustc_typeck/lib.rs | 3 +- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 5 ++-- .../compile-fail/feature-gate-termination_trait.rs | 13 -------- .../termination-trait-main-i32.rs | 14 +++++++++ .../termination-trait-main-wrong-type.rs | 1 - .../termination-trait-not-satisfied.rs | 2 -- .../termination-trait-for-never.rs | 2 -- .../termination-trait-for-result-box-error_err.rs | 2 -- .../termination-trait-for-empty.rs | 2 -- .../termination-trait-for-exitcode.rs | 1 - .../termination-trait-for-result-box-error_ok.rs | 2 -- .../termination-trait-for-result.rs | 2 -- 14 files changed, 34 insertions(+), 52 deletions(-) delete mode 100644 src/test/compile-fail/feature-gate-termination_trait.rs create mode 100644 src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs (limited to 'src/libstd') diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4a685cfddb7..42bf516a0af 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1106,25 +1106,22 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } fcx.demand_suptype(span, ret_ty, actual_return_ty); - if fcx.tcx.features().termination_trait { - // If the termination trait language item is activated, check that the main return type - // implements the termination trait. - if let Some(term_id) = fcx.tcx.lang_items().termination() { - if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() { - if id == fn_id { - match fcx.sess().entry_type.get() { - Some(config::EntryMain) => { - let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty))); - let trait_ref = ty::TraitRef::new(term_id, substs); - let cause = traits::ObligationCause::new( - span, fn_id, ObligationCauseCode::MainFunctionType); - - inherited.register_predicate( - traits::Obligation::new( - cause, param_env, trait_ref.to_predicate())); - }, - _ => {}, - } + // Check that the main return type implements the termination trait. + if let Some(term_id) = fcx.tcx.lang_items().termination() { + if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() { + if id == fn_id { + match fcx.sess().entry_type.get() { + Some(config::EntryMain) => { + let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty))); + let trait_ref = ty::TraitRef::new(term_id, substs); + let cause = traits::ObligationCause::new( + span, fn_id, ObligationCauseCode::MainFunctionType); + + inherited.register_predicate( + traits::Obligation::new( + cause, param_env, trait_ref.to_predicate())); + }, + _ => {}, } } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 964c0021133..80890140442 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -208,8 +208,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let actual = tcx.fn_sig(main_def_id); - let expected_return_type = if tcx.lang_items().termination().is_some() - && tcx.features().termination_trait { + let expected_return_type = if tcx.lang_items().termination().is_some() { // we take the return type of the given main function, the real check is done // in `check_fn` actual.output().skip_binder() diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 70a1f82c9a1..33da0e57886 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -308,7 +308,6 @@ #![feature(str_char)] #![feature(str_internals)] #![feature(str_utf16)] -#![feature(termination_trait)] #![feature(test, rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] @@ -325,6 +324,7 @@ #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] #![cfg_attr(stage0, feature(never_type))] +#![cfg_attr(stage0, feature(termination_trait))] #![default_lib_allocator] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0950965233f..781071b7f7f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -429,9 +429,6 @@ declare_features! ( // `foo.rs` as an alternative to `foo/mod.rs` (active, non_modrs_mods, "1.24.0", Some(44660), None), - // Termination trait in main (RFC 1937) - (active, termination_trait, "1.24.0", Some(43301), None), - // Termination trait in tests (RFC 1937) (active, termination_trait_test, "1.24.0", Some(48854), None), @@ -558,6 +555,8 @@ declare_features! ( (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), // allow `..=` in patterns (RFC 1192) (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + // Termination trait in main (RFC 1937) + (accepted, termination_trait, "1.26.0", Some(43301), None), ); // If you change this, please modify src/doc/unstable-book as well. You must diff --git a/src/test/compile-fail/feature-gate-termination_trait.rs b/src/test/compile-fail/feature-gate-termination_trait.rs deleted file mode 100644 index 5a56445b64e..00000000000 --- a/src/test/compile-fail/feature-gate-termination_trait.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() -> i32 { //~ ERROR main function has wrong type [E0580] - 0 -} diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs new file mode 100644 index 00000000000..ff2b32f3fd9 --- /dev/null +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() -> i32 { +//~^ ERROR the trait bound `i32: std::process::Termination` is not satisfied [E0277] + 0 +} diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs index 93e2561adf7..ea39ba92f41 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-wrong-type.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] fn main() -> char { //~^ ERROR: the trait bound `char: std::process::Termination` is not satisfied diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index e87e0ceebf1..bab02fc5597 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - struct ReturnType {} fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs index c1dd44a9176..863de85af88 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-never.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - // error-pattern:oh, dear fn main() -> ! { diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs index 8ce27c0a062..0c6cb4de956 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-result-box-error_err.rs @@ -11,8 +11,6 @@ // must-compile-successfully // failure-status: 1 -#![feature(termination_trait)] - use std::io::{Error, ErrorKind}; fn main() -> Result<(), Box> { diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs index 5e534da0128..046d27a9f0f 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-empty.rs @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - fn main() {} diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs index 80fa4d17b61..4aa7d8c3a77 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-exitcode.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] #![feature(process_exitcode_placeholder)] use std::process::ExitCode; diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs index 269ac451cf4..33686ed0b8f 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result-box-error_ok.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - use std::io::Error; fn main() -> Result<(), Box> { diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs index 751db0fb500..1c87e31e763 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-result.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(termination_trait)] - use std::io::Error; fn main() -> Result<(), Error> { -- cgit 1.4.1-3-g733a5 From 6212904dd800864ca20ede8690fc827a1169fa26 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 19 Mar 2018 15:40:09 -0700 Subject: Don't use posix_spawn() if PATH was modified in the environment. The expected behavior is that the environment's PATH should be used to find the process. posix_spawn() could be used if we iterated PATH to search for the binary to execute. For now just skip posix_spawn() if PATH is modified. --- src/libstd/sys/unix/process/process_common.rs | 3 +++ src/libstd/sys/unix/process/process_unix.rs | 1 + src/libstd/sys_common/process.rs | 12 ++++++++++++ 3 files changed, 16 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index d0486f06a14..48255489dd9 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -184,6 +184,9 @@ impl Command { let maybe_env = self.env.capture_if_changed(); maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) } + pub fn env_saw_path(&self) -> bool { + self.env.have_changed_path() + } pub fn setup_io(&self, default: Stdio, needs_stdin: bool) -> io::Result<(StdioPipes, ChildPipes)> { diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 29e33ee822e..9d6d607e3f3 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -256,6 +256,7 @@ impl Command { if self.get_cwd().is_some() || self.get_gid().is_some() || self.get_uid().is_some() || + self.env_saw_path() || self.get_closures().len() != 0 { return Ok(None) } diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index fd1a5fdb410..775491d762c 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -47,6 +47,7 @@ impl EnvKey for DefaultEnvKey {} #[derive(Clone, Debug)] pub struct CommandEnv { clear: bool, + saw_path: bool, vars: BTreeMap> } @@ -54,6 +55,7 @@ impl Default for CommandEnv { fn default() -> Self { CommandEnv { clear: false, + saw_path: false, vars: Default::default() } } @@ -108,9 +110,11 @@ impl CommandEnv { // The following functions build up changes pub fn set(&mut self, key: &OsStr, value: &OsStr) { + self.maybe_saw_path(&key); self.vars.insert(key.to_owned().into(), Some(value.to_owned())); } pub fn remove(&mut self, key: &OsStr) { + self.maybe_saw_path(&key); if self.clear { self.vars.remove(key); } else { @@ -121,4 +125,12 @@ impl CommandEnv { self.clear = true; self.vars.clear(); } + pub fn have_changed_path(&self) -> bool { + self.saw_path || self.clear + } + fn maybe_saw_path(&mut self, key: &OsStr) { + if !self.saw_path && key.to_os_string() == OsString::from("PATH") { + self.saw_path = true; + } + } } -- cgit 1.4.1-3-g733a5 From 8e0faf79c0859f22d4e11268f272247a6ef73709 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Mon, 19 Mar 2018 16:15:26 -0700 Subject: Simplify PATH key comparison --- src/libstd/sys_common/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index 775491d762c..d0c5951bd6c 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -129,7 +129,7 @@ impl CommandEnv { self.saw_path || self.clear } fn maybe_saw_path(&mut self, key: &OsStr) { - if !self.saw_path && key.to_os_string() == OsString::from("PATH") { + if !self.saw_path && key == "PATH" { self.saw_path = true; } } -- cgit 1.4.1-3-g733a5 From 1af952cc490b62a1f43f48c9fd809cf99aff2630 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Tue, 20 Mar 2018 07:31:22 -0400 Subject: Remove StdioRaw doc additions, add backticks --- src/libstd/io/stdio.rs | 9 --------- src/libstd/net/addr.rs | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 9a4cde7e162..1f73054e3be 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -30,27 +30,18 @@ thread_local! { /// /// This handle is not synchronized or buffered in any fashion. Constructed via /// the `std::io::stdio::stdin_raw` function. -/// -/// The size of a StdinRaw struct may vary depending on the target operating -/// system. struct StdinRaw(stdio::Stdin); /// A handle to a raw instance of the standard output stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via /// the `std::io::stdio::stdout_raw` function. -/// -/// The size of a StdoutRaw struct may vary depending on the target operating -/// system. struct StdoutRaw(stdio::Stdout); /// A handle to a raw instance of the standard output stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via /// the `std::io::stdio::stderr_raw` function. -/// -/// The size of a StderrRaw struct may vary depending on the target operating -/// system. struct StderrRaw(stdio::Stderr); /// Constructs a new raw handle to the standard input of this process. diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index f985c1f2bc8..57efc3095fc 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -28,7 +28,7 @@ use slice; /// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and /// [`SocketAddrV6`]'s respective documentation for more details. /// -/// The size of a SocketAddr instance may vary depending on the target operating +/// The size of a `SocketAddr` instance may vary depending on the target operating /// system. /// /// [IP address]: ../../std/net/enum.IpAddr.html -- cgit 1.4.1-3-g733a5 From 2928c7a8a253b655132ac9f2beb4ca74540f0e14 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Tue, 20 Mar 2018 21:22:45 +0900 Subject: Refactor the stack addr aligning code into a function --- src/libstd/sys/unix/thread.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index d94e11a5207..4364089a181 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -284,10 +284,10 @@ pub mod guard { ret } - pub unsafe fn init() -> Option { - PAGE_SIZE = os::page_size(); - - let mut stackaddr = get_stack_start()?; + // Precondition: PAGE_SIZE is initialized. + unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> { + assert!(PAGE_SIZE != 0); + let stackaddr = get_stack_start()?; // Ensure stackaddr is page aligned! A parent process might // have reset RLIMIT_STACK to be non-page aligned. The @@ -296,10 +296,17 @@ pub mod guard { // page-aligned, calculate the fix such that stackaddr < // new_page_aligned_stackaddr < stackaddr + stacksize let remainder = (stackaddr as usize) % PAGE_SIZE; - if remainder != 0 { - stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder) - as *mut libc::c_void; - } + Some(if remainder == 0 { + stackaddr + } else { + ((stackaddr as usize) + PAGE_SIZE - remainder) as *mut libc::c_void + }) + } + + pub unsafe fn init() -> Option { + PAGE_SIZE = os::page_size(); + + let stackaddr = get_stack_start_aligned()?; if cfg!(target_os = "linux") { // Linux doesn't allocate the whole stack right away, and @@ -338,14 +345,7 @@ pub mod guard { pub unsafe fn deinit() { if !cfg!(target_os = "linux") { - if let Some(mut stackaddr) = get_stack_start() { - // Ensure address is aligned. Same as above. - let remainder = (stackaddr as usize) % PAGE_SIZE; - if remainder != 0 { - stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder) - as *mut libc::c_void; - } - + if let Some(stackaddr) = get_stack_start_aligned() { // Undo the guard page mapping. if munmap(stackaddr, PAGE_SIZE) != 0 { panic!("unable to deallocate the guard page"); -- cgit 1.4.1-3-g733a5 From 94bdeb64f96b266d990ba7b76cd78a1e2ed1977f Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Tue, 20 Mar 2018 23:01:42 -0500 Subject: termination_trait: Add () example to error message --- src/libstd/process.rs | 2 +- .../rfc-1937-termination-trait/termination-trait-main-i32.rs | 2 +- .../rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d5ac2d19e83..a6aa3502f26 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1443,7 +1443,7 @@ pub fn id() -> u32 { #[cfg_attr(not(test), lang = "termination")] #[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] + "`main` can only return types like `()` that implement {Termination}, not `{Self}`"] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index 67ee39d10d9..ffff33da581 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:`main` can only return types that implement std::process::Termination, not `i32` +// error-pattern:`main` can only return types like `()` that implement std::process::Termination, no fn main() -> i32 { 0 } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index d09aac3ac2f..24371c27742 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `char: std::process::Termination` is not satisfied --> $DIR/termination-trait-main-wrong-type.rs:11:14 | LL | fn main() -> char { //~ ERROR - | ^^^^ `main` can only return types that implement std::process::Termination, not `char` + | ^^^^ `main` can only return types like `()` that implement std::process::Termination, not `char` | = help: the trait `std::process::Termination` is not implemented for `char` -- cgit 1.4.1-3-g733a5 From afff64e7a4c88b39402c95f1368c880b17cdf793 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 21 Mar 2018 07:55:09 +0100 Subject: document format_args! further wrt. Debug & Display" --- src/libstd/macros.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 000f9713615..47609f17221 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -335,6 +335,18 @@ pub mod builtin { /// proxied through this one. `format_args!`, unlike its derived macros, avoids /// heap allocations. /// + /// You can use the [`fmt::Arguments`] value that `format_args!` returns + /// in `Debug` and `Display` contexts as seen below. The example also shows + /// that `Debug` and `Display` format to the same thing: the interpolated + /// format string in `format_args!`. + /// + /// ```rust + /// let display = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); + /// let debug = format!("{}", format_args!("{} foo {:?}", 1, 2)); + /// assert_eq!("1 foo 2", display); + /// assert_eq!(display, debug); + /// ``` + /// /// For more information, see the documentation in [`std::fmt`]. /// /// [`Display`]: ../std/fmt/trait.Display.html -- cgit 1.4.1-3-g733a5 From c09b9f937250db0f51b705a3110f8cffdad083bb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 17 Mar 2018 12:15:24 +0100 Subject: Deprecate the AsciiExt trait in favor of inherent methods The trait and some of its methods are stable and will remain. Some of the newer methods are unstable and can be removed later. Fixes https://github.com/rust-lang/rust/issues/39658 --- src/libcore/tests/ascii.rs | 3 --- src/libstd/ascii.rs | 17 +++++++++++++++++ src/libstd/sys/windows/process.rs | 1 - src/libstd/sys_common/wtf8.rs | 17 +++++++---------- src/test/run-pass/issue-10683.rs | 2 -- 5 files changed, 24 insertions(+), 16 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs index 4d43067ad2c..950222dbcfa 100644 --- a/src/libcore/tests/ascii.rs +++ b/src/libcore/tests/ascii.rs @@ -9,7 +9,6 @@ // except according to those terms. use core::char::from_u32; -use std::ascii::AsciiExt; #[test] fn test_is_ascii() { @@ -143,8 +142,6 @@ macro_rules! assert_all { stringify!($what), b); } } - assert!($str.$what()); - assert!($str.as_bytes().$what()); )+ }}; ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 0837ff91c14..6472edb0aa7 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -52,6 +52,7 @@ pub use core::ascii::{EscapeDefault, escape_default}; /// /// [combining character]: https://en.wikipedia.org/wiki/Combining_character #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] pub trait AsciiExt { /// Container type for copied ASCII characters. #[stable(feature = "rust1", since = "1.0.0")] @@ -84,6 +85,7 @@ pub trait AsciiExt { /// [`make_ascii_uppercase`]: #tymethod.make_ascii_uppercase /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] fn to_ascii_uppercase(&self) -> Self::Owned; /// Makes a copy of the value in its ASCII lower case equivalent. @@ -104,6 +106,7 @@ pub trait AsciiExt { /// [`make_ascii_lowercase`]: #tymethod.make_ascii_lowercase /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] fn to_ascii_lowercase(&self) -> Self::Owned; /// Checks that two values are an ASCII case-insensitive match. @@ -162,6 +165,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII uppercase character: @@ -174,6 +178,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII lowercase character: @@ -186,6 +191,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII alphanumeric character: @@ -199,6 +205,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII decimal digit: @@ -211,6 +218,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_digit(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII hexadecimal digit: @@ -224,6 +232,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII punctuation character: @@ -241,6 +250,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII graphic character: @@ -253,6 +263,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_graphic(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII whitespace character: @@ -282,6 +293,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII control character: @@ -294,6 +306,7 @@ pub trait AsciiExt { /// This method will be deprecated in favor of the identically-named /// inherent methods on `u8`, `char`, `[u8]` and `str`. #[unstable(feature = "ascii_ctype", issue = "39658")] + #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_control(&self) -> bool { unimplemented!(); } } @@ -354,6 +367,7 @@ macro_rules! delegating_ascii_ctype_methods { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for u8 { type Owned = u8; @@ -362,6 +376,7 @@ impl AsciiExt for u8 { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for char { type Owned = char; @@ -370,6 +385,7 @@ impl AsciiExt for char { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for [u8] { type Owned = Vec; @@ -427,6 +443,7 @@ impl AsciiExt for [u8] { } #[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] impl AsciiExt for str { type Owned = String; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index f1ab9c47609..afa8e3e1369 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,7 +10,6 @@ #![unstable(feature = "process_internals", issue = "0")] -use ascii::AsciiExt; use collections::BTreeMap; use env::split_paths; use env; diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 9fff8b91f96..78b2bb5fe6e 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -27,7 +27,6 @@ use core::str::next_code_point; -use ascii::*; use borrow::Cow; use char; use fmt; @@ -871,24 +870,22 @@ impl Hash for Wtf8 { } } -impl AsciiExt for Wtf8 { - type Owned = Wtf8Buf; - - fn is_ascii(&self) -> bool { +impl Wtf8 { + pub fn is_ascii(&self) -> bool { self.bytes.is_ascii() } - fn to_ascii_uppercase(&self) -> Wtf8Buf { + pub fn to_ascii_uppercase(&self) -> Wtf8Buf { Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() } } - fn to_ascii_lowercase(&self) -> Wtf8Buf { + pub fn to_ascii_lowercase(&self) -> Wtf8Buf { Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() } } - fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { + pub fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { self.bytes.eq_ignore_ascii_case(&other.bytes) } - fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } - fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } + pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } + pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } } #[cfg(test)] diff --git a/src/test/run-pass/issue-10683.rs b/src/test/run-pass/issue-10683.rs index eb2177202a2..d3ba477fa57 100644 --- a/src/test/run-pass/issue-10683.rs +++ b/src/test/run-pass/issue-10683.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -use std::ascii::AsciiExt; - static NAME: &'static str = "hello world"; fn main() { -- cgit 1.4.1-3-g733a5 From b6934c91b23517c4e17d8016b6c46ffd0703eded Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 21 Mar 2018 13:32:46 -0500 Subject: termination_trait: Put examples in error help, not label --- src/librustc/traits/error_reporting.rs | 23 +++++++++++++--------- src/libstd/process.rs | 2 +- .../termination-trait-main-i32.rs | 2 +- .../termination-trait-main-wrong-type.stderr | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7e5dc02798d..8572c407714 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -585,20 +585,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref.to_predicate(), post_message) })); + let explanation = match obligation.cause.code { + ObligationCauseCode::MainFunctionType => { + "consider using `()`, or a `Result`".to_owned() + } + _ => { + format!("{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty()) + } + }; + if let Some(ref s) = label { // If it has a custom "#[rustc_on_unimplemented]" // error message, let's display it as the label! err.span_label(span, s.as_str()); - err.help(&format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); + err.help(&explanation); } else { - err.span_label(span, - &*format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); + err.span_label(span, explanation); } if let Some(ref s) = note { // If it has a custom "#[rustc_on_unimplemented]" note, let's display it diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a6aa3502f26..d5ac2d19e83 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1443,7 +1443,7 @@ pub fn id() -> u32 { #[cfg_attr(not(test), lang = "termination")] #[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented = - "`main` can only return types like `()` that implement {Termination}, not `{Self}`"] + "`main` can only return types that implement {Termination}, not `{Self}`"] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index 053d6bbf93a..2cf9fdcfb4d 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -10,6 +10,6 @@ fn main() -> i32 { //~^ ERROR `i32: std::process::Termination` is not satisfied -//~| NOTE `main` can only return types like `()` that implement std::process::Termination, not `i32` +//~| NOTE `main` can only return types that implement std::process::Termination, not `i32` 0 } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index 24371c27742..211247757cb 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -2,9 +2,9 @@ error[E0277]: the trait bound `char: std::process::Termination` is not satisfied --> $DIR/termination-trait-main-wrong-type.rs:11:14 | LL | fn main() -> char { //~ ERROR - | ^^^^ `main` can only return types like `()` that implement std::process::Termination, not `char` + | ^^^^ `main` can only return types that implement std::process::Termination, not `char` | - = help: the trait `std::process::Termination` is not implemented for `char` + = help: consider using `()`, or a `Result` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From c116b0e8296dc4198408a708fae53f47fc1e51c6 Mon Sep 17 00:00:00 2001 From: Maxwell Borden Date: Wed, 21 Mar 2018 18:11:57 -0700 Subject: Fixed clockwise/counter-clockwise in atan2 documentation in f32 and f64 and included that it returns radians --- src/libstd/f32.rs | 9 +++++---- src/libstd/f64.rs | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index a760922115a..ceb019bc95b 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -780,7 +780,7 @@ impl f32 { unsafe { cmath::atanf(self) } } - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// /// * `x = 0`, `y = 0`: `0` /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` @@ -791,12 +791,13 @@ impl f32 { /// use std::f32; /// /// let pi = f32::consts::PI; - /// // All angles from horizontal right (+x) - /// // 45 deg counter-clockwise + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) /// let x1 = 3.0f32; /// let y1 = -3.0f32; /// - /// // 135 deg clockwise + /// // 3pi/4 radians (135 deg counter-clockwise) /// let x2 = -3.0f32; /// let y2 = 3.0f32; /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 6f34f176a97..97adf108b73 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -716,7 +716,7 @@ impl f64 { unsafe { cmath::atan(self) } } - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians. /// /// * `x = 0`, `y = 0`: `0` /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` @@ -727,12 +727,13 @@ impl f64 { /// use std::f64; /// /// let pi = f64::consts::PI; - /// // All angles from horizontal right (+x) - /// // 45 deg counter-clockwise + /// // Positive angles measured counter-clockwise + /// // from positive x axis + /// // -pi/4 radians (45 deg clockwise) /// let x1 = 3.0_f64; /// let y1 = -3.0_f64; /// - /// // 135 deg clockwise + /// // 3pi/4 radians (135 deg counter-clockwise) /// let x2 = -3.0_f64; /// let y2 = 3.0_f64; /// -- cgit 1.4.1-3-g733a5 From 2b13d95da02d318c12814261dd36edd91ae6879e Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 21 Mar 2018 23:28:48 -0500 Subject: termination_trait: Make error message more helpful --- src/librustc/traits/error_reporting.rs | 16 +++++++--------- src/libstd/process.rs | 5 +++-- .../termination-trait-main-i32.rs | 5 +++-- .../termination-trait-not-satisfied.rs | 2 +- .../termination-trait-main-wrong-type.stderr | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8572c407714..47e6b0fecea 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -585,17 +585,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref.to_predicate(), post_message) })); - let explanation = match obligation.cause.code { - ObligationCauseCode::MainFunctionType => { + let explanation = + if obligation.cause.code == ObligationCauseCode::MainFunctionType { "consider using `()`, or a `Result`".to_owned() - } - _ => { + } else { format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty()) - } - }; + pre_message, + trait_ref, + trait_ref.self_ty()) + }; if let Some(ref s) = label { // If it has a custom "#[rustc_on_unimplemented]" diff --git a/src/libstd/process.rs b/src/libstd/process.rs index d5ac2d19e83..c877bf6aa35 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1442,8 +1442,9 @@ pub fn id() -> u32 { /// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned. #[cfg_attr(not(test), lang = "termination")] #[unstable(feature = "termination_trait_lib", issue = "43301")] -#[rustc_on_unimplemented = - "`main` can only return types that implement {Termination}, not `{Self}`"] +#[rustc_on_unimplemented( + message="`main` has invalid return type `{Self}`", + label="`main` can only return types that implement {Termination}")] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs index 2cf9fdcfb4d..0e6ddf7c92f 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -9,7 +9,8 @@ // except according to those terms. fn main() -> i32 { -//~^ ERROR `i32: std::process::Termination` is not satisfied -//~| NOTE `main` can only return types that implement std::process::Termination, not `i32` +//~^ ERROR `main` has invalid return type `i32` +//~| NOTE `main` can only return types that implement std::process::Termination +//~| HELP consider using `()`, or a `Result` 0 } diff --git a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs index bab02fc5597..b5f5472b492 100644 --- a/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs +++ b/src/test/compile-fail/rfc-1937-termination-trait/termination-trait-not-satisfied.rs @@ -10,6 +10,6 @@ struct ReturnType {} -fn main() -> ReturnType { //~ ERROR `ReturnType: std::process::Termination` is not satisfied +fn main() -> ReturnType { //~ ERROR `main` has invalid return type `ReturnType` ReturnType {} } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index 211247757cb..5109d9275c5 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `char: std::process::Termination` is not satisfied +error[E0277]: `main` has invalid return type `char` --> $DIR/termination-trait-main-wrong-type.rs:11:14 | LL | fn main() -> char { //~ ERROR - | ^^^^ `main` can only return types that implement std::process::Termination, not `char` + | ^^^^ `main` can only return types that implement std::process::Termination | = help: consider using `()`, or a `Result` -- cgit 1.4.1-3-g733a5 From 70559c54ce2a493a15f447436e281e16fc55b291 Mon Sep 17 00:00:00 2001 From: Bryan Drewery Date: Thu, 22 Mar 2018 09:49:20 -0700 Subject: Command::env_saw_path() may be unused on platforms not using posix_spawn() --- src/libstd/sys/unix/process/process_common.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 48255489dd9..b7f30600b8a 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -184,6 +184,7 @@ impl Command { let maybe_env = self.env.capture_if_changed(); maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) } + #[allow(dead_code)] pub fn env_saw_path(&self) -> bool { self.env.have_changed_path() } -- cgit 1.4.1-3-g733a5 From fdde09c70c102058feff4c9932044ae77d341d11 Mon Sep 17 00:00:00 2001 From: Daniel Kolsoi Date: Fri, 23 Mar 2018 17:01:34 -0400 Subject: Reduce scope of unsafe block in sun_path_offset --- src/libstd/sys/unix/ext/net.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index ad437658d14..ba80cbe47c8 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -51,13 +51,11 @@ use libc::MSG_NOSIGNAL; const MSG_NOSIGNAL: libc::c_int = 0x0; fn sun_path_offset() -> usize { - unsafe { - // Work with an actual instance of the type since using a null pointer is UB - let addr: libc::sockaddr_un = mem::uninitialized(); - let base = &addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base - } + // Work with an actual instance of the type since using a null pointer is UB + let addr: libc::sockaddr_un = unsafe { mem::uninitialized() }; + let base = &addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base } unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { -- cgit 1.4.1-3-g733a5 From 91279904345e2ecd3f52b17339183bbe3bd11203 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sat, 24 Mar 2018 13:47:36 +0900 Subject: Fix build on non-Unix platforms --- src/libstd/sys/cloudabi/thread.rs | 1 + src/libstd/sys/redox/thread.rs | 1 + src/libstd/sys/unix/thread.rs | 1 + src/libstd/sys/wasm/thread.rs | 1 + src/libstd/sys/windows/thread.rs | 1 + 5 files changed, 5 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index 78a3b82546e..a22d9053b69 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -118,6 +118,7 @@ pub mod guard { pub unsafe fn init() -> Option { None } + pub unsafe fn deinit() {} } fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index c4719a94c7e..f20350269b7 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -91,4 +91,5 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } + pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 4364089a181..b9ec0d4a403 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -209,6 +209,7 @@ pub mod guard { pub type Guard = Range; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } + pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 6a066509b49..7345843b975 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -46,4 +46,5 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } + pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 43abfbb1f64..4b3d1b586b5 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -96,4 +96,5 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } + pub unsafe fn deinit() {} } -- cgit 1.4.1-3-g733a5 From efd04423c3300d79d0430c78602545ddf5b7f415 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sat, 24 Mar 2018 23:41:34 -0400 Subject: Add backticks --- src/libstd/net/addr.rs | 4 ++-- src/libstd/net/ip.rs | 6 +++--- src/libstd/time.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 57efc3095fc..bc2c9f522d3 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -64,7 +64,7 @@ pub enum SocketAddr { /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// -/// The size of a SocketAddrV4 struct may vary depending on the target operating +/// The size of a `SocketAddrV4` struct may vary depending on the target operating /// system. /// /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 @@ -94,7 +94,7 @@ pub struct SocketAddrV4 { inner: c::sockaddr_in } /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// -/// The size of a SocketAddrV6 struct may vary depending on the target operating +/// The size of a `SocketAddrV6` struct may vary depending on the target operating /// system. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 67b9e7a2f9d..031fae6d59b 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -26,7 +26,7 @@ use sys_common::{AsInner, FromInner}; /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their /// respective documentation for more details. /// -/// The size of an IpAddr instance may vary depending on the target operating +/// The size of an `IpAddr` instance may vary depending on the target operating /// system. /// /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html @@ -64,7 +64,7 @@ pub enum IpAddr { /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// -/// The size of an Ipv4Addr struct may vary depending on the target operating +/// The size of an `Ipv4Addr` struct may vary depending on the target operating /// system. /// /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 @@ -99,7 +99,7 @@ pub struct Ipv4Addr { /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// -/// The size of an Ipv6Addr struct may vary depending on the target operating +/// The size of an `Ipv6Addr` struct may vary depending on the target operating /// system. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 4e08301fe05..7256ac43e27 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -49,7 +49,7 @@ pub use core::time::Duration; /// allows measuring the duration between two instants (or comparing two /// instants). /// -/// The size of an Instant struct may vary depending on the target operating +/// The size of an `Instant` struct may vary depending on the target operating /// system. /// /// Example: @@ -91,7 +91,7 @@ pub struct Instant(time::Instant); /// fixed point in time, a `SystemTime` can be converted to a human-readable time, /// or perhaps some other string representation. /// -/// The size of a SystemTime struct may vary depending on the target operating +/// The size of a `SystemTime` struct may vary depending on the target operating /// system. /// /// [`Instant`]: ../../std/time/struct.Instant.html -- cgit 1.4.1-3-g733a5 From f9661126ca1904d3712eb19d24a5880c6dc7b8ed Mon Sep 17 00:00:00 2001 From: Alexander Ronald Altman Date: Sun, 25 Mar 2018 00:15:50 -0500 Subject: Minor formatting consistency fix. --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index c877bf6aa35..92e9f48f7eb 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1444,7 +1444,7 @@ pub fn id() -> u32 { #[unstable(feature = "termination_trait_lib", issue = "43301")] #[rustc_on_unimplemented( message="`main` has invalid return type `{Self}`", - label="`main` can only return types that implement {Termination}")] + label="`main` can only return types that implement `{Termination}`")] pub trait Termination { /// Is called to get the representation of the value as status code. /// This status code is returned to the operating system. -- cgit 1.4.1-3-g733a5 From d39b02c2c9e8aa472ab47ccfb5de63bc616daf62 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 25 Mar 2018 16:08:03 +0900 Subject: Use a more conservative way to deinit stack guard --- src/libstd/sys/unix/thread.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index b9ec0d4a403..6064b55489e 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -223,8 +223,8 @@ pub mod guard { #[cfg_attr(test, allow(dead_code))] pub mod guard { use libc; - use libc::{mmap, munmap}; - use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; + use libc::mmap; + use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; use ops::Range; use sys::os; @@ -347,9 +347,19 @@ pub mod guard { pub unsafe fn deinit() { if !cfg!(target_os = "linux") { if let Some(stackaddr) = get_stack_start_aligned() { - // Undo the guard page mapping. - if munmap(stackaddr, PAGE_SIZE) != 0 { - panic!("unable to deallocate the guard page"); + // Remove the protection on the guard page. + // FIXME: we cannot unmap the page, because when we mmap() + // above it may be already mapped by the OS, which we can't + // detect from mmap()'s return value. If we unmap this page, + // it will lead to failure growing stack size on platforms like + // macOS. Instead, just restore the page to a writable state. + // This ain't Linux, so we probably don't need to care about + // execstack. + let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + + if result != stackaddr || result == MAP_FAILED { + panic!("unable to reset the guard page"); } } } -- cgit 1.4.1-3-g733a5 From fbec3ec5a78747ee458518e4be7cfe1b5eac9e3b Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Mon, 25 Dec 2017 00:00:04 +0000 Subject: Implement get_key_value for HashMap, BTreeMap --- src/liballoc/btree/map.rs | 27 +++++++++++++++++++++++++++ src/libstd/collections/hash/map.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'src/libstd') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index ed9c8c18f0d..cada190032a 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -576,6 +576,33 @@ impl BTreeMap { } } + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_get_key_value)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[unstable(feature = "map_get_key_value", issue = "49347")] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where K: Borrow, + Q: Ord + { + match search::search_tree(self.root.as_ref(), k) { + Found(handle) => Some(handle.into_kv()), + GoDown(_) => None, + } + } + /// Returns `true` if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but the ordering diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index b18b38ec302..f0bb781411f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1184,6 +1184,34 @@ impl HashMap self.search(k).map(|bucket| bucket.into_refs().1) } + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// #![feature(map_get_key_value)] + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[unstable(feature = "map_get_key_value", issue = "49347")] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where K: Borrow, + Q: Hash + Eq + { + self.search(k).map(|bucket| bucket.into_refs()) + } + /// Returns true if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but -- cgit 1.4.1-3-g733a5 From 7ce8191775b44d3773e28d647b5b17ec85508e16 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 16 Mar 2018 19:51:49 -0500 Subject: Stabilize i128_type --- src/liballoc/benches/lib.rs | 2 +- src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/libcore/num/mod.rs | 6 ++-- src/libcore/tests/lib.rs | 2 +- src/libproc_macro/lib.rs | 2 +- src/librustc/lib.rs | 2 +- src/librustc_apfloat/lib.rs | 2 +- src/librustc_apfloat/tests/ieee.rs | 2 +- src/librustc_const_eval/lib.rs | 2 +- src/librustc_const_math/lib.rs | 2 +- src/librustc_data_structures/lib.rs | 2 +- src/librustc_errors/lib.rs | 2 +- src/librustc_incremental/lib.rs | 2 +- src/librustc_lint/lib.rs | 2 +- src/librustc_metadata/lib.rs | 2 +- src/librustc_mir/lib.rs | 2 +- src/librustc_resolve/lib.rs | 11 -------- src/librustc_trans/lib.rs | 2 +- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/libserialize/lib.rs | 2 +- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 17 ++---------- src/libsyntax/lib.rs | 2 +- src/libsyntax_pos/lib.rs | 2 +- src/test/codegen/unchecked-float-casts.rs | 1 - src/test/mir-opt/lower_128bit_debug_test.rs | 1 - src/test/mir-opt/lower_128bit_test.rs | 1 - src/test/run-pass/float-int-invalid-const-cast.rs | 1 - src/test/run-pass/i128-ffi.rs | 2 -- src/test/run-pass/i128.rs | 2 +- src/test/run-pass/intrinsics-integer.rs | 2 +- src/test/run-pass/issue-38763.rs | 2 -- src/test/run-pass/issue-38987.rs | 1 - .../run-pass/next-power-of-two-overflow-debug.rs | 2 -- .../run-pass/next-power-of-two-overflow-ndebug.rs | 2 -- src/test/run-pass/saturating-float-casts.rs | 2 +- src/test/run-pass/u128-as-f32.rs | 2 +- src/test/run-pass/u128.rs | 2 +- src/test/ui/feature-gate-i128_type.rs | 18 ------------ src/test/ui/feature-gate-i128_type.stderr | 19 ------------- src/test/ui/feature-gate-i128_type2.rs | 8 +++--- src/test/ui/feature-gate-i128_type2.stderr | 32 ---------------------- src/test/ui/lint-ctypes.rs | 2 +- src/test/ui/lint/type-overflow.rs | 2 -- 46 files changed, 37 insertions(+), 147 deletions(-) delete mode 100644 src/test/ui/feature-gate-i128_type.rs delete mode 100644 src/test/ui/feature-gate-i128_type.stderr (limited to 'src/libstd') diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 2de0ffb4b26..09685d1bb40 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -10,7 +10,7 @@ #![deny(warnings)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rand)] #![feature(repr_simd)] #![feature(test)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f914b1a93a9..19d64d8fea9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,7 +97,7 @@ #![feature(from_ref)] #![feature(fundamental)] #![feature(generic_param_attrs)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9aebe2e4ee4..11fecde3951 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,7 +78,7 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 18e0aa453d8..9ff42a6d4ea 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1635,8 +1635,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128_type)] -#![feature(i128)] + 170141183460469231731687303715884105727, "#![feature(i128)] # fn main() { ", " # }" } @@ -3493,8 +3492,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128_type)] -#![feature(i128)] + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128)] # fn main() { ", " diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 1c71669abb1..0b70f692403 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,7 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index d6e679bad48..716a2cc6cbb 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -34,7 +34,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 1bb903c0627..061044cdf14 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -53,7 +53,7 @@ #![feature(from_ref)] #![feature(fs_read_write)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 565658804b0..2ee7bea8476 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -46,8 +46,8 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![feature(i128_type)] #![cfg_attr(stage0, feature(slice_patterns))] +#![cfg_attr(stage0, feature(i128_type))] #![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index ff46ee79c31..627d79724b2 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #[macro_use] extern crate rustc_apfloat; diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 2b0775e8695..2620448927d 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -23,7 +23,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(macro_lifetime_matcher)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(from_ref)] extern crate arena; diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 5555e727a95..a53055c7ce7 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -20,7 +20,7 @@ #![deny(warnings)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ff869072871..01f91e37db8 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,7 +26,7 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(specialization)] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 1152c9c574e..37ae64cef57 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -18,7 +18,7 @@ #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(stage0, feature(conservative_impl_trait))] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] extern crate atty; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 6adb950fe4e..5a33f566e90 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4639f7b2d28..d024adad9d0 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -27,7 +27,7 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 902dd87c574..4af5ec9ae08 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -16,7 +16,7 @@ #![feature(box_patterns)] #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(libc)] #![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 750839f8b00..a1f096b2a38 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -27,7 +27,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(decl_macro)] #![feature(dyn_trait)] #![feature(fs_read_write)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2cb2c76c632..01eda71e9b6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3117,17 +3117,6 @@ impl<'a> Resolver<'a> { self.primitive_type_table.primitive_types .contains_key(&path[0].node.name) => { let prim = self.primitive_type_table.primitive_types[&path[0].node.name]; - match prim { - TyUint(UintTy::U128) | TyInt(IntTy::I128) => { - if !self.session.features_untracked().i128_type { - emit_feature_err(&self.session.parse_sess, - "i128_type", span, GateIssue::Language, - "128-bit type is unstable"); - - } - } - _ => {} - } PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } PathResult::Module(module) => PathResolution::new(module.def().unwrap()), diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 38adc603628..d89d19db63e 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,7 +24,7 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(i128)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 9e4addd1ed1..99de124c6e1 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -21,7 +21,7 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![cfg_attr(stage0, feature(conservative_impl_trait))] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index e466ef39234..8b3d5af3edd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -86,7 +86,7 @@ This API is completely unstable and subject to change. #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate log; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2e354252c15..ee952523462 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -23,7 +23,7 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(core_intrinsics)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(specialization)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0b06c5d4d65..3cc5d7b81c3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -270,7 +270,7 @@ #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(i128)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1bb369b551d..4e3c77d5e46 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -303,9 +303,6 @@ declare_features! ( // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None, None), - // The `i128` type - (active, i128_type, "1.16.0", Some(35118), None), - // The `repr(i128)` annotation for enums (active, repr128, "1.16.0", Some(35118), None), @@ -564,6 +561,8 @@ declare_features! ( (accepted, universal_impl_trait, "1.26.0", Some(34511), None), // Allows `impl Trait` in function return types. (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + // The `i128` type + (accepted, i128_type, "1.26.0", Some(35118), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1641,18 +1640,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { e.span, "yield syntax is experimental"); } - ast::ExprKind::Lit(ref lit) => { - if let ast::LitKind::Int(_, ref ty) = lit.node { - match *ty { - ast::LitIntType::Signed(ast::IntTy::I128) | - ast::LitIntType::Unsigned(ast::UintTy::U128) => { - gate_feature_post!(&self, i128_type, e.span, - "128-bit integers are not stable"); - } - _ => {} - } - } - } ast::ExprKind::Catch(_) => { gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 74f1ee373ec..2218b396685 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -24,7 +24,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(match_default_bindings)] #![feature(non_exhaustive)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 5a7b7e9ceca..eb345200f41 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] -#![feature(i128_type)] +#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] diff --git a/src/test/codegen/unchecked-float-casts.rs b/src/test/codegen/unchecked-float-casts.rs index c2fc2966170..87ebaaeec32 100644 --- a/src/test/codegen/unchecked-float-casts.rs +++ b/src/test/codegen/unchecked-float-casts.rs @@ -14,7 +14,6 @@ // -Z saturating-float-casts is not enabled. #![crate_type = "lib"] -#![feature(i128_type)] // CHECK-LABEL: @f32_to_u32 #[no_mangle] diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 1752445a141..d7586b1aa4b 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 4058eaef9b0..341682debeb 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -15,7 +15,6 @@ // compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -#![feature(i128_type)] #![feature(const_fn)] static TEST_SIGNED: i128 = const_signed(-222); diff --git a/src/test/run-pass/float-int-invalid-const-cast.rs b/src/test/run-pass/float-int-invalid-const-cast.rs index d44f78922c7..f84432abbfa 100644 --- a/src/test/run-pass/float-int-invalid-const-cast.rs +++ b/src/test/run-pass/float-int-invalid-const-cast.rs @@ -10,7 +10,6 @@ // ignore-emscripten no i128 support -#![feature(i128_type)] #![deny(const_err)] use std::{f32, f64}; diff --git a/src/test/run-pass/i128-ffi.rs b/src/test/run-pass/i128-ffi.rs index d989210dd71..edf278cbf64 100644 --- a/src/test/run-pass/i128-ffi.rs +++ b/src/test/run-pass/i128-ffi.rs @@ -15,8 +15,6 @@ // ignore-windows // ignore-32bit -#![feature(i128_type)] - #[link(name = "rust_test_helpers", kind = "static")] extern "C" { fn identity(f: u128) -> u128; diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs index c3e43c92590..baf3b339984 100644 --- a/src/test/run-pass/i128.rs +++ b/src/test/run-pass/i128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index cdfad51e648..7a8ff1befc7 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -10,7 +10,7 @@ // ignore-emscripten no i128 support -#![feature(intrinsics, i128_type)] +#![feature(intrinsics)] mod rusti { extern "rust-intrinsic" { diff --git a/src/test/run-pass/issue-38763.rs b/src/test/run-pass/issue-38763.rs index 01cc8265a39..e038062ff9a 100644 --- a/src/test/run-pass/issue-38763.rs +++ b/src/test/run-pass/issue-38763.rs @@ -10,8 +10,6 @@ // ignore-emscripten -#![feature(i128_type)] - #[repr(C)] pub struct Foo(i128); diff --git a/src/test/run-pass/issue-38987.rs b/src/test/run-pass/issue-38987.rs index a513476d4a3..31a3b7233d8 100644 --- a/src/test/run-pass/issue-38987.rs +++ b/src/test/run-pass/issue-38987.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(i128_type)] fn main() { let _ = -0x8000_0000_0000_0000_0000_0000_0000_0000i128; diff --git a/src/test/run-pass/next-power-of-two-overflow-debug.rs b/src/test/run-pass/next-power-of-two-overflow-debug.rs index 599c6dfd31d..2135b3f8764 100644 --- a/src/test/run-pass/next-power-of-two-overflow-debug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-debug.rs @@ -12,8 +12,6 @@ // ignore-wasm32-bare compiled with panic=abort by default // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - use std::panic; fn main() { diff --git a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs index f2312b70be6..b05c1863d90 100644 --- a/src/test/run-pass/next-power-of-two-overflow-ndebug.rs +++ b/src/test/run-pass/next-power-of-two-overflow-ndebug.rs @@ -11,8 +11,6 @@ // compile-flags: -C debug_assertions=no // ignore-emscripten dies with an LLVM error -#![feature(i128_type)] - fn main() { for i in 129..256 { assert_eq!((i as u8).next_power_of_two(), 0); diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs index c8fa49c62a0..d1a0901bb3d 100644 --- a/src/test/run-pass/saturating-float-casts.rs +++ b/src/test/run-pass/saturating-float-casts.rs @@ -11,7 +11,7 @@ // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. // compile-flags: -Z saturating-float-casts -#![feature(test, i128, i128_type, stmt_expr_attributes)] +#![feature(test, i128, stmt_expr_attributes)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128-as-f32.rs b/src/test/run-pass/u128-as-f32.rs index 117e520155f..3531a961bef 100644 --- a/src/test/run-pass/u128-as-f32.rs +++ b/src/test/run-pass/u128-as-f32.rs @@ -10,7 +10,7 @@ // ignore-emscripten u128 not supported -#![feature(test, i128, i128_type)] +#![feature(test, i128)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs index ebd43a86033..d649b3b74d3 100644 --- a/src/test/run-pass/u128.rs +++ b/src/test/run-pass/u128.rs @@ -12,7 +12,7 @@ // compile-flags: -Z borrowck=compare -#![feature(i128_type, test)] +#![feature(test)] extern crate test; use test::black_box as b; diff --git a/src/test/ui/feature-gate-i128_type.rs b/src/test/ui/feature-gate-i128_type.rs deleted file mode 100644 index ddb49a3e5d9..00000000000 --- a/src/test/ui/feature-gate-i128_type.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn test2() { - 0i128; //~ ERROR 128-bit integers are not stable -} - -fn test2_2() { - 0u128; //~ ERROR 128-bit integers are not stable -} - diff --git a/src/test/ui/feature-gate-i128_type.stderr b/src/test/ui/feature-gate-i128_type.stderr deleted file mode 100644 index eb3b29f4f55..00000000000 --- a/src/test/ui/feature-gate-i128_type.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:12:5 - | -LL | 0i128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit integers are not stable (see issue #35118) - --> $DIR/feature-gate-i128_type.rs:16:5 - | -LL | 0u128; //~ ERROR 128-bit integers are not stable - | ^^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-i128_type2.rs b/src/test/ui/feature-gate-i128_type2.rs index 8a7d316ed83..cd65b9d9223 100644 --- a/src/test/ui/feature-gate-i128_type2.rs +++ b/src/test/ui/feature-gate-i128_type2.rs @@ -10,20 +10,20 @@ // gate-test-i128_type -fn test1() -> i128 { //~ ERROR 128-bit type is unstable +fn test1() -> i128 { 0 } -fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable +fn test1_2() -> u128 { 0 } fn test3() { - let x: i128 = 0; //~ ERROR 128-bit type is unstable + let x: i128 = 0; } fn test3_2() { - let x: u128 = 0; //~ ERROR 128-bit type is unstable + let x: u128 = 0; } #[repr(u128)] diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr index 23d4d6c98d9..fe4557899ac 100644 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ b/src/test/ui/feature-gate-i128_type2.stderr @@ -1,35 +1,3 @@ -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:13:15 - | -LL | fn test1() -> i128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:17:17 - | -LL | fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:22:12 - | -LL | let x: i128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - -error[E0658]: 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:26:12 - | -LL | let x: u128 = 0; //~ ERROR 128-bit type is unstable - | ^^^^ - | - = help: add #![feature(i128_type)] to the crate attributes to enable - error[E0658]: repr with 128-bit type is unstable (see issue #35118) --> $DIR/feature-gate-i128_type2.rs:30:1 | diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 77cb1ef0f51..85957831653 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -9,7 +9,7 @@ // except according to those terms. #![deny(improper_ctypes)] -#![feature(libc, i128_type, repr_transparent)] +#![feature(libc, repr_transparent)] extern crate libc; diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs index 495989587e5..30e6fb2883b 100644 --- a/src/test/ui/lint/type-overflow.rs +++ b/src/test/ui/lint/type-overflow.rs @@ -10,8 +10,6 @@ // must-compile-successfully -#![feature(i128_type)] - fn main() { let error = 255i8; //~WARNING literal out of range for i8 -- cgit 1.4.1-3-g733a5 From db7d9ea480e16c7135c997f56b44d3c0a657cc9d Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Fri, 16 Mar 2018 20:15:56 -0500 Subject: Stabilize i128 feature too --- src/doc/unstable-book/src/language-features/i128-type.md | 2 +- src/libcore/num/i128.rs | 4 ++-- src/libcore/num/mod.rs | 11 ++--------- src/librustc/lib.rs | 3 +-- src/librustc_const_math/lib.rs | 3 +-- src/librustc_data_structures/lib.rs | 3 +-- src/librustc_trans/lib.rs | 3 +-- src/libstd/lib.rs | 7 +++---- src/libsyntax/diagnostic_list.rs | 12 ++++++++---- src/test/ui/error-codes/E0658.stderr | 2 +- 10 files changed, 21 insertions(+), 29 deletions(-) (limited to 'src/libstd') diff --git a/src/doc/unstable-book/src/language-features/i128-type.md b/src/doc/unstable-book/src/language-features/i128-type.md index 6f46469f324..ff5fc0fdc15 100644 --- a/src/doc/unstable-book/src/language-features/i128-type.md +++ b/src/doc/unstable-book/src/language-features/i128-type.md @@ -9,7 +9,7 @@ The tracking issue for this feature is: [#35118] The `i128` feature adds support for `#[repr(u128)]` on `enum`s. ```rust -#![feature(i128)] +#![feature(repri128)] #[repr(u128)] enum Foo { diff --git a/src/libcore/num/i128.rs b/src/libcore/num/i128.rs index 04354e2e33f..989376d1ac2 100644 --- a/src/libcore/num/i128.rs +++ b/src/libcore/num/i128.rs @@ -12,6 +12,6 @@ //! //! *[See also the `i128` primitive type](../../std/primitive.i128.html).* -#![unstable(feature = "i128", issue="35118")] +#![stable(feature = "i128", since = "1.26.0")] -int_module! { i128, #[unstable(feature = "i128", issue="35118")] } +int_module! { i128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 9ff42a6d4ea..66f7160827a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1635,10 +1635,7 @@ impl i64 { #[lang = "i128"] impl i128 { int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728, - 170141183460469231731687303715884105727, "#![feature(i128)] -# fn main() { -", " -# }" } + 170141183460469231731687303715884105727, "", "" } } #[cfg(target_pointer_width = "16")] @@ -3492,11 +3489,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "#![feature(i128)] - -# fn main() { -", " -# }" } + uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "", "" } } #[cfg(target_pointer_width = "16")] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 061044cdf14..e835d6192e5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -52,8 +52,7 @@ #![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index a53055c7ce7..7177e2818fb 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -19,8 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 01f91e37db8..378a06dd912 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,9 +26,8 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![cfg_attr(stage0, feature(i128_type))] -#![feature(i128)] #![cfg_attr(stage0, feature(conservative_impl_trait))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(specialization)] #![feature(optin_builtin_traits)] #![feature(underscore_lifetimes)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index d89d19db63e..bd33707b1c6 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,8 +24,7 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type))] -#![feature(i128)] +#![cfg_attr(stage0, feature(i128_type, i128))] #![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] #![feature(quote)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3cc5d7b81c3..93996868f16 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -269,8 +269,7 @@ #![feature(generic_param_attrs)] #![feature(hashmap_internals)] #![feature(heap_api)] -#![feature(i128)] -#![cfg_attr(stage0, feature(i128_type))] +#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] @@ -435,7 +434,7 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; @@ -465,7 +464,7 @@ pub use alloc::string; pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::char; -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] pub use core::u128; pub mod f32; diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 1f87c1b94c5..3246dc47701 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -250,7 +250,10 @@ An unstable feature was used. Erroneous code example: ```compile_fail,E658 -let x = ::std::u128::MAX; // error: use of unstable library feature 'i128' +#[repr(u128)] // error: use of unstable library feature 'i128' +enum Foo { + Bar(u64), +} ``` If you're using a stable or a beta version of rustc, you won't be able to use @@ -261,10 +264,11 @@ If you're using a nightly version of rustc, just add the corresponding feature to be able to use it: ``` -#![feature(i128)] +#![feature(repri128)] -fn main() { - let x = ::std::u128::MAX; // ok! +#[repr(u128)] // ok! +enum Foo { + Bar(u64), } ``` "##, diff --git a/src/test/ui/error-codes/E0658.stderr b/src/test/ui/error-codes/E0658.stderr index 5be05600ee5..f4294e6b026 100644 --- a/src/test/ui/error-codes/E0658.stderr +++ b/src/test/ui/error-codes/E0658.stderr @@ -4,7 +4,7 @@ error[E0658]: use of unstable library feature 'i128' (see issue #35118) LL | let _ = ::std::u128::MAX; //~ ERROR E0658 | ^^^^^^^^^^^^^^^^ | - = help: add #![feature(i128)] to the crate attributes to enable + = help: add #![feature(repri128)] to the crate attributes to enable error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 07104692d5df1401fe0109fca800e4efe4e81a6c Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 17 Mar 2018 11:46:31 -0500 Subject: Fix missed i128 feature gates --- .../unstable-book/src/language-features/repr128.md | 2 +- src/libcore/num/mod.rs | 24 +++++++-------- src/libstd/primitive_docs.rs | 4 +-- src/libsyntax/diagnostic_list.rs | 4 +-- src/test/run-pass/saturating-float-casts.rs | 2 +- src/test/run-pass/u128-as-f32.rs | 2 +- src/test/ui/feature-gate-i128_type2.rs | 34 ---------------------- src/test/ui/feature-gate-i128_type2.stderr | 13 --------- 8 files changed, 19 insertions(+), 66 deletions(-) delete mode 100644 src/test/ui/feature-gate-i128_type2.rs delete mode 100644 src/test/ui/feature-gate-i128_type2.stderr (limited to 'src/libstd') diff --git a/src/doc/unstable-book/src/language-features/repr128.md b/src/doc/unstable-book/src/language-features/repr128.md index 3c86d581fa7..0858988952c 100644 --- a/src/doc/unstable-book/src/language-features/repr128.md +++ b/src/doc/unstable-book/src/language-features/repr128.md @@ -1,4 +1,4 @@ -# `repri128` +# `repr128` The tracking issue for this feature is: [#35118] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 66f7160827a..55186b0a3ac 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4046,39 +4046,39 @@ macro_rules! impl_from { impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, u128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { u64, u128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } // Signed -> Signed impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i32, i128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { i64, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } // Unsigned -> Signed impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, i128, #[unstable(feature = "i128", issue = "35118")] } -impl_from! { u64, i128, #[unstable(feature = "i128", issue = "35118")] } +impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } +impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index e6e6be2e453..ce4bbfffc2e 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -751,7 +751,7 @@ mod prim_i64 { } /// The 128-bit signed integer type. /// /// *[See also the `std::i128` module](i128/index.html).* -#[unstable(feature = "i128", issue="35118")] +#[stable(feature = "i128", since="1.26.0")] mod prim_i128 { } #[doc(primitive = "u8")] @@ -791,7 +791,7 @@ mod prim_u64 { } /// The 128-bit unsigned integer type. /// /// *[See also the `std::u128` module](u128/index.html).* -#[unstable(feature = "i128", issue="35118")] +#[stable(feature = "i128", since="1.26.0")] mod prim_u128 { } #[doc(primitive = "isize")] diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 3246dc47701..bb7988e64bc 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -250,7 +250,7 @@ An unstable feature was used. Erroneous code example: ```compile_fail,E658 -#[repr(u128)] // error: use of unstable library feature 'i128' +#[repr(u128)] // error: use of unstable library feature 'repr128' enum Foo { Bar(u64), } @@ -264,7 +264,7 @@ If you're using a nightly version of rustc, just add the corresponding feature to be able to use it: ``` -#![feature(repri128)] +#![feature(repr128)] #[repr(u128)] // ok! enum Foo { diff --git a/src/test/run-pass/saturating-float-casts.rs b/src/test/run-pass/saturating-float-casts.rs index d1a0901bb3d..ad3b4b17259 100644 --- a/src/test/run-pass/saturating-float-casts.rs +++ b/src/test/run-pass/saturating-float-casts.rs @@ -11,7 +11,7 @@ // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. // compile-flags: -Z saturating-float-casts -#![feature(test, i128, stmt_expr_attributes)] +#![feature(test, stmt_expr_attributes)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/run-pass/u128-as-f32.rs b/src/test/run-pass/u128-as-f32.rs index 3531a961bef..2848fb2d51a 100644 --- a/src/test/run-pass/u128-as-f32.rs +++ b/src/test/run-pass/u128-as-f32.rs @@ -10,7 +10,7 @@ // ignore-emscripten u128 not supported -#![feature(test, i128)] +#![feature(test)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/ui/feature-gate-i128_type2.rs b/src/test/ui/feature-gate-i128_type2.rs deleted file mode 100644 index cd65b9d9223..00000000000 --- a/src/test/ui/feature-gate-i128_type2.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// gate-test-i128_type - -fn test1() -> i128 { - 0 -} - -fn test1_2() -> u128 { - 0 -} - -fn test3() { - let x: i128 = 0; -} - -fn test3_2() { - let x: u128 = 0; -} - -#[repr(u128)] -enum A { //~ ERROR 128-bit type is unstable - A(u64) -} - -fn main() {} diff --git a/src/test/ui/feature-gate-i128_type2.stderr b/src/test/ui/feature-gate-i128_type2.stderr deleted file mode 100644 index fe4557899ac..00000000000 --- a/src/test/ui/feature-gate-i128_type2.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: repr with 128-bit type is unstable (see issue #35118) - --> $DIR/feature-gate-i128_type2.rs:30:1 - | -LL | / enum A { //~ ERROR 128-bit type is unstable -LL | | A(u64) -LL | | } - | |_^ - | - = help: add #![feature(repr128)] to the crate attributes to enable - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From a7f21f1c0a57984eb9a04b39223ae0c5b1cf63fb Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 17 Mar 2018 11:55:44 -0500 Subject: Fix a few more --- src/libcore/num/u128.rs | 4 ++-- src/libstd/net/ip.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/u128.rs b/src/libcore/num/u128.rs index 987ac3e0007..e8c783a1bb5 100644 --- a/src/libcore/num/u128.rs +++ b/src/libcore/num/u128.rs @@ -12,5 +12,5 @@ //! //! *[See also the `u128` primitive type](../../std/primitive.u128.html).* -#![unstable(feature = "i128", issue="35118")] -uint_module! { u128, #[unstable(feature = "i128", issue="35118")] } +#![stable(feature = "i128", since = "1.26.0")] +uint_module! { u128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 0d73a6f4fd7..36376c07791 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -1346,7 +1346,7 @@ impl FromInner for Ipv6Addr { } } -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] impl From for u128 { fn from(ip: Ipv6Addr) -> u128 { let ip = ip.segments(); @@ -1355,7 +1355,7 @@ impl From for u128 { ((ip[6] as u128) << 16) + (ip[7] as u128) } } -#[unstable(feature = "i128", issue = "35118")] +#[stable(feature = "i128", since = "1.26.0")] impl From for Ipv6Addr { fn from(ip: u128) -> Ipv6Addr { Ipv6Addr::new( -- cgit 1.4.1-3-g733a5 From 140bf949bf65bb0479dbe31bd3474d5546ef59e1 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sat, 24 Mar 2018 18:19:33 -0500 Subject: fix last two tidy --- src/libcore/num/mod.rs | 8 +------- src/libstd/num.rs | 7 +------ 2 files changed, 2 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 55186b0a3ac..a5ba0bcdf7e 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -97,14 +97,8 @@ nonzero_integers! { NonZeroU16(u16); NonZeroI16(i16); NonZeroU32(u32); NonZeroI32(i32); NonZeroU64(u64); NonZeroI64(i64); - NonZeroUsize(usize); NonZeroIsize(isize); -} - -nonzero_integers! { - // Change this to `#[unstable(feature = "i128", issue = "35118")]` - // if other NonZero* integer types are stabilizied before 128-bit integers - #[unstable(feature = "nonzero", issue = "49137")] NonZeroU128(u128); NonZeroI128(i128); + NonZeroUsize(usize); NonZeroIsize(isize); } /// Provides intentionally-wrapped arithmetic on `T`. diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 6f537fd5c50..547b8c7c925 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -24,14 +24,9 @@ pub use core::num::Wrapping; #[unstable(feature = "nonzero", issue = "49137")] pub use core::num::{ NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, - NonZeroU64, NonZeroI64, NonZeroUsize, NonZeroIsize, + NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize, }; -// Change this to `#[unstable(feature = "i128", issue = "35118")]` -// if other NonZero* integer types are stabilizied before 128-bit integers -#[unstable(feature = "nonzero", issue = "49137")] -pub use core::num::{NonZeroU128, NonZeroI128}; - #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; -- cgit 1.4.1-3-g733a5 From 9255bbd035ee032f1ccd47fcf93c87f7bc2e4bad Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Mon, 26 Mar 2018 20:15:19 +0200 Subject: Implement RFC #2169 (Euclidean division). Tracking issue: #49048 --- src/libcore/num/mod.rs | 436 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/f32.rs | 51 ++++++ src/libstd/f64.rs | 50 ++++++ 3 files changed, 537 insertions(+) (limited to 'src/libstd') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 18e0aa453d8..b4a43b216e8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -633,6 +633,32 @@ $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` if `rhs == 0` +or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::min_value() + 1).checked_div_euc(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euc(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div_euc(0), None);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_div_euc(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(self.div_euc(rhs)) + } + } + } + doc_comment! { concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0` or the division results in overflow. @@ -660,6 +686,33 @@ $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_mod_euc(-1), None);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_mod_euc(self, rhs: Self) -> Option { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(self.mod_euc(rhs)) + } + } + } + doc_comment! { concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. @@ -993,6 +1046,34 @@ $EndFeature, " } } + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, wrapping around at the +boundary of the type. + +The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where +`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value +that is too large to represent in the type. In such a case, this function returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); +assert_eq!((-128i8).wrapping_div_euc(-1), -128);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_div_euc(self, rhs: Self) -> Self { + self.overflowing_div_euc(rhs).0 + } + } + doc_comment! { concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the boundary of the type. @@ -1021,6 +1102,34 @@ $EndFeature, " } } + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`, wrapping around at the +boundary of the type. + +Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` +invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, +this function returns `0`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); +assert_eq!((-128i8).wrapping_mod_euc(-1), 0);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_mod_euc(self, rhs: Self) -> Self { + self.overflowing_mod_euc(rhs).0 + } + } + doc_comment! { concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary of the type. @@ -1286,6 +1395,39 @@ $EndFeature, " } } + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then self is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euc(-1), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (self, true) + } else { + (self.div_euc(rhs), false) + } + } + } + doc_comment! { concat!("Calculates the remainder when `self` is divided by `rhs`. @@ -1318,6 +1460,40 @@ $EndFeature, " } } + + doc_comment! { + concat!("Calculates the modulo of Euclidean divsion `self.mod_euc(rhs)`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_mod_euc(-1), (0, true));", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (0, true) + } else { + (self.mod_euc(rhs), false) + } + } + } + + doc_comment! { concat!("Negates self, overflowing if this is equal to the minimum value. @@ -1512,6 +1688,80 @@ $EndFeature, " } } + doc_comment! { + concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. + +This computes the integer n such that `self = n * rhs + self.mod_euc(rhs)`. +In other words, the result is `self / rhs` rounded to the integer n +such that `self >= n * rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.div_euc(b), 1); // 7 >= 4 * 1 +assert_eq!(a.div_euc(-b), -1); // 7 >= -4 * -1 +assert_eq!((-a).div_euc(b), -2); // -7 >= 4 * -2 +assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn div_euc(self, rhs: Self) -> Self { + let q = self / rhs; + if self % rhs < 0 { + return if rhs > 0 { q - 1 } else { q + 1 } + } + q + } + } + + + doc_comment! { + concat!("Calculates the modulo `self mod rhs` by Euclidean division. + +In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.mod_euc(b), 3); +assert_eq!((-a).mod_euc(b), 1); +assert_eq!(a.mod_euc(-b), 3); +assert_eq!((-a).mod_euc(-b), 1);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn mod_euc(self, rhs: Self) -> Self { + let r = self % rhs; + if r < 0 { + r + rhs.abs() + } else { + r + } + } + } + doc_comment! { concat!("Computes the absolute value of `self`. @@ -2103,6 +2353,30 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div_euc(0), None); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_div_euc(self, rhs: Self) -> Option { + if rhs == 0 { + None + } else { + Some(self.div_euc(rhs)) + } + } + } + + doc_comment! { concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`. @@ -2126,6 +2400,30 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " } } + doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None);", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_mod_euc(self, rhs: Self) -> Option { + if rhs == 0 { + None + } else { + Some(self.mod_euc(rhs)) + } + } + } + doc_comment! { concat!("Checked negation. Computes `-self`, returning `None` unless `self == 0`. @@ -2405,6 +2703,27 @@ Basic usage: } } + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10);", $EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_div_euc(self, rhs: Self) -> Self { + self.div_euc(rhs) + } + } + doc_comment! { concat!("Wrapping (modular) remainder. Computes `self % rhs`. Wrapped remainder calculation on unsigned types is @@ -2427,6 +2746,28 @@ Basic usage: } } + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`. +Wrapped modulo calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0);", $EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_mod_euc(self, rhs: Self) -> Self { + self % rhs + } + } + /// Wrapping (modular) negation. Computes `-self`, /// wrapping around at the boundary of the type. /// @@ -2660,6 +3001,32 @@ Basic usage } } + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));", $EndFeature, " +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + doc_comment! { concat!("Calculates the remainder when `self` is divided by `rhs`. @@ -2686,6 +3053,32 @@ Basic usage } } + doc_comment! { + concat!("Calculates the modulo of Euclidean division of `self.mod_euc(rhs)`. + +Returns a tuple of the modulo after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));", $EndFeature, " +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + doc_comment! { concat!("Negates self in an overflowing fashion. @@ -2843,6 +3236,49 @@ Basic usage: } } + doc_comment! { + concat!("Performs Euclidean division. + +For unsigned types, this is just the same as `self / rhs`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn div_euc(self, rhs: Self) -> Self { + self / rhs + } + } + + + doc_comment! { + concat!("Calculates the Euclidean modulo `self mod rhs`. + +For unsigned types, this is just the same as `self % rhs`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type", +$EndFeature, " +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn mod_euc(self, rhs: Self) -> Self { + self % rhs + } + } + doc_comment! { concat!("Returns `true` if and only if `self == 2^k` for some `k`. diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ceb019bc95b..ed63f445084 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -329,6 +329,57 @@ impl f32 { unsafe { intrinsics::fmaf32(self, a, b) } } + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer n such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer n + /// such that `self >= n * rhs`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f32) -> f32 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// + /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 97adf108b73..320655c443c 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -315,6 +315,56 @@ impl f64 { unsafe { intrinsics::fmaf64(self, a, b) } } + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer n such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer n + /// such that `self >= n * rhs`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f64) -> f64 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// + /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f64) -> f64 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` -- cgit 1.4.1-3-g733a5 From e53a2a72743810e05f58c61c9d8a4c89b712ad2e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 13:52:54 +0100 Subject: Stabilize the TryFrom and TryInto traits Tracking issue: https://github.com/rust-lang/rust/issues/33417 --- src/libcore/array.rs | 6 +++--- src/libcore/char.rs | 6 +++--- src/libcore/convert.rs | 12 ++++++++---- src/libcore/num/mod.rs | 14 +++++++------- src/libcore/tests/lib.rs | 1 - src/librustc_apfloat/lib.rs | 2 +- src/libstd/error.rs | 6 +++--- src/libstd/lib.rs | 1 - src/libstd_unicode/char.rs | 2 +- src/libstd_unicode/lib.rs | 1 - src/test/ui/e0119/conflict-with-std.rs | 2 -- src/test/ui/e0119/conflict-with-std.stderr | 6 +++--- 12 files changed, 29 insertions(+), 30 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 3d24f8902bd..87144c27c9e 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -59,7 +59,7 @@ unsafe impl> FixedSizeArray for A { } /// The error type returned when a conversion from a slice to an array fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); @@ -148,7 +148,7 @@ macro_rules! array_impls { } } - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { type Error = TryFromSliceError; @@ -162,7 +162,7 @@ macro_rules! array_impls { } } - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { type Error = TryFromSliceError; diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 1638f9710f5..bbeebf52a73 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -265,7 +265,7 @@ impl FromStr for char { } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl TryFrom for char { type Error = CharTryFromError; @@ -280,11 +280,11 @@ impl TryFrom for char { } /// The error type returned when a conversion from u32 to char fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CharTryFromError(()); -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl fmt::Display for CharTryFromError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { "converted integer out of range for `char`".fmt(f) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 7324df95bc5..63721395784 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -322,22 +322,26 @@ pub trait From: Sized { /// /// [`TryFrom`]: trait.TryFrom.html /// [`Into`]: trait.Into.html -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. + #[stable(feature = "try_from", since = "1.26.0")] fn try_into(self) -> Result; } /// Attempt to construct `Self` via a conversion. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. + #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. + #[stable(feature = "try_from", since = "1.26.0")] fn try_from(value: T) -> Result; } @@ -405,7 +409,7 @@ impl From for T { // TryFrom implies TryInto -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl TryInto for T where U: TryFrom { type Error = U::Error; @@ -417,7 +421,7 @@ impl TryInto for T where U: TryFrom // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl TryFrom for T where T: From { type Error = !; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 2da5718a358..8f7e8d0c8ab 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3647,7 +3647,7 @@ macro_rules! from_str_radix_int_impl { from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } /// The error type returned when a checked integral type conversion fails. -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] #[derive(Debug, Copy, Clone)] pub struct TryFromIntError(()); @@ -3662,14 +3662,14 @@ impl TryFromIntError { } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.__description().fmt(fmt) } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { never @@ -3679,7 +3679,7 @@ impl From for TryFromIntError { // no possible bounds violation macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3694,7 +3694,7 @@ macro_rules! try_from_unbounded { // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3713,7 +3713,7 @@ macro_rules! try_from_lower_bounded { // unsigned to signed (only positive bound) macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -3732,7 +3732,7 @@ macro_rules! try_from_upper_bounded { // all other cases macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( - #[unstable(feature = "try_from", issue = "33417")] + #[stable(feature = "try_from", since = "1.26.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 0b70f692403..1a68f04532d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -43,7 +43,6 @@ #![feature(step_trait)] #![feature(test)] #![feature(trusted_len)] -#![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] #![feature(atomic_nand)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 2ee7bea8476..6f08fcf7025 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -48,7 +48,7 @@ #![cfg_attr(stage0, feature(slice_patterns))] #![cfg_attr(stage0, feature(i128_type))] -#![feature(try_from)] +#![cfg_attr(stage0, feature(try_from))] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 79bb6af168f..3d0c96585b5 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -275,14 +275,14 @@ impl Error for num::ParseIntError { } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl Error for num::TryFromIntError { fn description(&self) -> &str { self.__description() } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl Error for array::TryFromSliceError { fn description(&self) -> &str { self.__description() @@ -356,7 +356,7 @@ impl Error for cell::BorrowMutError { } } -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] impl Error for char::CharTryFromError { fn description(&self) -> &str { "converted integer out of range for `char`" diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 93996868f16..15a22443b6a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -310,7 +310,6 @@ #![feature(test, rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] -#![feature(try_from)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode)] diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index de8b46d5f1b..33e47ade8cb 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -42,7 +42,7 @@ pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode}; pub use core::char::ParseCharError; // unstable re-exports -#[unstable(feature = "try_from", issue = "33417")] +#[stable(feature = "try_from", since = "1.26.0")] pub use core::char::CharTryFromError; #[unstable(feature = "decode_utf8", issue = "33906")] pub use core::char::{DecodeUtf8, decode_utf8}; diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index f155b62e3cc..c22ea1671fa 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -39,7 +39,6 @@ #![feature(lang_items)] #![feature(non_exhaustive)] #![feature(staged_api)] -#![feature(try_from)] #![feature(unboxed_closures)] mod bool_trie; diff --git a/src/test/ui/e0119/conflict-with-std.rs b/src/test/ui/e0119/conflict-with-std.rs index ed9033ad53d..a9f747d09ec 100644 --- a/src/test/ui/e0119/conflict-with-std.rs +++ b/src/test/ui/e0119/conflict-with-std.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(try_from)] - use std::marker::PhantomData; use std::convert::{TryFrom, AsRef}; diff --git a/src/test/ui/e0119/conflict-with-std.stderr b/src/test/ui/e0119/conflict-with-std.stderr index e8b2c84c0df..417ff1de3f8 100644 --- a/src/test/ui/e0119/conflict-with-std.stderr +++ b/src/test/ui/e0119/conflict-with-std.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `std::convert::AsRef` for type `std::boxed::Box`: - --> $DIR/conflict-with-std.rs:17:1 + --> $DIR/conflict-with-std.rs:15:1 | LL | impl AsRef for Box { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | impl AsRef for Box { //~ ERROR conflicting implementations where T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: - --> $DIR/conflict-with-std.rs:24:1 + --> $DIR/conflict-with-std.rs:22:1 | LL | impl From for S { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | impl From for S { //~ ERROR conflicting implementations - impl std::convert::From for T; error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: - --> $DIR/conflict-with-std.rs:31:1 + --> $DIR/conflict-with-std.rs:29:1 | LL | impl TryFrom for X { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 09008cc23ff6395c2c928f3690e07d7389d08ebc Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 26 Mar 2018 11:17:31 +0200 Subject: Add TryFrom and TryInto to the prelude --- src/libcore/prelude/v1.rs | 3 +++ src/libstd/prelude/v1.rs | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src/libstd') diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index d43496c387c..2c8e27abac9 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -39,6 +39,9 @@ pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[stable(feature = "try_from", since = "1.26.0")] +#[doc(no_inline)] +pub use convert::{TryFrom, TryInto}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use default::Default; diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index feedd4e1abe..d5b7c68a3fa 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -35,6 +35,8 @@ #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[stable(feature = "try_from", since = "1.26.0")] +#[doc(no_inline)] pub use convert::{TryFrom, TryInto}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 04f6692aaf78809c041ba6145bde2dcbeec9725e Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Mon, 26 Mar 2018 23:24:31 +0100 Subject: Implement `shrink_to` method on collections --- src/liballoc/binary_heap.rs | 25 ++++++++++++++++++++++++ src/liballoc/string.rs | 28 ++++++++++++++++++++++++++ src/liballoc/vec.rs | 27 ++++++++++++++++++++++++- src/liballoc/vec_deque.rs | 35 ++++++++++++++++++++++++++++++++- src/libstd/collections/hash/map.rs | 40 ++++++++++++++++++++++++++++++++++++++ src/libstd/collections/hash/set.rs | 28 ++++++++++++++++++++++++++ src/libstd/ffi/os_str.rs | 30 ++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/sys/redox/os_str.rs | 5 +++++ src/libstd/sys/unix/os_str.rs | 5 +++++ src/libstd/sys/wasm/os_str.rs | 5 +++++ src/libstd/sys/windows/os_str.rs | 5 +++++ src/libstd/sys_common/wtf8.rs | 5 +++++ 13 files changed, 237 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index 8aaac5d6e08..f6a666b599b 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -509,6 +509,31 @@ impl BinaryHeap { self.data.shrink_to_fit(); } + /// Discards capacity with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::BinaryHeap; + /// let mut heap: BinaryHeap = BinaryHeap::with_capacity(100); + /// + /// assert!(heap.capacity() >= 100); + /// heap.shrink_to(10); + /// assert!(heap.capacity() >= 10); + /// ``` + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.data.shrink_to(min_capacity) + } + /// Removes the greatest item from the binary heap and returns it, or `None` if it /// is empty. /// diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index e253122ffd6..2bb60a50679 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1015,6 +1015,34 @@ impl String { self.vec.shrink_to_fit() } + /// Shrinks the capacity of this `String` with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// let mut s = String::from("foo"); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to(10); + /// assert!(s.capacity() >= 10); + /// s.shrink_to(0); + /// assert!(s.capacity() >= 3); + /// ``` + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.vec.shrink_to(min_capacity) + } + /// Appends the given [`char`] to the end of this `String`. /// /// [`char`]: ../../std/primitive.char.html diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 953f95876be..c9c6cf1cb66 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -66,7 +66,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use core::cmp::Ordering; +use core::cmp::{self, Ordering}; use core::fmt; use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; @@ -586,6 +586,31 @@ impl Vec { self.buf.shrink_to_fit(self.len); } + /// Shrinks the capacity of the vector with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3].iter().cloned()); + /// assert_eq!(vec.capacity(), 10); + /// vec.shrink_to(4); + /// assert!(vec.capacity() >= 4); + /// vec.shrink_to(0); + /// assert!(vec.capacity() >= 3); + /// ``` + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); + } + /// Converts the vector into [`Box<[T]>`][owned slice]. /// /// Note that this will drop any excess capacity. diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 0658777f0a0..be6e8d0f22f 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -676,9 +676,42 @@ impl VecDeque { /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn shrink_to_fit(&mut self) { + self.shrink_to(0); + } + + /// Shrinks the capacity of the `VecDeque` with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::with_capacity(15); + /// buf.extend(0..4); + /// assert_eq!(buf.capacity(), 15); + /// buf.shrink_to(6); + /// assert!(buf.capacity() >= 6); + /// buf.shrink_to(0); + /// assert!(buf.capacity() >= 4); + /// ``` + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); + // +1 since the ringbuffer always leaves one space empty // len + 1 can't overflow for an existing, well-formed ringbuffer. - let target_cap = cmp::max(self.len() + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); + let target_cap = cmp::max( + cmp::max(min_capacity, self.len()) + 1, + MINIMUM_CAPACITY + 1 + ).next_power_of_two(); + if target_cap < self.cap() { // There are three cases of interest: // All elements are out of desired bounds diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index b18b38ec302..169d365c0ac 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -910,6 +910,46 @@ impl HashMap } } + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// ``` + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); + + let new_raw_cap = self.resize_policy.raw_capacity(max(self.len(), min_capacity)); + if self.raw_capacity() != new_raw_cap { + let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); + let old_size = old_table.size(); + + // Shrink the table. Naive algorithm for resizing: + for (h, k, v) in old_table.into_iter() { + self.insert_hashed_nocheck(h, k, v); + } + + debug_assert_eq!(self.table.size(), old_size); + } + } + /// Insert a pre-hashed key-value pair, without first checking /// that there's enough room in the buckets. Returns a reference to the /// newly insert value. diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 9e63ba2717a..855563a5cb8 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -292,6 +292,34 @@ impl HashSet self.map.shrink_to_fit() } + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity) + } + /// An iterator visiting all elements in arbitrary order. /// The iterator element type is `&'a T`. /// diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 3959e8533be..7520121a8c2 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -295,6 +295,36 @@ impl OsString { self.inner.shrink_to_fit() } + /// Shrinks the capacity of the `OsString` with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("foo"); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to(10); + /// assert!(s.capacity() >= 10); + /// s.shrink_to(0); + /// assert!(s.capacity() >= 3); + /// ``` + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + /// Converts this `OsString` into a boxed [`OsStr`]. /// /// [`OsStr`]: struct.OsStr.html diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0b06c5d4d65..edecf309d16 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -299,6 +299,7 @@ #![feature(raw)] #![feature(rustc_attrs)] #![feature(stdsimd)] +#![feature(shrink_to)] #![feature(slice_bytes)] #![feature(slice_concat_ext)] #![feature(slice_internals)] diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 655bfdb9167..da27787babb 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -104,6 +104,11 @@ impl Buf { self.inner.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index e0349387998..e43bc6da5f1 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -104,6 +104,11 @@ impl Buf { self.inner.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs index 543c22ebe18..84f560af69b 100644 --- a/src/libstd/sys/wasm/os_str.rs +++ b/src/libstd/sys/wasm/os_str.rs @@ -104,6 +104,11 @@ impl Buf { self.inner.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 414c9c5418e..bcc66b9954b 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -113,6 +113,11 @@ impl Buf { self.inner.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + #[inline] pub fn into_box(self) -> Box { unsafe { mem::transmute(self.inner.into_box()) } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 78b2bb5fe6e..dda4e1bab3b 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -253,6 +253,11 @@ impl Wtf8Buf { self.bytes.shrink_to_fit() } + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.bytes.shrink_to(min_capacity) + } + /// Returns the number of bytes that this string buffer can hold without reallocating. #[inline] pub fn capacity(&self) -> usize { -- cgit 1.4.1-3-g733a5 From 837d6c70233715a0ae8e15c703d40e3046a2f36a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 26 Mar 2018 22:48:12 +0200 Subject: Remove TryFrom impls that might become conditionally-infallible with a portability lint https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 --- src/libcore/iter/range.rs | 74 ++++++++++++++++++++++++- src/libcore/num/mod.rs | 70 ++++-------------------- src/libcore/tests/num/mod.rs | 127 ------------------------------------------- src/libstd/io/cursor.rs | 20 ++++++- 4 files changed, 100 insertions(+), 191 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 8d1080bb876..72b48b56571 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -91,7 +91,7 @@ macro_rules! step_impl_unsigned { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$t>::try_from(n) { + match <$t>::private_try_from(n) { Ok(n_as_t) => self.checked_add(n_as_t), Err(_) => None, } @@ -123,7 +123,7 @@ macro_rules! step_impl_signed { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$unsigned>::try_from(n) { + match <$unsigned>::private_try_from(n) { Ok(n_as_unsigned) => { // Wrapping in unsigned space handles cases like // `-120_i8.add_usize(200) == Some(80_i8)`, @@ -461,3 +461,73 @@ impl DoubleEndedIterator for ops::RangeInclusive { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} + +/// Compensate removal of some impls per +/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 +trait PrivateTryFromUsize: Sized { + fn private_try_from(n: usize) -> Result; +} + +impl PrivateTryFromUsize for T where T: TryFrom { + #[inline] + fn private_try_from(n: usize) -> Result { + T::try_from(n).map_err(|_| ()) + } +} + +// no possible bounds violation +macro_rules! try_from_unbounded { + ($($target:ty),*) => {$( + impl PrivateTryFromUsize for $target { + #[inline] + fn private_try_from(value: usize) -> Result { + Ok(value as $target) + } + } + )*} +} + +// unsigned to signed (only positive bound) +macro_rules! try_from_upper_bounded { + ($($target:ty),*) => {$( + impl PrivateTryFromUsize for $target { + #[inline] + fn private_try_from(u: usize) -> Result<$target, ()> { + if u > (<$target>::max_value() as usize) { + Err(()) + } else { + Ok(u as $target) + } + } + } + )*} +} + + +#[cfg(target_pointer_width = "16")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_unbounded!(u16, u32, u64, u128); + try_from_unbounded!(i32, i64, i128); +} + +#[cfg(target_pointer_width = "32")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_upper_bounded!(u16); + try_from_unbounded!(u32, u64, u128); + try_from_upper_bounded!(i32); + try_from_unbounded!(i64, i128); +} + +#[cfg(target_pointer_width = "64")] +mod ptr_try_from_impls { + use super::PrivateTryFromUsize; + + try_from_upper_bounded!(u16, u32); + try_from_unbounded!(u64, u128); + try_from_upper_bounded!(i32, i64); + try_from_unbounded!(i128); +} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 8f7e8d0c8ab..ee041e1e4f1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3676,21 +3676,6 @@ impl From for TryFromIntError { } } -// no possible bounds violation -macro_rules! try_from_unbounded { - ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] - impl TryFrom<$source> for $target { - type Error = TryFromIntError; - - #[inline] - fn try_from(value: $source) -> Result { - Ok(value as $target) - } - } - )*} -} - // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( @@ -3789,27 +3774,20 @@ try_from_both_bounded!(i128, u64, u32, u16, u8); try_from_upper_bounded!(usize, isize); try_from_lower_bounded!(isize, usize); +try_from_upper_bounded!(usize, u8); +try_from_upper_bounded!(usize, i8, i16); +try_from_both_bounded!(isize, u8); +try_from_both_bounded!(isize, i8); + #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - try_from_upper_bounded!(usize, u8); - try_from_unbounded!(usize, u16, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16); - try_from_unbounded!(usize, i32, i64, i128); - - try_from_both_bounded!(isize, u8); + // Fallible across platfoms, only implementation differs try_from_lower_bounded!(isize, u16, u32, u64, u128); - try_from_both_bounded!(isize, i8); - try_from_unbounded!(isize, i16, i32, i64, i128); - - rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); - - rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); - rev!(try_from_both_bounded, isize, i32, i64, i128); } #[cfg(target_pointer_width = "32")] @@ -3817,25 +3795,11 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - try_from_upper_bounded!(usize, u8, u16); - try_from_unbounded!(usize, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32); - try_from_unbounded!(usize, i64, i128); - - try_from_both_bounded!(isize, u8, u16); + // Fallible across platfoms, only implementation differs + try_from_both_bounded!(isize, u16); try_from_lower_bounded!(isize, u32, u64, u128); - try_from_both_bounded!(isize, i8, i16); - try_from_unbounded!(isize, i32, i64, i128); - - rev!(try_from_unbounded, usize, u32); - rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); - - rev!(try_from_unbounded, isize, u16); - rev!(try_from_upper_bounded, isize, u32, u64, u128); - rev!(try_from_unbounded, isize, i32); - rev!(try_from_both_bounded, isize, i64, i128); } #[cfg(target_pointer_width = "64")] @@ -3843,25 +3807,11 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - try_from_upper_bounded!(usize, u8, u16, u32); - try_from_unbounded!(usize, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, i64); - try_from_unbounded!(usize, i128); - - try_from_both_bounded!(isize, u8, u16, u32); + // Fallible across platfoms, only implementation differs + try_from_both_bounded!(isize, u16, u32); try_from_lower_bounded!(isize, u64, u128); - try_from_both_bounded!(isize, i8, i16, i32); - try_from_unbounded!(isize, i64, i128); - - rev!(try_from_unbounded, usize, u32, u64); - rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); - - rev!(try_from_unbounded, isize, u16, u32); - rev!(try_from_upper_bounded, isize, u64, u128); - rev!(try_from_unbounded, isize, i32, i64); - rev!(try_from_both_bounded, isize, i128); } #[doc(hidden)] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 587dcbe6d67..c7edb55b378 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -37,15 +37,6 @@ mod flt2dec; mod dec2flt; mod bignum; - -/// Adds the attribute to all items in the block. -macro_rules! cfg_block { - ($(#[$attr:meta]{$($it:item)*})*) => {$($( - #[$attr] - $it - )*)*} -} - /// Groups items that assume the pointer width is either 16/32/64, and has to be altered if /// support for larger/smaller pointer widths are added in the future. macro_rules! assume_usize_width { @@ -318,42 +309,6 @@ assume_usize_width! { test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } - - test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } - test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } - test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } - - test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } - test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } - test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } - test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } - test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } - test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } - test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } - test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } - test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } - } - ); } /// Conversions where max of $source can be represented as $target, @@ -402,24 +357,6 @@ assume_usize_width! { test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } - - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } - } - ); } /// Conversions where max of $source can not be represented as $target, @@ -461,29 +398,9 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } assume_usize_width! { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } - test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } - } - ); } /// Conversions where min/max of $source can not be represented as $target. @@ -543,34 +460,6 @@ test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } assume_usize_width! { test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } - test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } - test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } - - cfg_block!( - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - - test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - } - - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - - test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - } - - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } - test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } - - test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } - test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } - } - ); } /// Conversions where neither the min nor the max of $source can be represented by @@ -615,22 +504,6 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } assume_usize_width! { test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } - - cfg_block! { - #[cfg(target_pointer_width = "16")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - } - #[cfg(target_pointer_width = "32")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } - - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - } - #[cfg(target_pointer_width = "64")] { - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } - test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } - } - } } macro_rules! test_float { diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 76bcb5fedc9..2673f3ccfa3 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -10,7 +10,6 @@ use io::prelude::*; -use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; @@ -260,9 +259,26 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result Result { + if n <= (::max_value() as u64) { + Ok(n as usize) + } else { + Err(()) + } +} + +#[cfg(any(target_pointer_width = "64"))] +fn try_into(n: u64) -> Result { + Ok(n as usize) +} + // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result { - let pos: usize = (*pos_mut).try_into().map_err(|_| { + let pos: usize = try_into(*pos_mut).map_err(|_| { Error::new(ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length") })?; -- cgit 1.4.1-3-g733a5 From ece87c3f4e76fd996dbbbaf8202f2adecff06c1e Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Wed, 28 Mar 2018 01:41:40 +0200 Subject: Address nits and tidy errors. --- src/libcore/num/mod.rs | 28 +++++++++++++++------------- src/libstd/f32.rs | 4 ++-- src/libstd/f64.rs | 4 ++-- 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index b4a43b216e8..9e7e9357159 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -634,8 +634,8 @@ $EndFeature, " } doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` if `rhs == 0` -or the division results in overflow. + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, +returning `None` if `rhs == 0` or the division results in overflow. # Examples @@ -1047,8 +1047,8 @@ $EndFeature, " } doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, wrapping around at the -boundary of the type. + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, +wrapping around at the boundary of the type. The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value @@ -1462,7 +1462,7 @@ $EndFeature, " doc_comment! { - concat!("Calculates the modulo of Euclidean divsion `self.mod_euc(rhs)`. + concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. Returns a tuple of the remainder after dividing along with a boolean indicating whether an arithmetic overflow would occur. If an overflow would occur then 0 is returned. @@ -1691,8 +1691,8 @@ $EndFeature, " doc_comment! { concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. -This computes the integer n such that `self = n * rhs + self.mod_euc(rhs)`. -In other words, the result is `self / rhs` rounded to the integer n +This computes the integer `n` such that `self = n * rhs + self.mod_euc(rhs)`. +In other words, the result is `self / rhs` rounded to the integer `n` such that `self >= n * rhs`. # Panics @@ -1727,7 +1727,7 @@ $EndFeature, " doc_comment! { - concat!("Calculates the modulo `self mod rhs` by Euclidean division. + concat!("Calculates the remainder `self mod rhs` by Euclidean division. In particular, the result `n` satisfies `0 <= n < rhs.abs()`. @@ -2720,7 +2720,7 @@ Basic usage: #[unstable(feature = "euclidean_division", issue = "49048")] #[inline] pub fn wrapping_div_euc(self, rhs: Self) -> Self { - self.div_euc(rhs) + self / rhs } } @@ -3018,7 +3018,8 @@ This function will panic if `rhs` is 0. Basic usage ``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));", $EndFeature, " +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false));", +$EndFeature, " ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] @@ -3054,7 +3055,7 @@ Basic usage } doc_comment! { - concat!("Calculates the modulo of Euclidean division of `self.mod_euc(rhs)`. + concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. Returns a tuple of the modulo after dividing along with a boolean indicating whether an arithmetic overflow would occur. Note that for @@ -3070,7 +3071,8 @@ This function will panic if `rhs` is 0. Basic usage ``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));", $EndFeature, " +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false));", +$EndFeature, " ```"), #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] @@ -3259,7 +3261,7 @@ $EndFeature, " doc_comment! { - concat!("Calculates the Euclidean modulo `self mod rhs`. + concat!("Calculates the remainder `self mod rhs` by Euclidean division. For unsigned types, this is just the same as `self % rhs`. diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ed63f445084..ca39089a958 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -331,9 +331,9 @@ impl f32 { /// Calculates Euclidean division, the matching method for `mod_euc`. /// - /// This computes the integer n such that + /// This computes the integer `n` such that /// `self = n * rhs + self.mod_euc(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer n + /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// /// ``` diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 320655c443c..a9585670ad0 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -317,9 +317,9 @@ impl f64 { /// Calculates Euclidean division, the matching method for `mod_euc`. /// - /// This computes the integer n such that + /// This computes the integer `n` such that /// `self = n * rhs + self.mod_euc(rhs)`. - /// In other words, the result is `self / rhs` rounded to the integer n + /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// /// ``` -- cgit 1.4.1-3-g733a5 From 8ecbec1dba048bf55461dbff772f18a72311ecc2 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Wed, 28 Mar 2018 18:47:16 +0900 Subject: Use mprotect instead of mmap --- src/libstd/sys/unix/thread.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 6064b55489e..775289f393b 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -355,10 +355,9 @@ pub mod guard { // macOS. Instead, just restore the page to a writable state. // This ain't Linux, so we probably don't need to care about // execstack. - let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE); - if result != stackaddr || result == MAP_FAILED { + if result != 0 { panic!("unable to reset the guard page"); } } -- cgit 1.4.1-3-g733a5 From e9dcec070d6097e5a22b6658844dccd9d1f578cf Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 24 Mar 2018 22:56:07 -0400 Subject: Remove hidden `foo` functions from doc examples; use `Termination` trait. Fixes https://github.com/rust-lang/rust/issues/49233. --- src/libstd/env.rs | 14 +- src/libstd/fs.rs | 528 +++++++++++++++++----------------- src/libstd/io/buffered.rs | 219 +++++++------- src/libstd/io/mod.rs | 605 +++++++++++++++++++-------------------- src/libstd/io/stdio.rs | 106 +++---- src/libstd/io/util.rs | 15 +- src/libstd/net/mod.rs | 10 +- src/libstd/net/tcp.rs | 16 +- src/libstd/net/udp.rs | 28 +- src/libstd/os/linux/fs.rs | 238 +++++++-------- src/libstd/sys/redox/ext/fs.rs | 38 +-- src/libstd/sys/unix/ext/fs.rs | 342 +++++++++++----------- src/libstd/sys/windows/ext/fs.rs | 98 +++---- 13 files changed, 1130 insertions(+), 1127 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/env.rs b/src/libstd/env.rs index c4946b6b282..320a9f935d4 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -552,17 +552,17 @@ pub fn home_dir() -> Option { /// /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx /// -/// ``` +/// ```no_run /// use std::env; /// use std::fs::File; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut dir = env::temp_dir(); -/// dir.push("foo.txt"); +/// fn main() -> std::io::Result<()> { +/// let mut dir = env::temp_dir(); +/// dir.push("foo.txt"); /// -/// let f = File::create(dir)?; -/// # Ok(()) -/// # } +/// let f = File::create(dir)?; +/// Ok(()) +/// } /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn temp_dir() -> PathBuf { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index db52ed67d3a..46d164e31ba 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -41,11 +41,11 @@ use time::SystemTime; /// use std::fs::File; /// use std::io::prelude::*; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut file = File::create("foo.txt")?; -/// file.write_all(b"Hello, world!")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let mut file = File::create("foo.txt")?; +/// file.write_all(b"Hello, world!")?; +/// Ok(()) +/// } /// ``` /// /// Read the contents of a file into a [`String`]: @@ -54,13 +54,13 @@ use time::SystemTime; /// use std::fs::File; /// use std::io::prelude::*; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut file = File::open("foo.txt")?; -/// let mut contents = String::new(); -/// file.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let mut file = File::open("foo.txt")?; +/// let mut contents = String::new(); +/// file.read_to_string(&mut contents)?; +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } /// ``` /// /// It can be more efficient to read the contents of a file with a buffered @@ -71,14 +71,14 @@ use time::SystemTime; /// use std::io::BufReader; /// use std::io::prelude::*; /// -/// # fn foo() -> std::io::Result<()> { -/// let file = File::open("foo.txt")?; -/// let mut buf_reader = BufReader::new(file); -/// let mut contents = String::new(); -/// buf_reader.read_to_string(&mut contents)?; -/// assert_eq!(contents, "Hello, world!"); -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let file = File::open("foo.txt")?; +/// let mut buf_reader = BufReader::new(file); +/// let mut contents = String::new(); +/// buf_reader.read_to_string(&mut contents)?; +/// assert_eq!(contents, "Hello, world!"); +/// Ok(()) +/// } /// ``` /// /// Note that, although read and write methods require a `&mut File`, because @@ -256,10 +256,10 @@ fn initial_buffer_size(file: &File) -> usize { /// use std::fs; /// use std::net::SocketAddr; /// -/// # fn foo() -> Result<(), Box> { -/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; -/// # Ok(()) -/// # } +/// fn main() -> Result<(), Box> { +/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; +/// Ok(()) +/// } /// ``` #[unstable(feature = "fs_read_write", issue = "46588")] pub fn read>(path: P) -> io::Result> { @@ -298,10 +298,10 @@ pub fn read>(path: P) -> io::Result> { /// use std::fs; /// use std::net::SocketAddr; /// -/// # fn foo() -> Result<(), Box> { -/// let foo: SocketAddr = fs::read_string("address.txt")?.parse()?; -/// # Ok(()) -/// # } +/// fn main() -> Result<(), Box> { +/// let foo: SocketAddr = fs::read_string("address.txt")?.parse()?; +/// Ok(()) +/// } /// ``` #[unstable(feature = "fs_read_write", issue = "46588")] pub fn read_string>(path: P) -> io::Result { @@ -329,10 +329,10 @@ pub fn read_string>(path: P) -> io::Result { /// /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::write("foo.txt", b"Lorem ipsum")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::write("foo.txt", b"Lorem ipsum")?; +/// Ok(()) +/// } /// ``` #[unstable(feature = "fs_read_write", issue = "46588")] pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { @@ -356,7 +356,7 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { + /// fn main() -> std::io::Result<()> { /// let mut f = File::open("foo.txt")?; /// # Ok(()) /// # } @@ -380,10 +380,10 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create>(path: P) -> io::Result { @@ -401,13 +401,13 @@ impl File { /// use std::fs::File; /// use std::io::prelude::*; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// f.write_all(b"Hello, world!")?; /// - /// f.sync_all()?; - /// # Ok(()) - /// # } + /// f.sync_all()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_all(&self) -> io::Result<()> { @@ -432,13 +432,13 @@ impl File { /// use std::fs::File; /// use std::io::prelude::*; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.write_all(b"Hello, world!")?; + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// f.write_all(b"Hello, world!")?; /// - /// f.sync_data()?; - /// # Ok(()) - /// # } + /// f.sync_data()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn sync_data(&self) -> io::Result<()> { @@ -466,11 +466,11 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// f.set_len(10)?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// f.set_len(10)?; + /// Ok(()) + /// } /// ``` /// /// Note that this method alters the content of the underlying file, even @@ -487,11 +487,11 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let metadata = f.metadata()?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let metadata = f.metadata()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata(&self) -> io::Result { @@ -509,11 +509,11 @@ impl File { /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let file_copy = file.try_clone()?; - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let file_copy = file.try_clone()?; + /// Ok(()) + /// } /// ``` /// /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create @@ -525,17 +525,17 @@ impl File { /// use std::io::SeekFrom; /// use std::io::prelude::*; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let mut file_copy = file.try_clone()?; + /// fn main() -> std::io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut file_copy = file.try_clone()?; /// - /// file.seek(SeekFrom::Start(3))?; + /// file.seek(SeekFrom::Start(3))?; /// - /// let mut contents = vec![]; - /// file_copy.read_to_end(&mut contents)?; - /// assert_eq!(contents, b"def\n"); - /// # Ok(()) - /// # } + /// let mut contents = vec![]; + /// file_copy.read_to_end(&mut contents)?; + /// assert_eq!(contents, b"def\n"); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_try_clone", since = "1.9.0")] pub fn try_clone(&self) -> io::Result { @@ -562,16 +562,16 @@ impl File { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs::File; - /// - /// let file = File::open("foo.txt")?; - /// let mut perms = file.metadata()?.permissions(); - /// perms.set_readonly(true); - /// file.set_permissions(perms)?; - /// # Ok(()) - /// # } + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs::File; + /// + /// let file = File::open("foo.txt")?; + /// let mut perms = file.metadata()?.permissions(); + /// perms.set_readonly(true); + /// file.set_permissions(perms)?; + /// Ok(()) + /// } /// ``` /// /// Note that this method alters the permissions of the underlying file, @@ -891,15 +891,15 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// let metadata = fs::metadata("foo.txt")?; /// - /// println!("{:?}", metadata.file_type()); - /// # Ok(()) - /// # } + /// println!("{:?}", metadata.file_type()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn file_type(&self) -> FileType { @@ -910,15 +910,15 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert!(!metadata.is_dir()); - /// # Ok(()) - /// # } + /// assert!(!metadata.is_dir()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_dir(&self) -> bool { self.file_type().is_dir() } @@ -927,15 +927,15 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert!(metadata.is_file()); - /// # Ok(()) - /// # } + /// assert!(metadata.is_file()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_file(&self) -> bool { self.file_type().is_file() } @@ -944,15 +944,15 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert_eq!(0, metadata.len()); - /// # Ok(()) - /// # } + /// assert_eq!(0, metadata.len()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> u64 { self.0.size() } @@ -961,15 +961,15 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// assert!(!metadata.permissions().readonly()); - /// # Ok(()) - /// # } + /// assert!(!metadata.permissions().readonly()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn permissions(&self) -> Permissions { @@ -988,19 +988,19 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// if let Ok(time) = metadata.modified() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); + /// if let Ok(time) = metadata.modified() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn modified(&self) -> io::Result { @@ -1023,19 +1023,19 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// if let Ok(time) = metadata.accessed() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); + /// if let Ok(time) = metadata.accessed() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn accessed(&self) -> io::Result { @@ -1054,19 +1054,19 @@ impl Metadata { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; /// - /// if let Ok(time) = metadata.created() { - /// println!("{:?}", time); - /// } else { - /// println!("Not supported on this platform"); + /// if let Ok(time) = metadata.created() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn created(&self) -> io::Result { @@ -1098,16 +1098,16 @@ impl Permissions { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; /// - /// assert_eq!(false, metadata.permissions().readonly()); - /// # Ok(()) - /// # } + /// assert_eq!(false, metadata.permissions().readonly()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn readonly(&self) -> bool { self.0.readonly() } @@ -1123,23 +1123,23 @@ impl Permissions { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let mut permissions = metadata.permissions(); /// - /// permissions.set_readonly(true); + /// permissions.set_readonly(true); /// - /// // filesystem doesn't change - /// assert_eq!(false, metadata.permissions().readonly()); + /// // filesystem doesn't change + /// assert_eq!(false, metadata.permissions().readonly()); /// - /// // just this particular `permissions`. - /// assert_eq!(true, permissions.readonly()); - /// # Ok(()) - /// # } + /// // just this particular `permissions`. + /// assert_eq!(true, permissions.readonly()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_readonly(&mut self, readonly: bool) { @@ -1152,16 +1152,16 @@ impl FileType { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); + /// let metadata = fs::metadata("foo.txt")?; + /// let file_type = metadata.file_type(); /// - /// assert_eq!(file_type.is_dir(), false); - /// # Ok(()) - /// # } + /// assert_eq!(file_type.is_dir(), false); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_dir(&self) -> bool { self.0.is_dir() } @@ -1170,16 +1170,16 @@ impl FileType { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { - /// use std::fs; + /// ```no_run + /// fn main() -> std::io::Result<()> { + /// use std::fs; /// - /// let metadata = fs::metadata("foo.txt")?; - /// let file_type = metadata.file_type(); + /// let metadata = fs::metadata("foo.txt")?; + /// let file_type = metadata.file_type(); /// - /// assert_eq!(file_type.is_file(), true); - /// # Ok(()) - /// # } + /// assert_eq!(file_type.is_file(), true); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_file(&self) -> bool { self.0.is_file() } @@ -1199,16 +1199,16 @@ impl FileType { /// /// # Examples /// - /// ``` - /// # fn foo() -> std::io::Result<()> { + /// ```no_run /// use std::fs; /// - /// let metadata = fs::symlink_metadata("foo.txt")?; - /// let file_type = metadata.file_type(); + /// fn main() -> std::io::Result<()> { + /// let metadata = fs::symlink_metadata("foo.txt")?; + /// let file_type = metadata.file_type(); /// - /// assert_eq!(file_type.is_symlink(), false); - /// # Ok(()) - /// # } + /// assert_eq!(file_type.is_symlink(), false); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_symlink(&self) -> bool { self.0.is_symlink() } @@ -1245,15 +1245,16 @@ impl DirEntry { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; - /// # fn foo() -> std::io::Result<()> { - /// for entry in fs::read_dir(".")? { - /// let dir = entry?; - /// println!("{:?}", dir.path()); + /// + /// fn main() -> std::io::Result<()> { + /// for entry in fs::read_dir(".")? { + /// let dir = entry?; + /// println!("{:?}", dir.path()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` /// /// This prints output like: @@ -1398,13 +1399,13 @@ impl AsInner for DirEntry { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::remove_file("a.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::remove_file("a.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_file>(path: P) -> io::Result<()> { @@ -1435,14 +1436,14 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ```rust -/// # fn foo() -> std::io::Result<()> { +/// ```rust,no_run /// use std::fs; /// -/// let attr = fs::metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let attr = fs::metadata("/some/file/path.txt")?; +/// // inspect attr ... +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata>(path: P) -> io::Result { @@ -1469,14 +1470,14 @@ pub fn metadata>(path: P) -> io::Result { /// /// # Examples /// -/// ```rust -/// # fn foo() -> std::io::Result<()> { +/// ```rust,no_run /// use std::fs; /// -/// let attr = fs::symlink_metadata("/some/file/path.txt")?; -/// // inspect attr ... -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let attr = fs::symlink_metadata("/some/file/path.txt")?; +/// // inspect attr ... +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink_metadata", since = "1.1.0")] pub fn symlink_metadata>(path: P) -> io::Result { @@ -1513,13 +1514,13 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::rename("a.txt", "b.txt")?; // Rename a.txt to b.txt +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { @@ -1564,9 +1565,10 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt -/// # Ok(()) } +/// fn main() -> std::io::Result<()> { +/// fs::copy("foo.txt", "bar.txt")?; // Copy foo.txt to bar.txt +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { @@ -1595,13 +1597,13 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::hard_link("a.txt", "b.txt")?; // Hard link a.txt to b.txt +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { @@ -1618,13 +1620,13 @@ pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::soft_link("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::soft_link("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.1.0", @@ -1655,13 +1657,13 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// let path = fs::read_link("a.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let path = fs::read_link("a.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn read_link>(path: P) -> io::Result { @@ -1689,13 +1691,13 @@ pub fn read_link>(path: P) -> io::Result { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// let path = fs::canonicalize("../a/../foo.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let path = fs::canonicalize("../a/../foo.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "fs_canonicalize", since = "1.5.0")] pub fn canonicalize>(path: P) -> io::Result { @@ -1722,13 +1724,13 @@ pub fn canonicalize>(path: P) -> io::Result { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::create_dir("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::create_dir("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir>(path: P) -> io::Result<()> { @@ -1764,13 +1766,13 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::create_dir_all("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::create_dir_all("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir_all>(path: P) -> io::Result<()> { @@ -1797,13 +1799,13 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::remove_dir("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::remove_dir("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir>(path: P) -> io::Result<()> { @@ -1831,13 +1833,13 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::remove_dir_all("/some/dir")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::remove_dir_all("/some/dir")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir_all>(path: P) -> io::Result<()> { @@ -1917,15 +1919,15 @@ pub fn read_dir>(path: P) -> io::Result { /// /// # Examples /// -/// ``` -/// # fn foo() -> std::io::Result<()> { +/// ```no_run /// use std::fs; /// -/// let mut perms = fs::metadata("foo.txt")?.permissions(); -/// perms.set_readonly(true); -/// fs::set_permissions("foo.txt", perms)?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// let mut perms = fs::metadata("foo.txt")?.permissions(); +/// perms.set_readonly(true); +/// fs::set_permissions("foo.txt", perms)?; +/// Ok(()) +/// } /// ``` #[stable(feature = "set_permissions", since = "1.1.0")] pub fn set_permissions>(path: P, perm: Permissions) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index ccaa19acc83..cefff2f143c 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -31,20 +31,20 @@ use memchr; /// /// # Examples /// -/// ``` +/// ```no_run /// use std::io::prelude::*; /// use std::io::BufReader; /// use std::fs::File; /// -/// # fn foo() -> std::io::Result<()> { -/// let f = File::open("log.txt")?; -/// let mut reader = BufReader::new(f); +/// fn main() -> std::io::Result<()> { +/// let f = File::open("log.txt")?; +/// let mut reader = BufReader::new(f); /// -/// let mut line = String::new(); -/// let len = reader.read_line(&mut line)?; -/// println!("First line is {} bytes long", len); -/// # Ok(()) -/// # } +/// let mut line = String::new(); +/// let len = reader.read_line(&mut line)?; +/// println!("First line is {} bytes long", len); +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct BufReader { @@ -59,15 +59,15 @@ impl BufReader { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::new(f); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::new(f); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: R) -> BufReader { @@ -80,15 +80,15 @@ impl BufReader { /// /// Creating a buffer with ten bytes of capacity: /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::with_capacity(10, f); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::with_capacity(10, f); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: R) -> BufReader { @@ -111,17 +111,17 @@ impl BufReader { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); /// - /// let f2 = reader.get_ref(); - /// # Ok(()) - /// # } + /// let f2 = reader.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &R { &self.inner } @@ -132,17 +132,17 @@ impl BufReader { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let mut reader = BufReader::new(f1); /// - /// let f2 = reader.get_mut(); - /// # Ok(()) - /// # } + /// let f2 = reader.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } @@ -150,22 +150,23 @@ impl BufReader { /// Returns `true` if there are no bytes in the internal buffer. /// /// # Examples - /// ``` + // + /// ```no_run /// # #![feature(bufreader_is_empty)] /// use std::io::BufReader; /// use std::io::BufRead; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// assert!(reader.is_empty()); + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let mut reader = BufReader::new(f1); + /// assert!(reader.is_empty()); /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.is_empty()); + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.is_empty()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")] #[rustc_deprecated(since = "1.26.0", reason = "use .buffer().is_empty() instead")] @@ -179,21 +180,21 @@ impl BufReader { /// /// # Examples /// - /// ``` + /// ```no_ru /// # #![feature(bufreader_buffer)] /// use std::io::{BufReader, BufRead}; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// assert!(reader.buffer().is_empty()); + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// assert!(reader.buffer().is_empty()); /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.buffer().is_empty()); + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.buffer().is_empty()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[unstable(feature = "bufreader_buffer", issue = "45323")] pub fn buffer(&self) -> &[u8] { @@ -206,17 +207,17 @@ impl BufReader { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::BufReader; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); /// - /// let f2 = reader.into_inner(); - /// # Ok(()) - /// # } + /// let f2 = reader.into_inner(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> R { self.inner } @@ -724,34 +725,34 @@ impl fmt::Display for IntoInnerError { /// We can use `LineWriter` to write one line at a time, significantly /// reducing the number of actual writes to the file. /// -/// ``` +/// ```no_run /// use std::fs::File; /// use std::io::prelude::*; /// use std::io::LineWriter; /// -/// # fn foo() -> std::io::Result<()> { -/// let road_not_taken = b"I shall be telling this with a sigh +/// fn main() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh /// Somewhere ages and ages hence: /// Two roads diverged in a wood, and I - /// I took the one less traveled by, /// And that has made all the difference."; /// -/// let file = File::create("poem.txt")?; -/// let mut file = LineWriter::new(file); +/// let file = File::create("poem.txt")?; +/// let mut file = LineWriter::new(file); /// -/// for &byte in road_not_taken.iter() { -/// file.write(&[byte]).unwrap(); -/// } +/// for &byte in road_not_taken.iter() { +/// file.write(&[byte]).unwrap(); +/// } /// -/// // let's check we did the right thing. -/// let mut file = File::open("poem.txt")?; -/// let mut contents = String::new(); +/// // let's check we did the right thing. +/// let mut file = File::open("poem.txt")?; +/// let mut contents = String::new(); /// -/// file.read_to_string(&mut contents)?; +/// file.read_to_string(&mut contents)?; /// -/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); -/// # Ok(()) -/// # } +/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { @@ -764,15 +765,15 @@ impl LineWriter { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> LineWriter { @@ -785,15 +786,15 @@ impl LineWriter { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::with_capacity(100, file); - /// # Ok(()) - /// # } + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::with_capacity(100, file); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> LineWriter { @@ -807,17 +808,17 @@ impl LineWriter { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); /// - /// let reference = file.get_ref(); - /// # Ok(()) - /// # } + /// let reference = file.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.get_ref() } @@ -829,18 +830,18 @@ impl LineWriter { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let mut file = LineWriter::new(file); + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let mut file = LineWriter::new(file); /// - /// // we can use reference just like file - /// let reference = file.get_mut(); - /// # Ok(()) - /// # } + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } @@ -855,18 +856,18 @@ impl LineWriter { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs::File; /// use std::io::LineWriter; /// - /// # fn foo() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; /// - /// let writer: LineWriter = LineWriter::new(file); + /// let writer: LineWriter = LineWriter::new(file); /// - /// let file: File = writer.into_inner()?; - /// # Ok(()) - /// # } + /// let file: File = writer.into_inner()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index d403bf6bfe5..63b631ace96 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -24,21 +24,21 @@ //! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on //! [`File`]s: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let mut f = File::open("foo.txt")?; -//! let mut buffer = [0; 10]; +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; //! -//! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! // read up to 10 bytes +//! f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); -//! # Ok(()) -//! # } +//! println!("The bytes: {:?}", buffer); +//! Ok(()) +//! } //! ``` //! //! [`Read`] and [`Write`] are so important, implementors of the two traits have a @@ -52,25 +52,25 @@ //! how the reading happens. [`Seek`] lets you control where the next byte is //! coming from: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::SeekFrom; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let mut f = File::open("foo.txt")?; -//! let mut buffer = [0; 10]; +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; //! -//! // skip to the last 10 bytes of the file -//! f.seek(SeekFrom::End(-10))?; +//! // skip to the last 10 bytes of the file +//! f.seek(SeekFrom::End(-10))?; //! -//! // read up to 10 bytes -//! f.read(&mut buffer)?; +//! // read up to 10 bytes +//! f.read(&mut buffer)?; //! -//! println!("The bytes: {:?}", buffer); -//! # Ok(()) -//! # } +//! println!("The bytes: {:?}", buffer); +//! Ok(()) +//! } //! ``` //! //! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but @@ -87,70 +87,70 @@ //! For example, [`BufReader`] works with the [`BufRead`] trait to add extra //! methods to any reader: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::BufReader; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let f = File::open("foo.txt")?; -//! let mut reader = BufReader::new(f); -//! let mut buffer = String::new(); +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); //! -//! // read a line into buffer -//! reader.read_line(&mut buffer)?; +//! // read a line into buffer +//! reader.read_line(&mut buffer)?; //! -//! println!("{}", buffer); -//! # Ok(()) -//! # } +//! println!("{}", buffer); +//! Ok(()) +//! } //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call //! to [`write`][`Write::write`]: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::BufWriter; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let f = File::create("foo.txt")?; -//! { -//! let mut writer = BufWriter::new(f); +//! fn main() -> io::Result<()> { +//! let f = File::create("foo.txt")?; +//! { +//! let mut writer = BufWriter::new(f); //! -//! // write a byte to the buffer -//! writer.write(&[42])?; +//! // write a byte to the buffer +//! writer.write(&[42])?; //! -//! } // the buffer is flushed once writer goes out of scope +//! } // the buffer is flushed once writer goes out of scope //! -//! # Ok(()) -//! # } +//! Ok(()) +//! } //! ``` //! //! ## Standard input and output //! //! A very common source of input is standard input: //! -//! ``` +//! ```no_run //! use std::io; //! -//! # fn foo() -> io::Result<()> { -//! let mut input = String::new(); +//! fn main() -> io::Result<()> { +//! let mut input = String::new(); //! -//! io::stdin().read_line(&mut input)?; +//! io::stdin().read_line(&mut input)?; //! -//! println!("You typed: {}", input.trim()); -//! # Ok(()) -//! # } +//! println!("You typed: {}", input.trim()); +//! Ok(()) +//! } //! ``` //! //! Note that you cannot use the [`?` operator] in functions that do not return //! a [`Result`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`] //! or `match` on the return value to catch any possible errors: //! -//! ``` +//! ```no_run //! use std::io; //! //! let mut input = String::new(); @@ -160,14 +160,14 @@ //! //! And a very common source of output is standard output: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! -//! # fn foo() -> io::Result<()> { -//! io::stdout().write(&[42])?; -//! # Ok(()) -//! # } +//! fn main() -> io::Result<()> { +//! io::stdout().write(&[42])?; +//! Ok(()) +//! } //! ``` //! //! Of course, using [`io::stdout`] directly is less common than something like @@ -179,22 +179,21 @@ //! ways of iterating over I/O. For example, [`Lines`] is used to split over //! lines: //! -//! ``` +//! ```no_run //! use std::io; //! use std::io::prelude::*; //! use std::io::BufReader; //! use std::fs::File; //! -//! # fn foo() -> io::Result<()> { -//! let f = File::open("foo.txt")?; -//! let reader = BufReader::new(f); +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let reader = BufReader::new(f); //! -//! for line in reader.lines() { -//! println!("{}", line?); +//! for line in reader.lines() { +//! println!("{}", line?); +//! } +//! Ok(()) //! } -//! -//! # Ok(()) -//! # } //! ``` //! //! ## Functions @@ -203,13 +202,13 @@ //! features. For example, we can use three of these functions to copy everything //! from standard input to standard output: //! -//! ``` +//! ```no_run //! use std::io; //! -//! # fn foo() -> io::Result<()> { -//! io::copy(&mut io::stdin(), &mut io::stdout())?; -//! # Ok(()) -//! # } +//! fn main() -> io::Result<()> { +//! io::copy(&mut io::stdin(), &mut io::stdout())?; +//! Ok(()) +//! } //! ``` //! //! [functions-list]: #functions-1 @@ -416,47 +415,47 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result /// /// [`File`]s implement `Read`: /// -/// ``` -/// # use std::io; +/// ```no_run +/// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// -/// # fn foo() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; -/// let mut buffer = [0; 10]; +/// fn main() -> io::Result<()> { +/// let mut f = File::open("foo.txt")?; +/// let mut buffer = [0; 10]; /// -/// // read up to 10 bytes -/// f.read(&mut buffer)?; +/// // read up to 10 bytes +/// f.read(&mut buffer)?; /// -/// let mut buffer = vec![0; 10]; -/// // read the whole file -/// f.read_to_end(&mut buffer)?; +/// let mut buffer = vec![0; 10]; +/// // read the whole file +/// f.read_to_end(&mut buffer)?; /// -/// // read into a String, so that you don't need to do the conversion. -/// let mut buffer = String::new(); -/// f.read_to_string(&mut buffer)?; +/// // read into a String, so that you don't need to do the conversion. +/// let mut buffer = String::new(); +/// f.read_to_string(&mut buffer)?; /// -/// // and more! See the other methods for more details. -/// # Ok(()) -/// # } +/// // and more! See the other methods for more details. +/// Ok(()) +/// } /// ``` /// /// Read from [`&str`] because [`&[u8]`][slice] implements `Read`: /// -/// ``` +/// ```no_run /// # use std::io; /// use std::io::prelude::*; /// -/// # fn foo() -> io::Result<()> { -/// let mut b = "This string will be read".as_bytes(); -/// let mut buffer = [0; 10]; +/// fn main() -> io::Result<()> { +/// let mut b = "This string will be read".as_bytes(); +/// let mut buffer = [0; 10]; /// -/// // read up to 10 bytes -/// b.read(&mut buffer)?; +/// // read up to 10 bytes +/// b.read(&mut buffer)?; /// -/// // etc... it works exactly as a File does! -/// # Ok(()) -/// # } +/// // etc... it works exactly as a File does! +/// Ok(()) +/// } /// ``` /// /// [`read()`]: trait.Read.html#tymethod.read @@ -509,19 +508,19 @@ pub trait Read { /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted /// [`File`]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; /// - /// // read up to 10 bytes - /// f.read(&mut buffer[..])?; - /// # Ok(()) - /// # } + /// // read up to 10 bytes + /// f.read(&mut buffer[..])?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result; @@ -582,19 +581,19 @@ pub trait Read { /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted /// [`File`]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = Vec::new(); /// - /// // read the whole file - /// f.read_to_end(&mut buffer)?; - /// # Ok(()) - /// # } + /// // read the whole file + /// f.read_to_end(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec) -> Result { @@ -621,18 +620,18 @@ pub trait Read { /// /// [file]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = String::new(); + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = String::new(); /// - /// f.read_to_string(&mut buffer)?; - /// # Ok(()) - /// # } + /// f.read_to_string(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_to_string(&mut self, buf: &mut String) -> Result { @@ -683,19 +682,19 @@ pub trait Read { /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; /// - /// // read exactly 10 bytes - /// f.read_exact(&mut buffer)?; - /// # Ok(()) - /// # } + /// // read exactly 10 bytes + /// f.read_exact(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "read_exact", since = "1.6.0")] fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { @@ -726,28 +725,28 @@ pub trait Read { /// /// [file]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::Read; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = Vec::new(); - /// let mut other_buffer = Vec::new(); + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = Vec::new(); + /// let mut other_buffer = Vec::new(); /// - /// { - /// let reference = f.by_ref(); + /// { + /// let reference = f.by_ref(); /// - /// // read at most 5 bytes - /// reference.take(5).read_to_end(&mut buffer)?; + /// // read at most 5 bytes + /// reference.take(5).read_to_end(&mut buffer)?; /// - /// } // drop our &mut reference so we can use f again + /// } // drop our &mut reference so we can use f again /// - /// // original file still usable, read the rest - /// f.read_to_end(&mut other_buffer)?; - /// # Ok(()) - /// # } + /// // original file still usable, read the rest + /// f.read_to_end(&mut other_buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } @@ -772,19 +771,19 @@ pub trait Read { /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// [`None`]: ../../std/option/enum.Option.html#variant.None /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; /// - /// for byte in f.bytes() { - /// println!("{}", byte.unwrap()); + /// for byte in f.bytes() { + /// println!("{}", byte.unwrap()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn bytes(self) -> Bytes where Self: Sized { @@ -812,20 +811,20 @@ pub trait Read { /// [`char`]: ../../std/primitive.char.html /// [`None`]: ../../std/option/enum.Option.html#variant.None /// - /// ``` + /// ```no_run /// #![feature(io)] /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; /// - /// for c in f.chars() { - /// println!("{}", c.unwrap()); + /// for c in f.chars() { + /// println!("{}", c.unwrap()); + /// } + /// Ok(()) /// } - /// # Ok(()) - /// # } /// ``` #[unstable(feature = "io", reason = "the semantics of a partial read/write \ of where errors happen is currently \ @@ -847,23 +846,23 @@ pub trait Read { /// /// [file]: ../fs/struct.File.html /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f1 = File::open("foo.txt")?; - /// let mut f2 = File::open("bar.txt")?; + /// fn main() -> io::Result<()> { + /// let mut f1 = File::open("foo.txt")?; + /// let mut f2 = File::open("bar.txt")?; /// - /// let mut handle = f1.chain(f2); - /// let mut buffer = String::new(); + /// let mut handle = f1.chain(f2); + /// let mut buffer = String::new(); /// - /// // read the value into a String. We could use any Read method here, - /// // this is just one example. - /// handle.read_to_string(&mut buffer)?; - /// # Ok(()) - /// # } + /// // read the value into a String. We could use any Read method here, + /// // this is just one example. + /// handle.read_to_string(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn chain(self, next: R) -> Chain where Self: Sized { @@ -885,21 +884,21 @@ pub trait Read { /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok /// [`read()`]: trait.Read.html#tymethod.read /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// let mut buffer = [0; 5]; + /// fn main() -> io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// let mut buffer = [0; 5]; /// - /// // read at most five bytes - /// let mut handle = f.take(5); + /// // read at most five bytes + /// let mut handle = f.take(5); /// - /// handle.read(&mut buffer)?; - /// # Ok(()) - /// # } + /// handle.read(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn take(self, limit: u64) -> Take where Self: Sized { @@ -974,16 +973,16 @@ impl Initializer { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// -/// # fn foo() -> std::io::Result<()> { -/// let mut buffer = File::create("foo.txt")?; +/// fn main() -> std::io::Result<()> { +/// let mut buffer = File::create("foo.txt")?; /// -/// buffer.write(b"some bytes")?; -/// # Ok(()) -/// # } +/// buffer.write(b"some bytes")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[doc(spotlight)] @@ -1022,17 +1021,17 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// // Writes some prefix of the byte string, not necessarily all of it. - /// buffer.write(b"some bytes")?; - /// # Ok(()) - /// # } + /// // Writes some prefix of the byte string, not necessarily all of it. + /// buffer.write(b"some bytes")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, buf: &[u8]) -> Result; @@ -1047,18 +1046,18 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::io::BufWriter; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = BufWriter::new(File::create("foo.txt")?); + /// fn main() -> std::io::Result<()> { + /// let mut buffer = BufWriter::new(File::create("foo.txt")?); /// - /// buffer.write(b"some bytes")?; - /// buffer.flush()?; - /// # Ok(()) - /// # } + /// buffer.write(b"some bytes")?; + /// buffer.flush()?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn flush(&mut self) -> Result<()>; @@ -1082,16 +1081,16 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// buffer.write_all(b"some bytes")?; - /// # Ok(()) - /// # } + /// buffer.write_all(b"some bytes")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { @@ -1131,19 +1130,19 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// // this call - /// write!(buffer, "{:.*}", 2, 1.234567)?; - /// // turns into this: - /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; - /// # Ok(()) - /// # } + /// // this call + /// write!(buffer, "{:.*}", 2, 1.234567)?; + /// // turns into this: + /// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { @@ -1187,19 +1186,19 @@ pub trait Write { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::Write; /// use std::fs::File; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// let reference = buffer.by_ref(); + /// let reference = buffer.by_ref(); /// - /// // we can use reference just like our original buffer - /// reference.write_all(b"some bytes")?; - /// # Ok(()) - /// # } + /// // we can use reference just like our original buffer + /// reference.write_all(b"some bytes")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } @@ -1217,19 +1216,19 @@ pub trait Write { /// /// [file]: ../fs/struct.File.html /// -/// ``` +/// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// use std::io::SeekFrom; /// -/// # fn foo() -> io::Result<()> { -/// let mut f = File::open("foo.txt")?; +/// fn main() -> io::Result<()> { +/// let mut f = File::open("foo.txt")?; /// -/// // move the cursor 42 bytes from the start of the file -/// f.seek(SeekFrom::Start(42))?; -/// # Ok(()) -/// # } +/// // move the cursor 42 bytes from the start of the file +/// f.seek(SeekFrom::Start(42))?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Seek { @@ -1320,7 +1319,7 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// /// A locked standard input implements `BufRead`: /// -/// ``` +/// ```no_run /// use std::io; /// use std::io::prelude::*; /// @@ -1342,21 +1341,21 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// [`lines`]: #method.lines /// [`Read`]: trait.Read.html /// -/// ``` +/// ```no_run /// use std::io::{self, BufReader}; /// use std::io::prelude::*; /// use std::fs::File; /// -/// # fn foo() -> io::Result<()> { -/// let f = File::open("foo.txt")?; -/// let f = BufReader::new(f); +/// fn main() -> io::Result<()> { +/// let f = File::open("foo.txt")?; +/// let f = BufReader::new(f); /// -/// for line in f.lines() { -/// println!("{}", line.unwrap()); -/// } +/// for line in f.lines() { +/// println!("{}", line.unwrap()); +/// } /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` /// #[stable(feature = "rust1", since = "1.0.0")] @@ -1383,7 +1382,7 @@ pub trait BufRead: Read { /// /// A locked standard input implements `BufRead`: /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// @@ -1645,19 +1644,19 @@ impl Chain { /// /// # Examples /// - /// ``` - /// # use std::io; + /// ```no_run + /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; + /// fn main() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; /// - /// let chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.into_inner(); - /// # Ok(()) - /// # } + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.into_inner(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn into_inner(self) -> (T, U) { @@ -1668,19 +1667,19 @@ impl Chain { /// /// # Examples /// - /// ``` - /// # use std::io; + /// ```no_run + /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; + /// fn main() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; /// - /// let chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.get_ref(); - /// # Ok(()) - /// # } + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_ref(&self) -> (&T, &U) { @@ -1695,19 +1694,19 @@ impl Chain { /// /// # Examples /// - /// ``` - /// # use std::io; + /// ```no_run + /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut foo_file = File::open("foo.txt")?; - /// let mut bar_file = File::open("bar.txt")?; + /// fn main() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; /// - /// let mut chain = foo_file.chain(bar_file); - /// let (foo_file, bar_file) = chain.get_mut(); - /// # Ok(()) - /// # } + /// let mut chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_mut(&mut self) -> (&mut T, &mut U) { @@ -1794,20 +1793,20 @@ impl Take { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let f = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let f = File::open("foo.txt")?; /// - /// // read at most five bytes - /// let handle = f.take(5); + /// // read at most five bytes + /// let handle = f.take(5); /// - /// println!("limit: {}", handle.limit()); - /// # Ok(()) - /// # } + /// println!("limit: {}", handle.limit()); + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn limit(&self) -> u64 { self.limit } @@ -1819,22 +1818,22 @@ impl Take { /// /// # Examples /// - /// ``` + /// ```no_run /// #![feature(take_set_limit)] /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let f = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let f = File::open("foo.txt")?; /// - /// // read at most five bytes - /// let mut handle = f.take(5); - /// handle.set_limit(10); + /// // read at most five bytes + /// let mut handle = f.take(5); + /// handle.set_limit(10); /// - /// assert_eq!(handle.limit(), 10); - /// # Ok(()) - /// # } + /// assert_eq!(handle.limit(), 10); + /// Ok(()) + /// } /// ``` #[unstable(feature = "take_set_limit", issue = "42781")] pub fn set_limit(&mut self, limit: u64) { @@ -1845,21 +1844,21 @@ impl Take { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; /// - /// let file = handle.into_inner(); - /// # Ok(()) - /// # } + /// let file = handle.into_inner(); + /// Ok(()) + /// } /// ``` #[stable(feature = "io_take_into_inner", since = "1.15.0")] pub fn into_inner(self) -> T { @@ -1870,21 +1869,21 @@ impl Take { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; /// - /// let file = handle.get_ref(); - /// # Ok(()) - /// # } + /// let file = handle.get_ref(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_ref(&self) -> &T { @@ -1899,21 +1898,21 @@ impl Take { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; /// - /// # fn foo() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; /// - /// let mut buffer = [0; 5]; - /// let mut handle = file.take(5); - /// handle.read(&mut buffer)?; + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; /// - /// let file = handle.get_mut(); - /// # Ok(()) - /// # } + /// let file = handle.get_mut(); + /// Ok(()) + /// } /// ``` #[stable(feature = "more_io_inner_methods", since = "1.20.0")] pub fn get_mut(&mut self) -> &mut T { diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 1f73054e3be..2472bed5ba4 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -171,29 +171,29 @@ pub struct StdinLock<'a> { /// /// Using implicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Read}; /// -/// # fn foo() -> io::Result { -/// let mut buffer = String::new(); -/// io::stdin().read_to_string(&mut buffer)?; -/// # Ok(buffer) -/// # } +/// fn main() -> io::Result<()> { +/// let mut buffer = String::new(); +/// io::stdin().read_to_string(&mut buffer)?; +/// Ok(()) +/// } /// ``` /// /// Using explicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Read}; /// -/// # fn foo() -> io::Result { -/// let mut buffer = String::new(); -/// let stdin = io::stdin(); -/// let mut handle = stdin.lock(); +/// fn main() -> io::Result<()> { +/// let mut buffer = String::new(); +/// let stdin = io::stdin(); +/// let mut handle = stdin.lock(); /// -/// handle.read_to_string(&mut buffer)?; -/// # Ok(buffer) -/// # } +/// handle.read_to_string(&mut buffer)?; +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { @@ -225,17 +225,17 @@ impl Stdin { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::{self, Read}; /// - /// # fn foo() -> io::Result { - /// let mut buffer = String::new(); - /// let stdin = io::stdin(); - /// let mut handle = stdin.lock(); + /// fn main() -> io::Result<()> { + /// let mut buffer = String::new(); + /// let stdin = io::stdin(); + /// let mut handle = stdin.lock(); /// - /// handle.read_to_string(&mut buffer)?; - /// # Ok(buffer) - /// # } + /// handle.read_to_string(&mut buffer)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdinLock { @@ -369,29 +369,29 @@ pub struct StdoutLock<'a> { /// /// Using implicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// io::stdout().write(b"hello world")?; +/// fn main() -> io::Result<()> { +/// io::stdout().write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` /// /// Using explicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// let stdout = io::stdout(); -/// let mut handle = stdout.lock(); +/// fn main() -> io::Result<()> { +/// let stdout = io::stdout(); +/// let mut handle = stdout.lock(); /// -/// handle.write(b"hello world")?; +/// handle.write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { @@ -419,17 +419,17 @@ impl Stdout { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::io::{self, Write}; /// - /// # fn foo() -> io::Result<()> { - /// let stdout = io::stdout(); - /// let mut handle = stdout.lock(); + /// fn main() -> io::Result<()> { + /// let stdout = io::stdout(); + /// let mut handle = stdout.lock(); /// - /// handle.write(b"hello world")?; + /// handle.write(b"hello world")?; /// - /// # Ok(()) - /// # } + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdoutLock { @@ -505,29 +505,29 @@ pub struct StderrLock<'a> { /// /// Using implicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// io::stderr().write(b"hello world")?; +/// fn main() -> io::Result<()> { +/// io::stderr().write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` /// /// Using explicit synchronization: /// -/// ``` +/// ```no_run /// use std::io::{self, Write}; /// -/// # fn foo() -> io::Result<()> { -/// let stderr = io::stderr(); -/// let mut handle = stderr.lock(); +/// fn main() -> io::Result<()> { +/// let stderr = io::stderr(); +/// let mut handle = stderr.lock(); /// -/// handle.write(b"hello world")?; +/// handle.write(b"hello world")?; /// -/// # Ok(()) -/// # } +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 45d281ee34a..195310a26fe 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -34,16 +34,15 @@ use mem; /// ``` /// use std::io; /// -/// # fn foo() -> io::Result<()> { -/// let mut reader: &[u8] = b"hello"; -/// let mut writer: Vec = vec![]; +/// fn main() -> io::Result<()> { +/// let mut reader: &[u8] = b"hello"; +/// let mut writer: Vec = vec![]; /// -/// io::copy(&mut reader, &mut writer)?; +/// io::copy(&mut reader, &mut writer)?; /// -/// assert_eq!(&b"hello"[..], &writer[..]); -/// # Ok(()) -/// # } -/// # foo().unwrap(); +/// assert_eq!(&b"hello"[..], &writer[..]); +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn copy(reader: &mut R, writer: &mut W) -> io::Result diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index eef043683b0..b0d5e563cb9 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -175,12 +175,12 @@ impl fmt::Debug for LookupHost { /// /// use std::net; /// -/// # fn foo() -> std::io::Result<()> { -/// for host in net::lookup_host("rust-lang.org")? { -/// println!("found address: {}", host); +/// fn main() -> std::io::Result<()> { +/// for host in net::lookup_host("rust-lang.org")? { +/// println!("found address: {}", host); +/// } +/// Ok(()) /// } -/// # Ok(()) -/// # } /// ``` #[unstable(feature = "lookup_host", reason = "unsure about the returned \ iterator and returning socket \ diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index e28ccdb766a..0f60b5b3ee4 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -72,7 +72,7 @@ pub struct TcpStream(net_imp::TcpStream); /// /// # Examples /// -/// ``` +/// ```no_run /// # use std::io; /// use std::net::{TcpListener, TcpStream}; /// @@ -80,15 +80,15 @@ pub struct TcpStream(net_imp::TcpStream); /// // ... /// } /// -/// # fn process() -> io::Result<()> { -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// fn main() -> io::Result<()> { +/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); /// -/// // accept connections and process them serially -/// for stream in listener.incoming() { -/// handle_client(stream?); +/// // accept connections and process them serially +/// for stream in listener.incoming() { +/// handle_client(stream?); +/// } +/// Ok(()) /// } -/// # Ok(()) -/// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct TcpListener(net_imp::TcpListener); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 8e56954bea4..d25e29999cb 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -44,22 +44,22 @@ use time::Duration; /// ```no_run /// use std::net::UdpSocket; /// -/// # fn foo() -> std::io::Result<()> { -/// { -/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; +/// fn main() -> std::io::Result<()> { +/// { +/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?; /// -/// // Receives a single datagram message on the socket. If `buf` is too small to hold -/// // the message, it will be cut off. -/// let mut buf = [0; 10]; -/// let (amt, src) = socket.recv_from(&mut buf)?; +/// // Receives a single datagram message on the socket. If `buf` is too small to hold +/// // the message, it will be cut off. +/// let mut buf = [0; 10]; +/// let (amt, src) = socket.recv_from(&mut buf)?; /// -/// // Redeclare `buf` as slice of the received data and send reverse data back to origin. -/// let buf = &mut buf[..amt]; -/// buf.reverse(); -/// socket.send_to(buf, &src)?; -/// # Ok(()) -/// } // the socket is closed here -/// # } +/// // Redeclare `buf` as slice of the received data and send reverse data back to origin. +/// let buf = &mut buf[..amt]; +/// buf.reverse(); +/// socket.send_to(buf, &src)?; +/// } // the socket is closed here +/// Ok(()) +/// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct UdpSocket(net_imp::UdpSocket); diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index 5d37d970e89..2be2fbcb2db 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -32,16 +32,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let stat = meta.as_raw_stat(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let stat = meta.as_raw_stat(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] #[rustc_deprecated(since = "1.8.0", @@ -54,16 +54,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_dev()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_dev(&self) -> u64; @@ -71,16 +71,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ino()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ino(&self) -> u64; @@ -88,16 +88,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mode()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mode(&self) -> u32; @@ -105,16 +105,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_nlink()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_nlink(&self) -> u64; @@ -122,16 +122,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_uid()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_uid(&self) -> u32; @@ -139,16 +139,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_gid()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_gid(&self) -> u32; @@ -156,16 +156,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_rdev()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_rdev(&self) -> u64; @@ -176,16 +176,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_size()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_size(&self) -> u64; @@ -193,16 +193,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; @@ -210,16 +210,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_atime_nsec()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime_nsec(&self) -> i64; @@ -227,16 +227,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; @@ -244,16 +244,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_mtime_nsec()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime_nsec(&self) -> i64; @@ -261,16 +261,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; @@ -278,16 +278,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_ctime_nsec()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime_nsec(&self) -> i64; @@ -295,16 +295,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blksize()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; @@ -312,16 +312,16 @@ pub trait MetadataExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; + /// use std::io; /// use std::os::linux::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// println!("{}", meta.st_blocks()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 5d4edc2cf92..0f4762aa881 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -30,13 +30,14 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::redox::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let permissions = metadata.permissions(); /// - /// println!("permissions: {}", permissions.mode()); - /// # Ok(()) } + /// println!("permissions: {}", permissions.mode()); + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -49,14 +50,15 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::redox::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let mut permissions = metadata.permissions(); /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// # Ok(()) } + /// permissions.set_mode(0o644); // Read/write for owner and read for others. + /// assert_eq!(permissions.mode(), 0o644); + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); @@ -291,13 +293,13 @@ impl FileTypeExt for fs::FileType { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::os::redox::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 2e17fd58e0a..3c5b9424fb0 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -41,20 +41,20 @@ pub trait FileExt { /// /// # Examples /// - /// ``` - /// use std::os::unix::prelude::FileExt; + /// ```no_run + /// use std::io; /// use std::fs::File; + /// use std::os::unix::prelude::FileExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let mut buf = [0u8; 8]; + /// let file = File::open("foo.txt")?; /// - /// // We now read 8 bytes from the offset 10. - /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); - /// # Ok(()) - /// # } + /// // We now read 8 bytes from the offset 10. + /// let num_bytes_read = file.read_at(&mut buf, 10)?; + /// println!("read {} bytes: {:?}", num_bytes_read, buf); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; @@ -78,18 +78,18 @@ pub trait FileExt { /// /// # Examples /// - /// ``` - /// use std::os::unix::prelude::FileExt; + /// ```no_run /// use std::fs::File; + /// use std::io; + /// use std::os::unix::prelude::FileExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let file = File::open("foo.txt")?; + /// fn main() -> io::Result<()> { + /// let file = File::open("foo.txt")?; /// - /// // We now write at the offset 10. - /// file.write_at(b"sushi", 10)?; - /// # Ok(()) - /// # } + /// // We now write at the offset 10. + /// file.write_at(b"sushi", 10)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; @@ -117,13 +117,13 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::unix::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let permissions = metadata.permissions(); /// - /// println!("permissions: {}", permissions.mode()); - /// # Ok(()) } + /// println!("permissions: {}", permissions.mode()); + /// Ok(()) } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -136,14 +136,14 @@ pub trait PermissionsExt { /// use std::fs::File; /// use std::os::unix::fs::PermissionsExt; /// - /// # fn run() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); + /// fn main() -> std::io::Result<()> { + /// let f = File::create("foo.txt")?; + /// let metadata = f.metadata()?; + /// let mut permissions = metadata.permissions(); /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// # Ok(()) } + /// permissions.set_mode(0o644); // Read/write for owner and read for others. + /// assert_eq!(permissions.mode(), 0o644); + /// Ok(()) } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); @@ -260,15 +260,15 @@ pub trait MetadataExt { /// # Examples /// /// ```no_run + /// use std::io; /// use std::fs; /// use std::os::unix::fs::MetadataExt; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let dev_id = meta.dev(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let dev_id = meta.dev(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn dev(&self) -> u64; @@ -279,13 +279,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let inode = meta.ino(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let inode = meta.ino(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ino(&self) -> u64; @@ -296,17 +296,17 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; - /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let mode = meta.mode(); - /// let user_has_write_access = mode & 0o200; - /// let user_has_read_write_access = mode & 0o600; - /// let group_has_read_access = mode & 0o040; - /// let others_have_exec_access = mode & 0o001; - /// # Ok(()) - /// # } + /// use std::io; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let mode = meta.mode(); + /// let user_has_write_access = mode & 0o200; + /// let user_has_read_write_access = mode & 0o600; + /// let group_has_read_access = mode & 0o040; + /// let others_have_exec_access = mode & 0o001; + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -317,13 +317,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nb_hard_links = meta.nlink(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nb_hard_links = meta.nlink(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn nlink(&self) -> u64; @@ -334,13 +334,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let user_id = meta.uid(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let user_id = meta.uid(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn uid(&self) -> u32; @@ -351,13 +351,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let group_id = meta.gid(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let group_id = meta.gid(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn gid(&self) -> u32; @@ -368,13 +368,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let device_id = meta.rdev(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let device_id = meta.rdev(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn rdev(&self) -> u64; @@ -385,13 +385,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let file_size = meta.size(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let file_size = meta.size(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn size(&self) -> u64; @@ -402,13 +402,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_access_time = meta.atime(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_access_time = meta.atime(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn atime(&self) -> i64; @@ -419,13 +419,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_access_time = meta.atime_nsec(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_access_time = meta.atime_nsec(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn atime_nsec(&self) -> i64; @@ -436,13 +436,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_modification_time = meta.mtime(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_modification_time = meta.mtime(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mtime(&self) -> i64; @@ -453,13 +453,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_modification_time = meta.mtime_nsec(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_modification_time = meta.mtime_nsec(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn mtime_nsec(&self) -> i64; @@ -470,13 +470,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_status_change_time = meta.ctime(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let last_status_change_time = meta.ctime(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ctime(&self) -> i64; @@ -487,13 +487,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_status_change_time = meta.ctime_nsec(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let nano_last_status_change_time = meta.ctime_nsec(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn ctime_nsec(&self) -> i64; @@ -504,13 +504,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocksize = meta.blksize(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let blocksize = meta.blksize(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blksize(&self) -> u64; @@ -523,13 +523,13 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocks = meta.blocks(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let blocks = meta.blocks(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blocks(&self) -> u64; @@ -562,17 +562,17 @@ pub trait FileTypeExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("block_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_block_device()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("block_device_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_block_device()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_block_device(&self) -> bool; @@ -580,17 +580,17 @@ pub trait FileTypeExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("char_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_char_device()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("char_device_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_char_device()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_char_device(&self) -> bool; @@ -598,17 +598,17 @@ pub trait FileTypeExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("fifo_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_fifo()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("fifo_file")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_fifo()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_fifo(&self) -> bool; @@ -616,17 +616,17 @@ pub trait FileTypeExt { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::fs; /// use std::os::unix::fs::FileTypeExt; + /// use std::io; /// - /// # use std::io; - /// # fn f() -> io::Result<()> { - /// let meta = fs::metadata("unix.socket")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_socket()); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("unix.socket")?; + /// let file_type = meta.file_type(); + /// assert!(file_type.is_socket()); + /// Ok(()) + /// } /// ``` #[stable(feature = "file_type_ext", since = "1.5.0")] fn is_socket(&self) -> bool; @@ -687,13 +687,13 @@ impl DirEntryExt for fs::DirEntry { /// /// # Examples /// -/// ``` +/// ```no_run /// use std::os::unix::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index 38bf4cca851..e5cd51b6550 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -45,15 +45,15 @@ pub trait FileExt { /// use std::fs::File; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> io::Result<()> { - /// let mut file = File::open("foo.txt")?; - /// let mut buffer = [0; 10]; - /// - /// // Read 10 bytes, starting 72 bytes from the - /// // start of the file. - /// file.seek_read(&mut buffer[..], 72)?; - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; + /// + /// // Read 10 bytes, starting 72 bytes from the + /// // start of the file. + /// file.seek_read(&mut buffer[..], 72)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result; @@ -79,14 +79,14 @@ pub trait FileExt { /// use std::fs::File; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = File::create("foo.txt")?; + /// fn main() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; /// - /// // Write a byte string starting 72 bytes from - /// // the start of the file. - /// buffer.seek_write(b"some bytes", 72)?; - /// # Ok(()) - /// # } + /// // Write a byte string starting 72 bytes from + /// // the start of the file. + /// buffer.seek_write(b"some bytes", 72)?; + /// Ok(()) + /// } /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result; @@ -305,11 +305,11 @@ pub trait MetadataExt { /// use std::fs; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let attributes = metadata.file_attributes(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let attributes = metadata.file_attributes(); + /// Ok(()) + /// } /// ``` /// /// [File Attribute Constants]: @@ -335,11 +335,11 @@ pub trait MetadataExt { /// use std::fs; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let creation_time = metadata.creation_time(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let creation_time = metadata.creation_time(); + /// Ok(()) + /// } /// ``` /// /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx @@ -370,11 +370,11 @@ pub trait MetadataExt { /// use std::fs; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let last_access_time = metadata.last_access_time(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let last_access_time = metadata.last_access_time(); + /// Ok(()) + /// } /// ``` /// /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx @@ -403,11 +403,11 @@ pub trait MetadataExt { /// use std::fs; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let last_write_time = metadata.last_write_time(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let last_write_time = metadata.last_write_time(); + /// Ok(()) + /// } /// ``` /// /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx @@ -426,11 +426,11 @@ pub trait MetadataExt { /// use std::fs; /// use std::os::windows::prelude::*; /// - /// # fn foo() -> io::Result<()> { - /// let metadata = fs::metadata("foo.txt")?; - /// let file_size = metadata.file_size(); - /// # Ok(()) - /// # } + /// fn main() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let file_size = metadata.file_size(); + /// Ok(()) + /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn file_size(&self) -> u64; @@ -473,10 +473,10 @@ impl FileTypeExt for fs::FileType { /// ```no_run /// use std::os::windows::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink_file("a.txt", "b.txt")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink_file("a.txt", "b.txt")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink_file, Q: AsRef>(src: P, dst: Q) @@ -494,10 +494,10 @@ pub fn symlink_file, Q: AsRef>(src: P, dst: Q) /// ```no_run /// use std::os::windows::fs; /// -/// # fn foo() -> std::io::Result<()> { -/// fs::symlink_dir("a", "b")?; -/// # Ok(()) -/// # } +/// fn main() -> std::io::Result<()> { +/// fs::symlink_dir("a", "b")?; +/// Ok(()) +/// } /// ``` #[stable(feature = "symlink", since = "1.1.0")] pub fn symlink_dir, Q: AsRef>(src: P, dst: Q) -- cgit 1.4.1-3-g733a5 From b89fb71441db5fc7f719bbd25ba2ec61b0b9091a Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 26 Mar 2018 17:43:49 +0200 Subject: Clarify network byte order conversions for integer / IP address conversions. Opened primarily to address https://github.com/rust-lang/rust/issues/48819. --- src/libstd/net/ip.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 0d73a6f4fd7..8115f50f09b 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -769,7 +769,16 @@ impl FromInner for Ipv4Addr { #[stable(feature = "ip_u32", since = "1.1.0")] impl From for u32 { - /// It performs the conversion in network order (big-endian). + /// Convert an `Ipv4Addr` into a host byte order `u32`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::new(13, 12, 11, 10); + /// assert_eq!(0x0d0c0b0au32, u32::from(addr)); + /// ``` fn from(ip: Ipv4Addr) -> u32 { let ip = ip.octets(); ((ip[0] as u32) << 24) + ((ip[1] as u32) << 16) + ((ip[2] as u32) << 8) + (ip[3] as u32) @@ -778,7 +787,16 @@ impl From for u32 { #[stable(feature = "ip_u32", since = "1.1.0")] impl From for Ipv4Addr { - /// It performs the conversion in network order (big-endian). + /// Convert a host byte order `u32` into an `Ipv4Addr`. + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from(0x0d0c0b0au32); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` fn from(ip: u32) -> Ipv4Addr { Ipv4Addr::new((ip >> 24) as u8, (ip >> 16) as u8, (ip >> 8) as u8, ip as u8) } @@ -786,6 +804,14 @@ impl From for Ipv4Addr { #[stable(feature = "from_slice_v4", since = "1.9.0")] impl From<[u8; 4]> for Ipv4Addr { + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr); + /// ``` fn from(octets: [u8; 4]) -> Ipv4Addr { Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]) } @@ -793,6 +819,16 @@ impl From<[u8; 4]> for Ipv4Addr { #[stable(feature = "ip_from_slice", since = "1.17.0")] impl From<[u8; 4]> for IpAddr { + /// Create an `IpAddr::V4` from a four element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv4Addr}; + /// + /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]); + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr); + /// ``` fn from(octets: [u8; 4]) -> IpAddr { IpAddr::V4(Ipv4Addr::from(octets)) } @@ -1386,6 +1422,27 @@ impl From<[u16; 8]> for Ipv6Addr { #[stable(feature = "ip_from_slice", since = "1.17.0")] impl From<[u8; 16]> for IpAddr { + /// Create an `IpAddr::V6` from a sixteen element byte array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8, + /// 17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x1918, 0x1716, + /// 0x1514, 0x1312, + /// 0x1110, 0x0f0e, + /// 0x0d0c, 0x0b0a + /// )), + /// addr + /// ); + /// ``` fn from(octets: [u8; 16]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(octets)) } @@ -1393,6 +1450,27 @@ impl From<[u8; 16]> for IpAddr { #[stable(feature = "ip_from_slice", since = "1.17.0")] impl From<[u16; 8]> for IpAddr { + /// Create an `IpAddr::V6` from an eight element 16-bit array. + /// + /// # Examples + /// + /// ``` + /// use std::net::{IpAddr, Ipv6Addr}; + /// + /// let addr = IpAddr::from([ + /// 525u16, 524u16, 523u16, 522u16, + /// 521u16, 520u16, 519u16, 518u16, + /// ]); + /// assert_eq!( + /// IpAddr::V6(Ipv6Addr::new( + /// 0x20d, 0x20c, + /// 0x20b, 0x20a, + /// 0x209, 0x208, + /// 0x207, 0x206 + /// )), + /// addr + /// ); + /// ``` fn from(segments: [u16; 8]) -> IpAddr { IpAddr::V6(Ipv6Addr::from(segments)) } -- cgit 1.4.1-3-g733a5 From 0600d0f38d4998f1cacb3b97408224a0ee350db4 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 27 Mar 2018 10:20:27 -0700 Subject: Stabilize fs::read and fs::write --- src/libstd/fs.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5caa703ee97..b5476e9326d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -251,8 +251,6 @@ fn initial_buffer_size(file: &File) -> usize { /// # Examples /// /// ```no_run -/// #![feature(fs_read_write)] -/// /// use std::fs; /// use std::net::SocketAddr; /// @@ -261,7 +259,7 @@ fn initial_buffer_size(file: &File) -> usize { /// # Ok(()) /// # } /// ``` -#[unstable(feature = "fs_read_write", issue = "46588")] +#[stable(feature = "fs_read_write_bytes", since = "1.27.0")] pub fn read>(path: P) -> io::Result> { let mut file = File::open(path)?; let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); @@ -325,8 +323,6 @@ pub fn read_string>(path: P) -> io::Result { /// # Examples /// /// ```no_run -/// #![feature(fs_read_write)] -/// /// use std::fs; /// /// # fn foo() -> std::io::Result<()> { @@ -334,7 +330,7 @@ pub fn read_string>(path: P) -> io::Result { /// # Ok(()) /// # } /// ``` -#[unstable(feature = "fs_read_write", issue = "46588")] +#[stable(feature = "fs_read_write_bytes", since = "1.27.0")] pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { File::create(path)?.write_all(contents.as_ref()) } -- cgit 1.4.1-3-g733a5 From 7eb9a091f3ab8e77978ad5c8369f2fb4bedc2610 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Wed, 28 Mar 2018 18:54:34 +0100 Subject: std: Child::kill() returns error if process has already exited This patch makes it clear in std::process::Child::kill()'s API documentation that an error is returned if the child process has already cleanly exited. This is implied by the example, but not called out explicitly. --- src/libstd/process.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 92e9f48f7eb..b3cb8d745b4 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1121,8 +1121,9 @@ impl ExitCode { } impl Child { - /// Forces the child to exit. This is equivalent to sending a - /// SIGKILL on unix platforms. + /// Forces the child process to exit. If the child has already exited, an error is returned. + /// + /// This is equivalent to sending a SIGKILL on Unix platforms. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From d541282d6c578fcb09000bd4747dd7f08ccd3805 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Wed, 28 Mar 2018 23:05:51 +0100 Subject: fixup! std: Child::kill() returns error if process has already exited --- src/libstd/process.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index b3cb8d745b4..4d4a48bd2da 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1121,7 +1121,8 @@ impl ExitCode { } impl Child { - /// Forces the child process to exit. If the child has already exited, an error is returned. + /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] + /// error might be returned. /// /// This is equivalent to sending a SIGKILL on Unix platforms. /// @@ -1139,6 +1140,8 @@ impl Child { /// println!("yes command didn't start"); /// } /// ``` + /// + /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput #[stable(feature = "process", since = "1.0.0")] pub fn kill(&mut self) -> io::Result<()> { self.handle.kill() -- cgit 1.4.1-3-g733a5 From c3a63970dee2422e2fcc79d8b99303b4b046f444 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 19 Mar 2018 09:01:17 +0100 Subject: Move alloc::Bound to {core,std}::ops The stable reexport `std::collections::Bound` is now deprecated. Another deprecated reexport could be added in `alloc`, but that crate is unstable. --- src/liballoc/btree/map.rs | 4 +- src/liballoc/btree/set.rs | 2 +- src/liballoc/lib.rs | 51 ---------------------- src/liballoc/range.rs | 2 +- src/liballoc/string.rs | 2 +- src/liballoc/tests/btree/map.rs | 2 +- src/liballoc/vec.rs | 2 +- src/liballoc/vec_deque.rs | 2 +- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 51 ++++++++++++++++++++++ src/librustc_data_structures/array_vec.rs | 2 +- src/libstd/collections/mod.rs | 3 +- .../sync-send-iterators-in-libcollections.rs | 2 +- 13 files changed, 64 insertions(+), 63 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index cada190032a..2ba56063e36 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -13,11 +13,11 @@ use core::fmt::Debug; use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::Index; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; -use Bound::{Excluded, Included, Unbounded}; use range::RangeArgument; use super::node::{self, Handle, NodeRef, marker}; @@ -804,7 +804,7 @@ impl BTreeMap { /// /// ``` /// use std::collections::BTreeMap; - /// use std::collections::Bound::Included; + /// use std::ops::Bound::Included; /// /// let mut map = BTreeMap::new(); /// map.insert(3, "a"); diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index 2e3157147a0..d488dd6cbbd 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -240,7 +240,7 @@ impl BTreeSet { /// /// ``` /// use std::collections::BTreeSet; - /// use std::collections::Bound::Included; + /// use std::ops::Bound::Included; /// /// let mut set = BTreeSet::new(); /// set.insert(3); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 19d64d8fea9..eddbd50ea03 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -204,57 +204,6 @@ mod std { pub use core::ops; // RangeFull } -/// An endpoint of a range of keys. -/// -/// # Examples -/// -/// `Bound`s are range endpoints: -/// -/// ``` -/// #![feature(collections_range)] -/// -/// use std::collections::range::RangeArgument; -/// use std::collections::Bound::*; -/// -/// assert_eq!((..100).start(), Unbounded); -/// assert_eq!((1..12).start(), Included(&1)); -/// assert_eq!((1..12).end(), Excluded(&12)); -/// ``` -/// -/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. -/// Note that in most cases, it's better to use range syntax (`1..5`) instead. -/// -/// ``` -/// use std::collections::BTreeMap; -/// use std::collections::Bound::{Excluded, Included, Unbounded}; -/// -/// let mut map = BTreeMap::new(); -/// map.insert(3, "a"); -/// map.insert(5, "b"); -/// map.insert(8, "c"); -/// -/// for (key, value) in map.range((Excluded(3), Included(8))) { -/// println!("{}: {}", key, value); -/// } -/// -/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); -/// ``` -/// -/// [`BTreeMap::range`]: btree_map/struct.BTreeMap.html#method.range -#[stable(feature = "collections_bound", since = "1.17.0")] -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] -pub enum Bound { - /// An inclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Included(#[stable(feature = "collections_bound", since = "1.17.0")] T), - /// An exclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T), - /// An infinite endpoint. Indicates that there is no bound in this direction. - #[stable(feature = "collections_bound", since = "1.17.0")] - Unbounded, -} - /// An intermediate trait for specialization of `Extend`. #[doc(hidden)] trait SpecExtend { diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs index b03abc85180..7cadbf3c90a 100644 --- a/src/liballoc/range.rs +++ b/src/liballoc/range.rs @@ -15,7 +15,7 @@ //! Range syntax. use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; -use Bound::{self, Excluded, Included, Unbounded}; +use core::ops::Bound::{self, Excluded, Included, Unbounded}; /// `RangeArgument` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 23c12bef3aa..754c78f7779 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -59,6 +59,7 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str::pattern::Pattern; @@ -67,7 +68,6 @@ use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use range::RangeArgument; -use Bound::{Excluded, Included, Unbounded}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 2393101040d..6ebdb86cc4a 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -9,8 +9,8 @@ // except according to those terms. use std::collections::BTreeMap; -use std::collections::Bound::{self, Excluded, Included, Unbounded}; use std::collections::btree_map::Entry::{Occupied, Vacant}; +use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::rc::Rc; use std::iter::FromIterator; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index bcc999d7386..280570ecd65 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -75,6 +75,7 @@ use core::marker::PhantomData; use core::mem; #[cfg(not(test))] use core::num::Float; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{InPlace, Index, IndexMut, Place, Placer}; use core::ops; use core::ptr; @@ -87,7 +88,6 @@ use boxed::Box; use raw_vec::RawVec; use super::range::RangeArgument; use super::allocator::CollectionAllocErr; -use Bound::{Excluded, Included, Unbounded}; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index be6e8d0f22f..9efd730790d 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -21,6 +21,7 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; use core::ptr::NonNull; @@ -33,7 +34,6 @@ use raw_vec::RawVec; use super::allocator::CollectionAllocErr; use super::range::RangeArgument; -use Bound::{Excluded, Included, Unbounded}; use super::vec::Vec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 234970a81fa..b0e75135282 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -192,7 +192,7 @@ pub use self::index::{Index, IndexMut}; pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] -pub use self::range::{RangeInclusive, RangeToInclusive}; +pub use self::range::{RangeInclusive, RangeToInclusive, Bound}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index be51f5239b0..dd44aedd09f 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -442,3 +442,54 @@ impl> RangeToInclusive { // RangeToInclusive cannot impl From> // because underflow would be possible with (..0).into() + +/// An endpoint of a range of keys. +/// +/// # Examples +/// +/// `Bound`s are range endpoints: +/// +/// ``` +/// #![feature(collections_range)] +/// +/// use std::collections::range::RangeArgument; +/// use std::ops::Bound::*; +/// +/// assert_eq!((..100).start(), Unbounded); +/// assert_eq!((1..12).start(), Included(&1)); +/// assert_eq!((1..12).end(), Excluded(&12)); +/// ``` +/// +/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. +/// Note that in most cases, it's better to use range syntax (`1..5`) instead. +/// +/// ``` +/// use std::collections::BTreeMap; +/// use std::ops::Bound::{Excluded, Included, Unbounded}; +/// +/// let mut map = BTreeMap::new(); +/// map.insert(3, "a"); +/// map.insert(5, "b"); +/// map.insert(8, "c"); +/// +/// for (key, value) in map.range((Excluded(3), Included(8))) { +/// println!("{}: {}", key, value); +/// } +/// +/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); +/// ``` +/// +/// [`BTreeMap::range`]: ../../std/collections/btree_map/struct.BTreeMap.html#method.range +#[stable(feature = "collections_bound", since = "1.17.0")] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +pub enum Bound { + /// An inclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Included(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An exclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Excluded(#[stable(feature = "collections_bound", since = "1.17.0")] T), + /// An infinite endpoint. Indicates that there is no bound in this direction. + #[stable(feature = "collections_bound", since = "1.17.0")] + Unbounded, +} diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 511c407d45a..b40f2f92237 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -19,8 +19,8 @@ use std::slice; use std::fmt; use std::mem; use std::collections::range::RangeArgument; -use std::collections::Bound::{Excluded, Included, Unbounded}; use std::mem::ManuallyDrop; +use std::ops::Bound::{Excluded, Included, Unbounded}; pub unsafe trait Array { type Element; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index be88f4e268a..e6f15a6119e 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -420,7 +420,8 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::Bound; +#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")] +pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 903532e9bc8..e096fb3bbae 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -18,8 +18,8 @@ use std::collections::VecDeque; use std::collections::HashMap; use std::collections::HashSet; -use std::collections::Bound::Included; use std::mem; +use std::ops::Bound::Included; fn is_sync(_: T) where T: Sync {} fn is_send(_: T) where T: Send {} -- cgit 1.4.1-3-g733a5 From 16d3ba1b23195da2d53e058c58c2a41def914dec Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 19 Mar 2018 09:26:29 +0100 Subject: Move RangeArguments to {core::std}::ops and rename to RangeBounds These unstable items are deprecated: * The `std::collections::range::RangeArgument` reexport * The `std::collections::range` module. --- src/liballoc/btree/map.rs | 8 +- src/liballoc/btree/set.rs | 5 +- src/liballoc/lib.rs | 2 +- src/liballoc/range.rs | 152 ------------------------ src/liballoc/string.rs | 7 +- src/liballoc/vec.rs | 7 +- src/liballoc/vec_deque.rs | 5 +- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 155 ++++++++++++++++++++++++- src/librustc_data_structures/accumulate_vec.rs | 5 +- src/librustc_data_structures/array_vec.rs | 4 +- src/librustc_data_structures/indexed_vec.rs | 7 +- src/libstd/collections/mod.rs | 8 +- 13 files changed, 183 insertions(+), 184 deletions(-) delete mode 100644 src/liballoc/range.rs (limited to 'src/libstd') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 2ba56063e36..c604df7049e 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -15,10 +15,10 @@ use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::Index; +use core::ops::RangeBounds; use core::{fmt, intrinsics, mem, ptr}; use borrow::Borrow; -use range::RangeArgument; use super::node::{self, Handle, NodeRef, marker}; use super::search; @@ -817,7 +817,7 @@ impl BTreeMap { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range - where T: Ord, K: Borrow, R: RangeArgument + where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_ref(); let root2 = self.root.as_ref(); @@ -857,7 +857,7 @@ impl BTreeMap { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range_mut(&mut self, range: R) -> RangeMut - where T: Ord, K: Borrow, R: RangeArgument + where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_mut(); let root2 = unsafe { ptr::read(&root1) }; @@ -1812,7 +1812,7 @@ fn last_leaf_edge } } -fn range_search>( +fn range_search>( root1: NodeRef, root2: NodeRef, range: R diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs index d488dd6cbbd..2aad476d315 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/btree/set.rs @@ -16,12 +16,11 @@ use core::cmp::{min, max}; use core::fmt::Debug; use core::fmt; use core::iter::{Peekable, FromIterator, FusedIterator}; -use core::ops::{BitOr, BitAnd, BitXor, Sub}; +use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; use borrow::Borrow; use btree_map::{BTreeMap, Keys}; use super::Recover; -use range::RangeArgument; // FIXME(conventions): implement bounded iterators @@ -253,7 +252,7 @@ impl BTreeSet { /// ``` #[stable(feature = "btree_range", since = "1.17.0")] pub fn range(&self, range: R) -> Range - where K: Ord, T: Borrow, R: RangeArgument + where K: Ord, T: Borrow, R: RangeBounds { Range { iter: self.map.range(range) } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index eddbd50ea03..e98b58994bf 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -88,6 +88,7 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] +#![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(custom_attribute)] @@ -178,7 +179,6 @@ mod btree; pub mod borrow; pub mod fmt; pub mod linked_list; -pub mod range; pub mod slice; pub mod str; pub mod string; diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs deleted file mode 100644 index 7cadbf3c90a..00000000000 --- a/src/liballoc/range.rs +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "collections_range", - reason = "waiting for dust to settle on inclusive ranges", - issue = "30877")] - -//! Range syntax. - -use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; -use core::ops::Bound::{self, Excluded, Included, Unbounded}; - -/// `RangeArgument` is implemented by Rust's built-in range types, produced -/// by range syntax like `..`, `a..`, `..b` or `c..d`. -pub trait RangeArgument { - /// Start index bound. - /// - /// Returns the start value as a `Bound`. - /// - /// # Examples - /// - /// ``` - /// #![feature(alloc)] - /// #![feature(collections_range)] - /// - /// extern crate alloc; - /// - /// # fn main() { - /// use alloc::range::RangeArgument; - /// use alloc::Bound::*; - /// - /// assert_eq!((..10).start(), Unbounded); - /// assert_eq!((3..10).start(), Included(&3)); - /// # } - /// ``` - fn start(&self) -> Bound<&T>; - - /// End index bound. - /// - /// Returns the end value as a `Bound`. - /// - /// # Examples - /// - /// ``` - /// #![feature(alloc)] - /// #![feature(collections_range)] - /// - /// extern crate alloc; - /// - /// # fn main() { - /// use alloc::range::RangeArgument; - /// use alloc::Bound::*; - /// - /// assert_eq!((3..).end(), Unbounded); - /// assert_eq!((3..10).end(), Excluded(&10)); - /// # } - /// ``` - fn end(&self) -> Bound<&T>; -} - -// FIXME add inclusive ranges to RangeArgument - -impl RangeArgument for RangeFull { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Unbounded - } -} - -impl RangeArgument for RangeFrom { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Unbounded - } -} - -impl RangeArgument for RangeTo { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Excluded(&self.end) - } -} - -impl RangeArgument for Range { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Excluded(&self.end) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl RangeArgument for RangeInclusive { - fn start(&self) -> Bound<&T> { - Included(&self.start) - } - fn end(&self) -> Bound<&T> { - Included(&self.end) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl RangeArgument for RangeToInclusive { - fn start(&self) -> Bound<&T> { - Unbounded - } - fn end(&self) -> Bound<&T> { - Included(&self.end) - } -} - -impl RangeArgument for (Bound, Bound) { - fn start(&self) -> Bound<&T> { - match *self { - (Included(ref start), _) => Included(start), - (Excluded(ref start), _) => Excluded(start), - (Unbounded, _) => Unbounded, - } - } - - fn end(&self) -> Bound<&T> { - match *self { - (_, Included(ref end)) => Included(end), - (_, Excluded(ref end)) => Excluded(end), - (_, Unbounded) => Unbounded, - } - } -} - -impl<'a, T: ?Sized + 'a> RangeArgument for (Bound<&'a T>, Bound<&'a T>) { - fn start(&self) -> Bound<&T> { - self.0 - } - - fn end(&self) -> Bound<&T> { - self.1 - } -} diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 754c78f7779..aa202e23628 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -60,14 +60,13 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Add, AddAssign, Index, IndexMut}; +use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; use std_unicode::lossy; use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; -use range::RangeArgument; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; @@ -1484,7 +1483,7 @@ impl String { /// ``` #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // @@ -1548,7 +1547,7 @@ impl String { /// ``` #[unstable(feature = "splice", reason = "recently added", issue = "44643")] pub fn splice(&mut self, range: R, replace_with: &str) - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 280570ecd65..df08e46fe25 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -76,7 +76,7 @@ use core::mem; #[cfg(not(test))] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{InPlace, Index, IndexMut, Place, Placer}; +use core::ops::{InPlace, Index, IndexMut, Place, Placer, RangeBounds}; use core::ops; use core::ptr; use core::ptr::NonNull; @@ -86,7 +86,6 @@ use borrow::ToOwned; use borrow::Cow; use boxed::Box; use raw_vec::RawVec; -use super::range::RangeArgument; use super::allocator::CollectionAllocErr; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. @@ -1176,7 +1175,7 @@ impl Vec { /// ``` #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // @@ -1950,7 +1949,7 @@ impl Vec { #[inline] #[stable(feature = "vec_splice", since = "1.21.0")] pub fn splice(&mut self, range: R, replace_with: I) -> Splice - where R: RangeArgument, I: IntoIterator + where R: RangeBounds, I: IntoIterator { Splice { drain: self.drain(range), diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 9efd730790d..94d042a45aa 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -22,7 +22,7 @@ use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, Place, Placer, InPlace}; +use core::ops::{Index, IndexMut, Place, Placer, InPlace, RangeBounds}; use core::ptr; use core::ptr::NonNull; use core::slice; @@ -33,7 +33,6 @@ use core::cmp; use raw_vec::RawVec; use super::allocator::CollectionAllocErr; -use super::range::RangeArgument; use super::vec::Vec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 @@ -969,7 +968,7 @@ impl VecDeque { #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index b0e75135282..0b480b618fc 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -192,7 +192,7 @@ pub use self::index::{Index, IndexMut}; pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] -pub use self::range::{RangeInclusive, RangeToInclusive, Bound}; +pub use self::range::{RangeInclusive, RangeToInclusive, RangeBounds, Bound}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index dd44aedd09f..b5aa81e36c4 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -452,8 +452,8 @@ impl> RangeToInclusive { /// ``` /// #![feature(collections_range)] /// -/// use std::collections::range::RangeArgument; /// use std::ops::Bound::*; +/// use std::ops::RangeBounds; /// /// assert_eq!((..100).start(), Unbounded); /// assert_eq!((1..12).start(), Included(&1)); @@ -493,3 +493,156 @@ pub enum Bound { #[stable(feature = "collections_bound", since = "1.17.0")] Unbounded, } + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +/// `RangeBounds` is implemented by Rust's built-in range types, produced +/// by range syntax like `..`, `a..`, `..b` or `c..d`. +pub trait RangeBounds { + /// Start index bound. + /// + /// Returns the start value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((..10).start(), Unbounded); + /// assert_eq!((3..10).start(), Included(&3)); + /// # } + /// ``` + fn start(&self) -> Bound<&T>; + + /// End index bound. + /// + /// Returns the end value as a `Bound`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections_range)] + /// + /// # fn main() { + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((3..).end(), Unbounded); + /// assert_eq!((3..10).end(), Excluded(&10)); + /// # } + /// ``` + fn end(&self) -> Bound<&T>; +} + +use self::Bound::{Excluded, Included, Unbounded}; + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeFull { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeFrom { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Unbounded + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeTo { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for Range { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Excluded(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeInclusive { + fn start(&self) -> Bound<&T> { + Included(&self.start) + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for RangeToInclusive { + fn start(&self) -> Bound<&T> { + Unbounded + } + fn end(&self) -> Bound<&T> { + Included(&self.end) + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl RangeBounds for (Bound, Bound) { + fn start(&self) -> Bound<&T> { + match *self { + (Included(ref start), _) => Included(start), + (Excluded(ref start), _) => Excluded(start), + (Unbounded, _) => Unbounded, + } + } + + fn end(&self) -> Bound<&T> { + match *self { + (_, Included(ref end)) => Included(end), + (_, Excluded(ref end)) => Excluded(end), + (_, Unbounded) => Unbounded, + } + } +} + +#[unstable(feature = "collections_range", + reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", + issue = "30877")] +impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { + fn start(&self) -> Bound<&T> { + self.0 + } + + fn end(&self) -> Bound<&T> { + self.1 + } +} diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 52306de74cb..f50b8cadf15 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -15,11 +15,10 @@ //! //! The N above is determined by Array's implementor, by way of an associated constant. -use std::ops::{Deref, DerefMut}; +use std::ops::{Deref, DerefMut, RangeBounds}; use std::iter::{self, IntoIterator, FromIterator}; use std::slice; use std::vec; -use std::collections::range::RangeArgument; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; @@ -74,7 +73,7 @@ impl AccumulateVec { } pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { match *self { AccumulateVec::Array(ref mut v) => { diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index b40f2f92237..db1cfb5c767 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -18,9 +18,9 @@ use std::hash::{Hash, Hasher}; use std::slice; use std::fmt; use std::mem; -use std::collections::range::RangeArgument; use std::mem::ManuallyDrop; use std::ops::Bound::{Excluded, Included, Unbounded}; +use std::ops::RangeBounds; pub unsafe trait Array { type Element; @@ -106,7 +106,7 @@ impl ArrayVec { } pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { // Memory safety // diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index cbb3ff51715..1fb63afc72f 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::range::RangeArgument; use std::fmt::Debug; use std::iter::{self, FromIterator}; use std::slice; use std::marker::PhantomData; -use std::ops::{Index, IndexMut, Range}; +use std::ops::{Index, IndexMut, Range, RangeBounds}; use std::fmt; use std::vec; use std::u32; @@ -448,13 +447,13 @@ impl IndexVec { } #[inline] - pub fn drain<'a, R: RangeArgument>( + pub fn drain<'a, R: RangeBounds>( &'a mut self, range: R) -> impl Iterator + 'a { self.raw.drain(range) } #[inline] - pub fn drain_enumerated<'a, R: RangeArgument>( + pub fn drain_enumerated<'a, R: RangeBounds>( &'a mut self, range: R) -> impl Iterator + 'a { self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index e6f15a6119e..47ea3bc26bf 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -436,8 +436,12 @@ pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::range; +#[unstable(feature = "collections_range", issue = "30877")] +#[rustc_deprecated(reason = "renamed and moved to `std::ops::RangeBounds`", since = "1.26.0")] +/// Range syntax +pub mod range { + pub use ops::RangeBounds as RangeArgument; +} #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] pub use alloc::allocator::CollectionAllocErr; -- cgit 1.4.1-3-g733a5 From 6960a960f10e95d750daca14cd0a103edaca6105 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 23 Mar 2018 19:44:51 +0100 Subject: Hide the deprecated std::collections::range module from docs --- src/libstd/collections/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 47ea3bc26bf..426949d65df 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -438,6 +438,7 @@ pub use self::hash_set::HashSet; #[unstable(feature = "collections_range", issue = "30877")] #[rustc_deprecated(reason = "renamed and moved to `std::ops::RangeBounds`", since = "1.26.0")] +#[doc(hidden)] /// Range syntax pub mod range { pub use ops::RangeBounds as RangeArgument; -- cgit 1.4.1-3-g733a5 From 3542ff8e396af4a1be7854e1ce028465c4366fc4 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 27 Mar 2018 22:05:32 +0200 Subject: Hide the Bound type in docs at its deprecated location in std::collections --- src/libstd/collections/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 426949d65df..c7ad27d8d26 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -421,6 +421,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")] +#[doc(hidden)] pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; -- cgit 1.4.1-3-g733a5 From 94d1970bba87f2d2893f6e934e4c3f02ed50604d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 28 Mar 2018 22:37:37 +0200 Subject: Move the alloc::allocator module to core::heap This is the `Alloc` trait and its dependencies. --- src/liballoc/allocator.rs | 1082 --------------------------------------------- src/liballoc/heap.rs | 2 +- src/liballoc/lib.rs | 7 +- src/libcore/heap.rs | 1082 +++++++++++++++++++++++++++++++++++++++++++++ src/libcore/lib.rs | 4 + src/libstd/heap.rs | 3 +- 6 files changed, 1093 insertions(+), 1087 deletions(-) delete mode 100644 src/liballoc/allocator.rs create mode 100644 src/libcore/heap.rs (limited to 'src/libstd') diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs deleted file mode 100644 index fdc4efc66b9..00000000000 --- a/src/liballoc/allocator.rs +++ /dev/null @@ -1,1082 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] - -use core::cmp; -use core::fmt; -use core::mem; -use core::usize; -use core::ptr::{self, NonNull}; - -/// Represents the combination of a starting address and -/// a total capacity of the returned block. -#[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); - -fn size_align() -> (usize, usize) { - (mem::size_of::(), mem::align_of::()) -} - -/// Layout of a block of memory. -/// -/// An instance of `Layout` describes a particular layout of memory. -/// You build a `Layout` up as an input to give to an allocator. -/// -/// All layouts have an associated non-negative size and a -/// power-of-two alignment. -/// -/// (Note however that layouts are *not* required to have positive -/// size, even though many allocators require that all memory -/// requests have positive size. A caller to the `Alloc::alloc` -/// method must either ensure that conditions like this are met, or -/// use specific allocators with looser requirements.) -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Layout { - // size of the requested block of memory, measured in bytes. - size: usize, - - // alignment of the requested block of memory, measured in bytes. - // we ensure that this is always a power-of-two, because API's - // like `posix_memalign` require it and it is a reasonable - // constraint to impose on Layout constructors. - // - // (However, we do not analogously require `align >= sizeof(void*)`, - // even though that is *also* a requirement of `posix_memalign`.) - align: usize, -} - - -// FIXME: audit default implementations for overflow errors, -// (potentially switching to overflowing_add and -// overflowing_mul as necessary). - -impl Layout { - /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `None` if any of the following conditions - /// are not met: - /// - /// * `align` must be a power of two, - /// - /// * `align` must not exceed 231 (i.e. `1 << 31`), - /// - /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow (i.e. the rounded value must be less than - /// `usize::MAX`). - #[inline] - pub fn from_size_align(size: usize, align: usize) -> Option { - if !align.is_power_of_two() { - return None; - } - - if align > (1 << 31) { - return None; - } - - // (power-of-two implies align != 0.) - - // Rounded up size is: - // size_rounded_up = (size + align - 1) & !(align - 1); - // - // We know from above that align != 0. If adding (align - 1) - // does not overflow, then rounding up will be fine. - // - // Conversely, &-masking with !(align - 1) will subtract off - // only low-order-bits. Thus if overflow occurs with the sum, - // the &-mask cannot subtract enough to undo that overflow. - // - // Above implies that checking for summation overflow is both - // necessary and sufficient. - if size > usize::MAX - (align - 1) { - return None; - } - - unsafe { - Some(Layout::from_size_align_unchecked(size, align)) - } - } - - /// Creates a layout, bypassing all checks. - /// - /// # Safety - /// - /// This function is unsafe as it does not verify that `align` is - /// a power-of-two that is also less than or equal to 231, nor - /// that `size` aligned to `align` fits within the address space - /// (i.e. the `Layout::from_size_align` preconditions). - #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { - Layout { size: size, align: align } - } - - /// The minimum size in bytes for a memory block of this layout. - #[inline] - pub fn size(&self) -> usize { self.size } - - /// The minimum byte alignment for a memory block of this layout. - #[inline] - pub fn align(&self) -> usize { self.align } - - /// Constructs a `Layout` suitable for holding a value of type `T`. - pub fn new() -> Self { - let (size, align) = size_align::(); - Layout::from_size_align(size, align).unwrap() - } - - /// Produces layout describing a record that could be used to - /// allocate backing structure for `T` (which could be a trait - /// or other unsized type like a slice). - pub fn for_value(t: &T) -> Self { - let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - Layout::from_size_align(size, align).unwrap() - } - - /// Creates a layout describing the record that can hold a value - /// of the same layout as `self`, but that also is aligned to - /// alignment `align` (measured in bytes). - /// - /// If `self` already meets the prescribed alignment, then returns - /// `self`. - /// - /// Note that this method does not add any padding to the overall - /// size, regardless of whether the returned layout has a different - /// alignment. In other words, if `K` has size 16, `K.align_to(32)` - /// will *still* have size 16. - /// - /// # Panics - /// - /// Panics if the combination of `self.size` and the given `align` - /// violates the conditions listed in `from_size_align`. - #[inline] - pub fn align_to(&self, align: usize) -> Self { - Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() - } - - /// Returns the amount of padding we must insert after `self` - /// to ensure that the following address will satisfy `align` - /// (measured in bytes). - /// - /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` - /// returns 3, because that is the minimum number of bytes of - /// padding required to get a 4-aligned address (assuming that the - /// corresponding memory block starts at a 4-aligned address). - /// - /// The return value of this function has no meaning if `align` is - /// not a power-of-two. - /// - /// Note that the utility of the returned value requires `align` - /// to be less than or equal to the alignment of the starting - /// address for the whole allocated block of memory. One way to - /// satisfy this constraint is to ensure `align <= self.align`. - #[inline] - pub fn padding_needed_for(&self, align: usize) -> usize { - let len = self.size(); - - // Rounded up value is: - // len_rounded_up = (len + align - 1) & !(align - 1); - // and then we return the padding difference: `len_rounded_up - len`. - // - // We use modular arithmetic throughout: - // - // 1. align is guaranteed to be > 0, so align - 1 is always - // valid. - // - // 2. `len + align - 1` can overflow by at most `align - 1`, - // so the &-mask wth `!(align - 1)` will ensure that in the - // case of overflow, `len_rounded_up` will itself be 0. - // Thus the returned padding, when added to `len`, yields 0, - // which trivially satisfies the alignment `align`. - // - // (Of course, attempts to allocate blocks of memory whose - // size and padding overflow in the above manner should cause - // the allocator to yield an error anyway.) - - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); - return len_rounded_up.wrapping_sub(len); - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with a suitable amount of padding between each to - /// ensure that each instance is given its requested size and - /// alignment. On success, returns `(k, offs)` where `k` is the - /// layout of the array and `offs` is the distance between the start - /// of each element in the array. - /// - /// On arithmetic overflow, returns `None`. - #[inline] - pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; - let alloc_size = padded_size.checked_mul(n)?; - - // We can assume that `self.align` is a power-of-two that does - // not exceed 231. Furthermore, `alloc_size` has already been - // rounded up to a multiple of `self.align`; therefore, the - // call to `Layout::from_size_align` below should never panic. - Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) - } - - /// Creates a layout describing the record for `self` followed by - /// `next`, including any necessary padding to ensure that `next` - /// will be properly aligned. Note that the result layout will - /// satisfy the alignment properties of both `self` and `next`. - /// - /// Returns `Some((k, offset))`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// On arithmetic overflow, returns `None`. - pub fn extend(&self, next: Self) -> Option<(Self, usize)> { - let new_align = cmp::max(self.align, next.align); - let realigned = Layout::from_size_align(self.size, new_align)?; - - let pad = realigned.padding_needed_for(next.align); - - let offset = self.size.checked_add(pad)?; - let new_size = offset.checked_add(next.size)?; - - let layout = Layout::from_size_align(new_size, new_align)?; - Some((layout, offset)) - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with no padding between each instance. - /// - /// Note that, unlike `repeat`, `repeat_packed` does not guarantee - /// that the repeated instances of `self` will be properly - /// aligned, even if a given instance of `self` is properly - /// aligned. In other words, if the layout returned by - /// `repeat_packed` is used to allocate an array, it is not - /// guaranteed that all elements in the array will be properly - /// aligned. - /// - /// On arithmetic overflow, returns `None`. - pub fn repeat_packed(&self, n: usize) -> Option { - let size = self.size().checked_mul(n)?; - Layout::from_size_align(size, self.align) - } - - /// Creates a layout describing the record for `self` followed by - /// `next` with no additional padding between the two. Since no - /// padding is inserted, the alignment of `next` is irrelevant, - /// and is not incorporated *at all* into the resulting layout. - /// - /// Returns `(k, offset)`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// (The `offset` is always the same as `self.size()`; we use this - /// signature out of convenience in matching the signature of - /// `extend`.) - /// - /// On arithmetic overflow, returns `None`. - pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { - let new_size = self.size().checked_add(next.size())?; - let layout = Layout::from_size_align(new_size, self.align)?; - Some((layout, self.size())) - } - - /// Creates a layout describing the record for a `[T; n]`. - /// - /// On arithmetic overflow, returns `None`. - pub fn array(n: usize) -> Option { - Layout::new::() - .repeat(n) - .map(|(k, offs)| { - debug_assert!(offs == mem::size_of::()); - k - }) - } -} - -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to -/// something wrong when combining the given input arguments with this -/// allocator. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum AllocErr { - /// Error due to hitting some resource limit or otherwise running - /// out of memory. This condition strongly implies that *some* - /// series of deallocations would allow a subsequent reissuing of - /// the original allocation request to succeed. - Exhausted { request: Layout }, - - /// Error due to allocator being fundamentally incapable of - /// satisfying the original request. This condition implies that - /// such an allocation request will never succeed on the given - /// allocator, regardless of environment, memory pressure, or - /// other contextual conditions. - /// - /// For example, an allocator that does not support requests for - /// large memory blocks might return this error variant. - Unsupported { details: &'static str }, -} - -impl AllocErr { - #[inline] - pub fn invalid_input(details: &'static str) -> Self { - AllocErr::Unsupported { details: details } - } - #[inline] - pub fn is_memory_exhausted(&self) -> bool { - if let AllocErr::Exhausted { .. } = *self { true } else { false } - } - #[inline] - pub fn is_request_unsupported(&self) -> bool { - if let AllocErr::Unsupported { .. } = *self { true } else { false } - } - #[inline] - pub fn description(&self) -> &str { - match *self { - AllocErr::Exhausted { .. } => "allocator memory exhausted", - AllocErr::Unsupported { .. } => "unsupported allocator request", - } - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for AllocErr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// The `CannotReallocInPlace` error is used when `grow_in_place` or -/// `shrink_in_place` were unable to reuse the given memory block for -/// a requested layout. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CannotReallocInPlace; - -impl CannotReallocInPlace { - pub fn description(&self) -> &str { - "cannot reallocate allocator's memory in place" - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for CannotReallocInPlace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// Augments `AllocErr` with a CapacityOverflow variant. -#[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr(AllocErr), -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - fn from(err: AllocErr) -> Self { - CollectionAllocErr::AllocErr(err) - } -} - -/// An implementation of `Alloc` can allocate, reallocate, and -/// deallocate arbitrary blocks of data described via `Layout`. -/// -/// Some of the methods require that a memory block be *currently -/// allocated* via an allocator. This means that: -/// -/// * the starting address for that memory block was previously -/// returned by a previous call to an allocation method (`alloc`, -/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or -/// reallocation method (`realloc`, `realloc_excess`, or -/// `realloc_array`), and -/// -/// * the memory block has not been subsequently deallocated, where -/// blocks are deallocated either by being passed to a deallocation -/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being -/// passed to a reallocation method (see above) that returns `Ok`. -/// -/// A note regarding zero-sized types and zero-sized layouts: many -/// methods in the `Alloc` trait state that allocation requests -/// must be non-zero size, or else undefined behavior can result. -/// -/// * However, some higher-level allocation methods (`alloc_one`, -/// `alloc_array`) are well-defined on zero-sized types and can -/// optionally support them: it is left up to the implementor -/// whether to return `Err`, or to return `Ok` with some pointer. -/// -/// * If an `Alloc` implementation chooses to return `Ok` in this -/// case (i.e. the pointer denotes a zero-sized inaccessible block) -/// then that returned pointer must be considered "currently -/// allocated". On such an allocator, *all* methods that take -/// currently-allocated pointers as inputs must accept these -/// zero-sized pointers, *without* causing undefined behavior. -/// -/// * In other words, if a zero-sized pointer can flow out of an -/// allocator, then that allocator must likewise accept that pointer -/// flowing back into its deallocation and reallocation methods. -/// -/// Some of the methods require that a layout *fit* a memory block. -/// What it means for a layout to "fit" a memory block means (or -/// equivalently, for a memory block to "fit" a layout) is that the -/// following two conditions must hold: -/// -/// 1. The block's starting address must be aligned to `layout.align()`. -/// -/// 2. The block's size must fall in the range `[use_min, use_max]`, where: -/// -/// * `use_min` is `self.usable_size(layout).0`, and -/// -/// * `use_max` is the capacity that was (or would have been) -/// returned when (if) the block was allocated via a call to -/// `alloc_excess` or `realloc_excess`. -/// -/// Note that: -/// -/// * the size of the layout most recently used to allocate the block -/// is guaranteed to be in the range `[use_min, use_max]`, and -/// -/// * a lower-bound on `use_max` can be safely approximated by a call to -/// `usable_size`. -/// -/// * if a layout `k` fits a memory block (denoted by `ptr`) -/// currently allocated via an allocator `a`, then it is legal to -/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. -/// -/// # Unsafety -/// -/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and -/// implementors must ensure that they adhere to these contracts: -/// -/// * Pointers returned from allocation functions must point to valid memory and -/// retain their validity until at least the instance of `Alloc` is dropped -/// itself. -/// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. Note that as of the time of this -/// writing allocators *not* intending to be global allocators can still panic -/// in their implementation without violating memory safety. -/// -/// * `Layout` queries and calculations in general must be correct. Callers of -/// this trait are allowed to rely on the contracts defined on each method, -/// and implementors must ensure such contracts remain true. -/// -/// Note that this list may get tweaked over time as clarifications are made in -/// the future. Additionally global allocators may gain unique requirements for -/// how to safely implement one in the future as well. -pub unsafe trait Alloc { - - // (Note: existing allocators have unspecified but well-defined - // behavior in response to a zero size allocation request ; - // e.g. in C, `malloc` of 0 will either return a null pointer or a - // unique pointer, but will not have arbitrary undefined - // behavior. Rust should consider revising the alloc::heap crate - // to reflect this reality.) - - /// Returns a pointer meeting the size and alignment guarantees of - /// `layout`. - /// - /// If this method returns an `Ok(addr)`, then the `addr` returned - /// will be non-null address pointing to a block of storage - /// suitable for holding an instance of `layout`. - /// - /// The returned block of storage may or may not have its contents - /// initialized. (Extension subtraits might restrict this - /// behavior, e.g. to ensure initialization to particular sets of - /// bit patterns.) - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure that `layout` has non-zero size. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints. - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - - /// Deallocate the memory referenced by `ptr`. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must denote a block of memory currently allocated via - /// this allocator, - /// - /// * `layout` must *fit* that block of memory, - /// - /// * In addition to fitting the block of memory `layout`, the - /// alignment of the `layout` must match the alignment used - /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); - - /// Allocator-specific method for signaling an out-of-memory - /// condition. - /// - /// `oom` aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request (signaled by an error such as - /// `AllocErr::Exhausted`), and wish to abandon computation rather - /// than attempt to recover locally. Such clients should pass the - /// signaling error value back into `oom`, where the allocator - /// may incorporate that error value into its diagnostic report - /// before aborting. - /// - /// Implementations of the `oom` method are discouraged from - /// infinitely regressing in nested calls to `oom`. In - /// practice this means implementors should eschew allocating, - /// especially from `self` (directly or indirectly). - /// - /// Implementations of the allocation and reallocation methods - /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from - /// panicking (or aborting) in the event of memory exhaustion; - /// instead they should return an appropriate error from the - /// invoked method, and let the client decide whether to invoke - /// this `oom` method in response. - fn oom(&mut self, _: AllocErr) -> ! { - unsafe { ::core::intrinsics::abort() } - } - - // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == - // usable_size - - /// Returns bounds on the guaranteed usable size of a successful - /// allocation created with the specified `layout`. - /// - /// In particular, if one has a memory block allocated via a given - /// allocator `a` and layout `k` where `a.usable_size(k)` returns - /// `(l, u)`, then one can pass that block to `a.dealloc()` with a - /// layout in the size range [l, u]. - /// - /// (All implementors of `usable_size` must ensure that - /// `l <= k.size() <= u`) - /// - /// Both the lower- and upper-bounds (`l` and `u` respectively) - /// are provided, because an allocator based on size classes could - /// misbehave if one attempts to deallocate a block without - /// providing a correct value for its size (i.e., one within the - /// range `[l, u]`). - /// - /// Clients who wish to make use of excess capacity are encouraged - /// to use the `alloc_excess` and `realloc_excess` instead, as - /// this method is constrained to report conservative values that - /// serve as valid bounds for *all possible* allocation method - /// calls. - /// - /// However, for clients that do not wish to track the capacity - /// returned by `alloc_excess` locally, this method is likely to - /// produce useful results. - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - (layout.size(), layout.size()) - } - - // == METHODS FOR MEMORY REUSE == - // realloc. alloc_excess, realloc_excess - - /// Returns a pointer suitable for holding data described by - /// `new_layout`, meeting its size and alignment guarantees. To - /// accomplish this, this may extend or shrink the allocation - /// referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then ownership of the memory block - /// referenced by `ptr` has been transferred to this - /// allocator. The memory may or may not have been freed, and - /// should be considered unusable (unless of course it was - /// transferred back to the caller again via the return value of - /// this method). - /// - /// If this method returns `Err`, then ownership of the memory - /// block has not been transferred to this allocator, and the - /// contents of the memory block are unaltered. - /// - /// For best results, `new_layout` should not impose a different - /// alignment constraint than `layout`. (In other words, - /// `new_layout.align()` should equal `layout.align()`.) However, - /// behavior is well-defined (though underspecified) when this - /// constraint is violated; further discussion below. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` - /// argument need not fit it.) - /// - /// * `new_layout` must have size greater than zero. - /// - /// * the alignment of `new_layout` is non-zero. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returns `Err` only if `new_layout` does not match the - /// alignment of `layout`, or does not meet the allocator's size - /// and alignment constraints of the allocator, or if reallocation - /// otherwise fails. - /// - /// (Note the previous sentence did not say "if and only if" -- in - /// particular, an implementation of this method *can* return `Ok` - /// if `new_layout.align() != old_layout.align()`; or it can - /// return `Err` in that scenario, depending on whether this - /// allocator can dynamically adjust the alignment constraint for - /// the block.) - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let new_size = new_layout.size(); - let old_size = layout.size(); - let aligns_match = layout.align == new_layout.align; - - if new_size >= old_size && aligns_match { - if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } else if new_size < old_size && aligns_match { - if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } - - // otherwise, fall back on alloc + copy + dealloc. - let result = self.alloc(new_layout); - if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); - self.dealloc(ptr, layout); - } - result - } - - /// Behaves like `alloc`, but also ensures that the contents - /// are set to zero before being returned. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let size = layout.size(); - let p = self.alloc(layout); - if let Ok(p) = p { - ptr::write_bytes(p, 0, size); - } - p - } - - /// Behaves like `alloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let usable_size = self.usable_size(&layout); - self.alloc(layout).map(|p| Excess(p, usable_size.1)) - } - - /// Behaves like `realloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `realloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `realloc`. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let usable_size = self.usable_size(&new_layout); - self.realloc(ptr, layout, new_layout) - .map(|p| Excess(p, usable_size.1)) - } - - /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and thus can - /// be used to carry data of that layout. (The allocator is allowed to - /// expend effort to accomplish this, such as extending the memory block to - /// include successor blocks, or virtual memory tricks.) - /// - /// Regardless of what this method returns, ownership of the - /// memory block referenced by `ptr` has not been transferred, and - /// the contents of the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be less than `layout.size()`, - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `grow_in_place` failures without aborting, or to fall back on - /// another reallocation method before resorting to an abort. - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size >= layout.size); - debug_assert!(new_layout.align == layout.align); - let (_l, u) = self.usable_size(&layout); - // _l <= layout.size() [guaranteed by usable_size()] - // layout.size() <= new_layout.size() [required by this method] - if new_layout.size <= u { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and - /// thus can only be used to carry data of that smaller - /// layout. (The allocator is allowed to take advantage of this, - /// carving off portions of the block for reuse elsewhere.) The - /// truncated contents of the block within the smaller layout are - /// unaltered, and ownership of block has not been transferred. - /// - /// If this returns `Err`, then the memory block is considered to - /// still represent the original (larger) `layout`. None of the - /// block has been carved off for reuse elsewhere, ownership of - /// the memory block has not been transferred, and the contents of - /// the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be greater than `layout.size()` - /// (and must be greater than zero), - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `shrink_in_place` failures without aborting, or to fall back - /// on another reallocation method before resorting to an abort. - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size <= layout.size); - debug_assert!(new_layout.align == layout.align); - let (l, _u) = self.usable_size(&layout); - // layout.size() <= _u [guaranteed by usable_size()] - // new_layout.size() <= layout.size() [required by this method] - if l <= new_layout.size { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - - // == COMMON USAGE PATTERNS == - // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array - - /// Allocates a block suitable for holding an instance of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `T` does not meet allocator's size or alignment constraints. - /// - /// For zero-sized `T`, may return either of `Ok` or `Err`, but - /// will *not* yield undefined behavior. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_one(&mut self) -> Result, AllocErr> - where Self: Sized - { - let k = Layout::new::(); - if k.size() > 0 { - unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } - } else { - Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) - } - } - - /// Deallocates a block suitable for holding an instance of `T`. - /// - /// The given block must have been produced by this allocator, - /// and must be suitable for storing a `T` (in terms of alignment - /// as well as minimum and maximum size); otherwise yields - /// undefined behavior. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `T` must *fit* that block of memory. - unsafe fn dealloc_one(&mut self, ptr: NonNull) - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - let k = Layout::new::(); - if k.size() > 0 { - self.dealloc(raw_ptr, k); - } - } - - /// Allocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_array(&mut self, n: usize) -> Result, AllocErr> - where Self: Sized - { - match Layout::array::(n) { - Some(ref layout) if layout.size() > 0 => { - unsafe { - self.alloc(layout.clone()) - .map(|p| { - NonNull::new_unchecked(p as *mut T) - }) - } - } - _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), - } - } - - /// Reallocates a block previously suitable for holding `n_old` - /// instances of `T`, returning a block suitable for holding - /// `n_new` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * the layout of `[T; n_old]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n_new]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_array(&mut self, - ptr: NonNull, - n_old: usize, - n_new: usize) -> Result, AllocErr> - where Self: Sized - { - match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { - self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) - .map(|p| NonNull::new_unchecked(p as *mut T)) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for realloc_array")) - } - } - } - - /// Deallocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `[T; n]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either `[T; n]` or the given - /// memory block does not meet allocator's size or alignment - /// constraints. - /// - /// Always returns `Err` on arithmetic overflow. - unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - match Layout::array::(n) { - Some(ref k) if k.size() > 0 => { - Ok(self.dealloc(raw_ptr, k.clone())) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for dealloc_array")) - } - } - } -} diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index c13ad39e5e1..9296a113071 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -19,7 +19,7 @@ use core::intrinsics::{min_align_of_val, size_of_val}; use core::mem::{self, ManuallyDrop}; use core::usize; -pub use allocator::*; +pub use core::heap::*; #[doc(hidden)] pub mod __core { pub use core::*; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 19d64d8fea9..5594caa65b9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -81,6 +81,7 @@ #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] +#![feature(allocator_api)] #![feature(allow_internal_unstable)] #![feature(ascii_ctype)] #![feature(box_into_raw_non_null)] @@ -145,9 +146,9 @@ extern crate std_unicode; #[macro_use] mod macros; -// Allocator trait and helper struct definitions - -pub mod allocator; +#[rustc_deprecated(since = "1.27.0", reason = "use the heap module in core, alloc, or std instead")] +#[unstable(feature = "allocator_api", issue = "32838")] +pub use core::heap as allocator; // Heaps provided for low-level allocation strategies diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs new file mode 100644 index 00000000000..dae60b1647f --- /dev/null +++ b/src/libcore/heap.rs @@ -0,0 +1,1082 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use cmp; +use fmt; +use mem; +use usize; +use ptr::{self, NonNull}; + +/// Represents the combination of a starting address and +/// a total capacity of the returned block. +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); + +fn size_align() -> (usize, usize) { + (mem::size_of::(), mem::align_of::()) +} + +/// Layout of a block of memory. +/// +/// An instance of `Layout` describes a particular layout of memory. +/// You build a `Layout` up as an input to give to an allocator. +/// +/// All layouts have an associated non-negative size and a +/// power-of-two alignment. +/// +/// (Note however that layouts are *not* required to have positive +/// size, even though many allocators require that all memory +/// requests have positive size. A caller to the `Alloc::alloc` +/// method must either ensure that conditions like this are met, or +/// use specific allocators with looser requirements.) +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Layout { + // size of the requested block of memory, measured in bytes. + size: usize, + + // alignment of the requested block of memory, measured in bytes. + // we ensure that this is always a power-of-two, because API's + // like `posix_memalign` require it and it is a reasonable + // constraint to impose on Layout constructors. + // + // (However, we do not analogously require `align >= sizeof(void*)`, + // even though that is *also* a requirement of `posix_memalign`.) + align: usize, +} + + +// FIXME: audit default implementations for overflow errors, +// (potentially switching to overflowing_add and +// overflowing_mul as necessary). + +impl Layout { + /// Constructs a `Layout` from a given `size` and `align`, + /// or returns `None` if any of the following conditions + /// are not met: + /// + /// * `align` must be a power of two, + /// + /// * `align` must not exceed 231 (i.e. `1 << 31`), + /// + /// * `size`, when rounded up to the nearest multiple of `align`, + /// must not overflow (i.e. the rounded value must be less than + /// `usize::MAX`). + #[inline] + pub fn from_size_align(size: usize, align: usize) -> Option { + if !align.is_power_of_two() { + return None; + } + + if align > (1 << 31) { + return None; + } + + // (power-of-two implies align != 0.) + + // Rounded up size is: + // size_rounded_up = (size + align - 1) & !(align - 1); + // + // We know from above that align != 0. If adding (align - 1) + // does not overflow, then rounding up will be fine. + // + // Conversely, &-masking with !(align - 1) will subtract off + // only low-order-bits. Thus if overflow occurs with the sum, + // the &-mask cannot subtract enough to undo that overflow. + // + // Above implies that checking for summation overflow is both + // necessary and sufficient. + if size > usize::MAX - (align - 1) { + return None; + } + + unsafe { + Some(Layout::from_size_align_unchecked(size, align)) + } + } + + /// Creates a layout, bypassing all checks. + /// + /// # Safety + /// + /// This function is unsafe as it does not verify that `align` is + /// a power-of-two that is also less than or equal to 231, nor + /// that `size` aligned to `align` fits within the address space + /// (i.e. the `Layout::from_size_align` preconditions). + #[inline] + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + Layout { size: size, align: align } + } + + /// The minimum size in bytes for a memory block of this layout. + #[inline] + pub fn size(&self) -> usize { self.size } + + /// The minimum byte alignment for a memory block of this layout. + #[inline] + pub fn align(&self) -> usize { self.align } + + /// Constructs a `Layout` suitable for holding a value of type `T`. + pub fn new() -> Self { + let (size, align) = size_align::(); + Layout::from_size_align(size, align).unwrap() + } + + /// Produces layout describing a record that could be used to + /// allocate backing structure for `T` (which could be a trait + /// or other unsized type like a slice). + pub fn for_value(t: &T) -> Self { + let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); + Layout::from_size_align(size, align).unwrap() + } + + /// Creates a layout describing the record that can hold a value + /// of the same layout as `self`, but that also is aligned to + /// alignment `align` (measured in bytes). + /// + /// If `self` already meets the prescribed alignment, then returns + /// `self`. + /// + /// Note that this method does not add any padding to the overall + /// size, regardless of whether the returned layout has a different + /// alignment. In other words, if `K` has size 16, `K.align_to(32)` + /// will *still* have size 16. + /// + /// # Panics + /// + /// Panics if the combination of `self.size` and the given `align` + /// violates the conditions listed in `from_size_align`. + #[inline] + pub fn align_to(&self, align: usize) -> Self { + Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() + } + + /// Returns the amount of padding we must insert after `self` + /// to ensure that the following address will satisfy `align` + /// (measured in bytes). + /// + /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` + /// returns 3, because that is the minimum number of bytes of + /// padding required to get a 4-aligned address (assuming that the + /// corresponding memory block starts at a 4-aligned address). + /// + /// The return value of this function has no meaning if `align` is + /// not a power-of-two. + /// + /// Note that the utility of the returned value requires `align` + /// to be less than or equal to the alignment of the starting + /// address for the whole allocated block of memory. One way to + /// satisfy this constraint is to ensure `align <= self.align`. + #[inline] + pub fn padding_needed_for(&self, align: usize) -> usize { + let len = self.size(); + + // Rounded up value is: + // len_rounded_up = (len + align - 1) & !(align - 1); + // and then we return the padding difference: `len_rounded_up - len`. + // + // We use modular arithmetic throughout: + // + // 1. align is guaranteed to be > 0, so align - 1 is always + // valid. + // + // 2. `len + align - 1` can overflow by at most `align - 1`, + // so the &-mask wth `!(align - 1)` will ensure that in the + // case of overflow, `len_rounded_up` will itself be 0. + // Thus the returned padding, when added to `len`, yields 0, + // which trivially satisfies the alignment `align`. + // + // (Of course, attempts to allocate blocks of memory whose + // size and padding overflow in the above manner should cause + // the allocator to yield an error anyway.) + + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + return len_rounded_up.wrapping_sub(len); + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with a suitable amount of padding between each to + /// ensure that each instance is given its requested size and + /// alignment. On success, returns `(k, offs)` where `k` is the + /// layout of the array and `offs` is the distance between the start + /// of each element in the array. + /// + /// On arithmetic overflow, returns `None`. + #[inline] + pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; + let alloc_size = padded_size.checked_mul(n)?; + + // We can assume that `self.align` is a power-of-two that does + // not exceed 231. Furthermore, `alloc_size` has already been + // rounded up to a multiple of `self.align`; therefore, the + // call to `Layout::from_size_align` below should never panic. + Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + } + + /// Creates a layout describing the record for `self` followed by + /// `next`, including any necessary padding to ensure that `next` + /// will be properly aligned. Note that the result layout will + /// satisfy the alignment properties of both `self` and `next`. + /// + /// Returns `Some((k, offset))`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// On arithmetic overflow, returns `None`. + pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + let new_align = cmp::max(self.align, next.align); + let realigned = Layout::from_size_align(self.size, new_align)?; + + let pad = realigned.padding_needed_for(next.align); + + let offset = self.size.checked_add(pad)?; + let new_size = offset.checked_add(next.size)?; + + let layout = Layout::from_size_align(new_size, new_align)?; + Some((layout, offset)) + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with no padding between each instance. + /// + /// Note that, unlike `repeat`, `repeat_packed` does not guarantee + /// that the repeated instances of `self` will be properly + /// aligned, even if a given instance of `self` is properly + /// aligned. In other words, if the layout returned by + /// `repeat_packed` is used to allocate an array, it is not + /// guaranteed that all elements in the array will be properly + /// aligned. + /// + /// On arithmetic overflow, returns `None`. + pub fn repeat_packed(&self, n: usize) -> Option { + let size = self.size().checked_mul(n)?; + Layout::from_size_align(size, self.align) + } + + /// Creates a layout describing the record for `self` followed by + /// `next` with no additional padding between the two. Since no + /// padding is inserted, the alignment of `next` is irrelevant, + /// and is not incorporated *at all* into the resulting layout. + /// + /// Returns `(k, offset)`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// (The `offset` is always the same as `self.size()`; we use this + /// signature out of convenience in matching the signature of + /// `extend`.) + /// + /// On arithmetic overflow, returns `None`. + pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { + let new_size = self.size().checked_add(next.size())?; + let layout = Layout::from_size_align(new_size, self.align)?; + Some((layout, self.size())) + } + + /// Creates a layout describing the record for a `[T; n]`. + /// + /// On arithmetic overflow, returns `None`. + pub fn array(n: usize) -> Option { + Layout::new::() + .repeat(n) + .map(|(k, offs)| { + debug_assert!(offs == mem::size_of::()); + k + }) + } +} + +/// The `AllocErr` error specifies whether an allocation failure is +/// specifically due to resource exhaustion or if it is due to +/// something wrong when combining the given input arguments with this +/// allocator. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum AllocErr { + /// Error due to hitting some resource limit or otherwise running + /// out of memory. This condition strongly implies that *some* + /// series of deallocations would allow a subsequent reissuing of + /// the original allocation request to succeed. + Exhausted { request: Layout }, + + /// Error due to allocator being fundamentally incapable of + /// satisfying the original request. This condition implies that + /// such an allocation request will never succeed on the given + /// allocator, regardless of environment, memory pressure, or + /// other contextual conditions. + /// + /// For example, an allocator that does not support requests for + /// large memory blocks might return this error variant. + Unsupported { details: &'static str }, +} + +impl AllocErr { + #[inline] + pub fn invalid_input(details: &'static str) -> Self { + AllocErr::Unsupported { details: details } + } + #[inline] + pub fn is_memory_exhausted(&self) -> bool { + if let AllocErr::Exhausted { .. } = *self { true } else { false } + } + #[inline] + pub fn is_request_unsupported(&self) -> bool { + if let AllocErr::Unsupported { .. } = *self { true } else { false } + } + #[inline] + pub fn description(&self) -> &str { + match *self { + AllocErr::Exhausted { .. } => "allocator memory exhausted", + AllocErr::Unsupported { .. } => "unsupported allocator request", + } + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for AllocErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// The `CannotReallocInPlace` error is used when `grow_in_place` or +/// `shrink_in_place` were unable to reuse the given memory block for +/// a requested layout. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CannotReallocInPlace; + +impl CannotReallocInPlace { + pub fn description(&self) -> &str { + "cannot reallocate allocator's memory in place" + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for CannotReallocInPlace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr(AllocErr), +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + fn from(err: AllocErr) -> Self { + CollectionAllocErr::AllocErr(err) + } +} + +/// An implementation of `Alloc` can allocate, reallocate, and +/// deallocate arbitrary blocks of data described via `Layout`. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method (`alloc`, +/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or +/// reallocation method (`realloc`, `realloc_excess`, or +/// `realloc_array`), and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being +/// passed to a reallocation method (see above) that returns `Ok`. +/// +/// A note regarding zero-sized types and zero-sized layouts: many +/// methods in the `Alloc` trait state that allocation requests +/// must be non-zero size, or else undefined behavior can result. +/// +/// * However, some higher-level allocation methods (`alloc_one`, +/// `alloc_array`) are well-defined on zero-sized types and can +/// optionally support them: it is left up to the implementor +/// whether to return `Err`, or to return `Ok` with some pointer. +/// +/// * If an `Alloc` implementation chooses to return `Ok` in this +/// case (i.e. the pointer denotes a zero-sized inaccessible block) +/// then that returned pointer must be considered "currently +/// allocated". On such an allocator, *all* methods that take +/// currently-allocated pointers as inputs must accept these +/// zero-sized pointers, *without* causing undefined behavior. +/// +/// * In other words, if a zero-sized pointer can flow out of an +/// allocator, then that allocator must likewise accept that pointer +/// flowing back into its deallocation and reallocation methods. +/// +/// Some of the methods require that a layout *fit* a memory block. +/// What it means for a layout to "fit" a memory block means (or +/// equivalently, for a memory block to "fit" a layout) is that the +/// following two conditions must hold: +/// +/// 1. The block's starting address must be aligned to `layout.align()`. +/// +/// 2. The block's size must fall in the range `[use_min, use_max]`, where: +/// +/// * `use_min` is `self.usable_size(layout).0`, and +/// +/// * `use_max` is the capacity that was (or would have been) +/// returned when (if) the block was allocated via a call to +/// `alloc_excess` or `realloc_excess`. +/// +/// Note that: +/// +/// * the size of the layout most recently used to allocate the block +/// is guaranteed to be in the range `[use_min, use_max]`, and +/// +/// * a lower-bound on `use_max` can be safely approximated by a call to +/// `usable_size`. +/// +/// * if a layout `k` fits a memory block (denoted by `ptr`) +/// currently allocated via an allocator `a`, then it is legal to +/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. +/// +/// # Unsafety +/// +/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `Alloc` is dropped +/// itself. +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. Note that as of the time of this +/// writing allocators *not* intending to be global allocators can still panic +/// in their implementation without violating memory safety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. +/// +/// Note that this list may get tweaked over time as clarifications are made in +/// the future. Additionally global allocators may gain unique requirements for +/// how to safely implement one in the future as well. +pub unsafe trait Alloc { + + // (Note: existing allocators have unspecified but well-defined + // behavior in response to a zero size allocation request ; + // e.g. in C, `malloc` of 0 will either return a null pointer or a + // unique pointer, but will not have arbitrary undefined + // behavior. Rust should consider revising the alloc::heap crate + // to reflect this reality.) + + /// Returns a pointer meeting the size and alignment guarantees of + /// `layout`. + /// + /// If this method returns an `Ok(addr)`, then the `addr` returned + /// will be non-null address pointing to a block of storage + /// suitable for holding an instance of `layout`. + /// + /// The returned block of storage may or may not have its contents + /// initialized. (Extension subtraits might restrict this + /// behavior, e.g. to ensure initialization to particular sets of + /// bit patterns.) + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints. + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + + /// Deallocate the memory referenced by `ptr`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must *fit* that block of memory, + /// + /// * In addition to fitting the block of memory `layout`, the + /// alignment of the `layout` must match the alignment used + /// to allocate that block of memory. + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + + /// Allocator-specific method for signaling an out-of-memory + /// condition. + /// + /// `oom` aborts the thread or process, optionally performing + /// cleanup or logging diagnostic information before panicking or + /// aborting. + /// + /// `oom` is meant to be used by clients unable to cope with an + /// unsatisfied allocation request (signaled by an error such as + /// `AllocErr::Exhausted`), and wish to abandon computation rather + /// than attempt to recover locally. Such clients should pass the + /// signaling error value back into `oom`, where the allocator + /// may incorporate that error value into its diagnostic report + /// before aborting. + /// + /// Implementations of the `oom` method are discouraged from + /// infinitely regressing in nested calls to `oom`. In + /// practice this means implementors should eschew allocating, + /// especially from `self` (directly or indirectly). + /// + /// Implementations of the allocation and reallocation methods + /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from + /// panicking (or aborting) in the event of memory exhaustion; + /// instead they should return an appropriate error from the + /// invoked method, and let the client decide whether to invoke + /// this `oom` method in response. + fn oom(&mut self, _: AllocErr) -> ! { + unsafe { ::intrinsics::abort() } + } + + // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == + // usable_size + + /// Returns bounds on the guaranteed usable size of a successful + /// allocation created with the specified `layout`. + /// + /// In particular, if one has a memory block allocated via a given + /// allocator `a` and layout `k` where `a.usable_size(k)` returns + /// `(l, u)`, then one can pass that block to `a.dealloc()` with a + /// layout in the size range [l, u]. + /// + /// (All implementors of `usable_size` must ensure that + /// `l <= k.size() <= u`) + /// + /// Both the lower- and upper-bounds (`l` and `u` respectively) + /// are provided, because an allocator based on size classes could + /// misbehave if one attempts to deallocate a block without + /// providing a correct value for its size (i.e., one within the + /// range `[l, u]`). + /// + /// Clients who wish to make use of excess capacity are encouraged + /// to use the `alloc_excess` and `realloc_excess` instead, as + /// this method is constrained to report conservative values that + /// serve as valid bounds for *all possible* allocation method + /// calls. + /// + /// However, for clients that do not wish to track the capacity + /// returned by `alloc_excess` locally, this method is likely to + /// produce useful results. + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + (layout.size(), layout.size()) + } + + // == METHODS FOR MEMORY REUSE == + // realloc. alloc_excess, realloc_excess + + /// Returns a pointer suitable for holding data described by + /// `new_layout`, meeting its size and alignment guarantees. To + /// accomplish this, this may extend or shrink the allocation + /// referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then ownership of the memory block + /// referenced by `ptr` has been transferred to this + /// allocator. The memory may or may not have been freed, and + /// should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). + /// + /// If this method returns `Err`, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. + /// + /// For best results, `new_layout` should not impose a different + /// alignment constraint than `layout`. (In other words, + /// `new_layout.align()` should equal `layout.align()`.) However, + /// behavior is well-defined (though underspecified) when this + /// constraint is violated; further discussion below. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` + /// argument need not fit it.) + /// + /// * `new_layout` must have size greater than zero. + /// + /// * the alignment of `new_layout` is non-zero. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns `Err` only if `new_layout` does not match the + /// alignment of `layout`, or does not meet the allocator's size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// (Note the previous sentence did not say "if and only if" -- in + /// particular, an implementation of this method *can* return `Ok` + /// if `new_layout.align() != old_layout.align()`; or it can + /// return `Err` in that scenario, depending on whether this + /// allocator can dynamically adjust the alignment constraint for + /// the block.) + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + let new_size = new_layout.size(); + let old_size = layout.size(); + let aligns_match = layout.align == new_layout.align; + + if new_size >= old_size && aligns_match { + if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } else if new_size < old_size && aligns_match { + if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } + + // otherwise, fall back on alloc + copy + dealloc. + let result = self.alloc(new_layout); + if let Ok(new_ptr) = result { + ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + self.dealloc(ptr, layout); + } + result + } + + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let size = layout.size(); + let p = self.alloc(layout); + if let Ok(p) = p { + ptr::write_bytes(p, 0, size); + } + p + } + + /// Behaves like `alloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + let usable_size = self.usable_size(&layout); + self.alloc(layout).map(|p| Excess(p, usable_size.1)) + } + + /// Behaves like `realloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `realloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `realloc`. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result { + let usable_size = self.usable_size(&new_layout); + self.realloc(ptr, layout, new_layout) + .map(|p| Excess(p, usable_size.1)) + } + + /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and thus can + /// be used to carry data of that layout. (The allocator is allowed to + /// expend effort to accomplish this, such as extending the memory block to + /// include successor blocks, or virtual memory tricks.) + /// + /// Regardless of what this method returns, ownership of the + /// memory block referenced by `ptr` has not been transferred, and + /// the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be less than `layout.size()`, + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `grow_in_place` failures without aborting, or to fall back on + /// another reallocation method before resorting to an abort. + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size >= layout.size); + debug_assert!(new_layout.align == layout.align); + let (_l, u) = self.usable_size(&layout); + // _l <= layout.size() [guaranteed by usable_size()] + // layout.size() <= new_layout.size() [required by this method] + if new_layout.size <= u { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and + /// thus can only be used to carry data of that smaller + /// layout. (The allocator is allowed to take advantage of this, + /// carving off portions of the block for reuse elsewhere.) The + /// truncated contents of the block within the smaller layout are + /// unaltered, and ownership of block has not been transferred. + /// + /// If this returns `Err`, then the memory block is considered to + /// still represent the original (larger) `layout`. None of the + /// block has been carved off for reuse elsewhere, ownership of + /// the memory block has not been transferred, and the contents of + /// the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be greater than `layout.size()` + /// (and must be greater than zero), + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `shrink_in_place` failures without aborting, or to fall back + /// on another reallocation method before resorting to an abort. + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size <= layout.size); + debug_assert!(new_layout.align == layout.align); + let (l, _u) = self.usable_size(&layout); + // layout.size() <= _u [guaranteed by usable_size()] + // new_layout.size() <= layout.size() [required by this method] + if l <= new_layout.size { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + + // == COMMON USAGE PATTERNS == + // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array + + /// Allocates a block suitable for holding an instance of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `T` does not meet allocator's size or alignment constraints. + /// + /// For zero-sized `T`, may return either of `Ok` or `Err`, but + /// will *not* yield undefined behavior. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_one(&mut self) -> Result, AllocErr> + where Self: Sized + { + let k = Layout::new::(); + if k.size() > 0 { + unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + } else { + Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + } + } + + /// Deallocates a block suitable for holding an instance of `T`. + /// + /// The given block must have been produced by this allocator, + /// and must be suitable for storing a `T` (in terms of alignment + /// as well as minimum and maximum size); otherwise yields + /// undefined behavior. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `T` must *fit* that block of memory. + unsafe fn dealloc_one(&mut self, ptr: NonNull) + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + let k = Layout::new::(); + if k.size() > 0 { + self.dealloc(raw_ptr, k); + } + } + + /// Allocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_array(&mut self, n: usize) -> Result, AllocErr> + where Self: Sized + { + match Layout::array::(n) { + Some(ref layout) if layout.size() > 0 => { + unsafe { + self.alloc(layout.clone()) + .map(|p| { + NonNull::new_unchecked(p as *mut T) + }) + } + } + _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + } + } + + /// Reallocates a block previously suitable for holding `n_old` + /// instances of `T`, returning a block suitable for holding + /// `n_new` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * the layout of `[T; n_old]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n_new]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_array(&mut self, + ptr: NonNull, + n_old: usize, + n_new: usize) -> Result, AllocErr> + where Self: Sized + { + match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { + (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) + .map(|p| NonNull::new_unchecked(p as *mut T)) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for realloc_array")) + } + } + } + + /// Deallocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `[T; n]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either `[T; n]` or the given + /// memory block does not meet allocator's size or alignment + /// constraints. + /// + /// Always returns `Err` on arithmetic overflow. + unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + match Layout::array::(n) { + Some(ref k) if k.size() > 0 => { + Ok(self.dealloc(raw_ptr, k.clone())) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + } + } + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 11fecde3951..c77402ed442 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -185,6 +185,10 @@ pub mod hash; pub mod fmt; pub mod time; +/* Heap memory allocator trait */ +#[allow(missing_docs)] +pub mod heap; + // note: does not need to be public mod char_private; mod iter_private; diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs index 4d5e4df6f95..4a391372c3a 100644 --- a/src/libstd/heap.rs +++ b/src/libstd/heap.rs @@ -12,8 +12,9 @@ #![unstable(issue = "32838", feature = "allocator_api")] -pub use alloc::heap::{Heap, Alloc, Layout, Excess, CannotReallocInPlace, AllocErr}; +pub use alloc::heap::Heap; pub use alloc_system::System; +pub use core::heap::*; #[cfg(not(test))] #[doc(hidden)] -- cgit 1.4.1-3-g733a5 From 51dc6304e71b95ad26f697db56c0bc2e6df5dd47 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Thu, 29 Mar 2018 18:10:40 +0100 Subject: fixup! std: Child::kill() returns error if process has already exited --- src/libstd/process.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 4d4a48bd2da..c3d681a8962 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1122,7 +1122,10 @@ impl ExitCode { impl Child { /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] - /// error might be returned. + /// error is returned. + /// + /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function, + /// especially the [`Other`] kind might change to more specific kinds in the future. /// /// This is equivalent to sending a SIGKILL on Unix platforms. /// @@ -1141,7 +1144,9 @@ impl Child { /// } /// ``` /// + /// [`ErrorKind`]: ../io/enum.ErrorKind.html /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput + /// [`Other]: ../io/enum.ErrorKind.html#variant.Other #[stable(feature = "process", since = "1.0.0")] pub fn kill(&mut self) -> io::Result<()> { self.handle.kill() -- cgit 1.4.1-3-g733a5 From dfde231ecaa480e9683d3a54f2182587dc747a56 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 30 Mar 2018 12:01:36 +0200 Subject: Make UNIX_EPOCH an associated constant of SystemTime It's not very discoverable as a separate const in the module. --- src/libstd/time.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 7256ac43e27..aeaa3046274 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -259,6 +259,28 @@ impl fmt::Debug for Instant { } impl SystemTime { + /// An anchor in time which can be used to create new `SystemTime` instances or + /// learn about where in time a `SystemTime` lies. + /// + /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with + /// respect to the system clock. Using `duration_since` on an existing + /// `SystemTime` instance can tell how far away from this point in time a + /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a + /// `SystemTime` instance to represent another fixed point in time. + /// + /// # Examples + /// + /// ```no_run + /// use std::time::SystemTime; + /// + /// match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { + /// Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), + /// Err(_) => panic!("SystemTime before UNIX EPOCH!"), + /// } + /// ``` + #[unstable(feature = "assoc_unix_epoch", issue = "49502")] + pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; + /// Returns the system time corresponding to "now". /// /// # Examples -- cgit 1.4.1-3-g733a5 From df2e238d1aae617f75424a2928d35cc39fae0fa0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 30 Mar 2018 15:35:36 +0200 Subject: Fix doctest --- src/libstd/time.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/time.rs b/src/libstd/time.rs index aeaa3046274..1215302757c 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -271,6 +271,7 @@ impl SystemTime { /// # Examples /// /// ```no_run + /// #![feature(assoc_unix_epoch)] /// use std::time::SystemTime; /// /// match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { -- cgit 1.4.1-3-g733a5 From ba4f310e3fc961af7b9e6db52c53b51244473ae7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 30 Mar 2018 15:54:05 +0200 Subject: Revert "Add TryFrom and TryInto to the prelude" This reverts commit 09008cc23ff6395c2c928f3690e07d7389d08ebc. --- src/libcore/prelude/v1.rs | 3 --- src/libstd/prelude/v1.rs | 2 -- 2 files changed, 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 2c8e27abac9..d43496c387c 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -39,9 +39,6 @@ pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; -#[stable(feature = "try_from", since = "1.26.0")] -#[doc(no_inline)] -pub use convert::{TryFrom, TryInto}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use default::Default; diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index d5b7c68a3fa..feedd4e1abe 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -35,8 +35,6 @@ #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; -#[stable(feature = "try_from", since = "1.26.0")] -#[doc(no_inline)] pub use convert::{TryFrom, TryInto}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From cea018f290f05b32ca6b5bcb2f8599d20b5de75c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 24 Mar 2018 11:15:10 +0100 Subject: Deprecate signed std::num::NonZeroI* with a call for use cases --- src/libcore/lib.rs | 1 + src/libcore/num/mod.rs | 30 +++++++++++++++++++++++------- src/libstd/num.rs | 1 + 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 11fecde3951..9c791597175 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -86,6 +86,7 @@ #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(exhaustive_patterns)] +#![feature(macro_at_most_once_rep)] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ee041e1e4f1..dcda404721c 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -23,6 +23,7 @@ macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( #[$stability] + #[allow(deprecated)] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -34,7 +35,7 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( #[$stability: meta] #[$deprecation: meta] $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -46,6 +47,7 @@ macro_rules! nonzero_integers { /// assert_eq!(size_of::>(), size_of::()); /// ``` #[$stability] + #[$deprecation] #[allow(deprecated)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); @@ -93,12 +95,26 @@ macro_rules! nonzero_integers { nonzero_integers! { #[unstable(feature = "nonzero", issue = "49137")] - NonZeroU8(u8); NonZeroI8(i8); - NonZeroU16(u16); NonZeroI16(i16); - NonZeroU32(u32); NonZeroI32(i32); - NonZeroU64(u64); NonZeroI64(i64); - NonZeroU128(u128); NonZeroI128(i128); - NonZeroUsize(usize); NonZeroIsize(isize); + #[allow(deprecated)] // Redundant, works around "error: inconsistent lockstep iteration" + NonZeroU8(u8); + NonZeroU16(u16); + NonZeroU32(u32); + NonZeroU64(u64); + NonZeroU128(u128); + NonZeroUsize(usize); +} + +nonzero_integers! { + #[unstable(feature = "nonzero", issue = "49137")] + #[rustc_deprecated(since = "1.26.0", reason = "\ + signed non-zero integers are considered for removal due to lack of known use cases. \ + If you’re using them, please comment on https://github.com/rust-lang/rust/issues/49137")] + NonZeroI8(i8); + NonZeroI16(i16); + NonZeroI32(i32); + NonZeroI64(i64); + NonZeroI128(i128); + NonZeroIsize(isize); } /// Provides intentionally-wrapped arithmetic on `T`. diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 547b8c7c925..4b975dd912a 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -22,6 +22,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} pub use core::num::Wrapping; #[unstable(feature = "nonzero", issue = "49137")] +#[allow(deprecated)] pub use core::num::{ NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize, -- cgit 1.4.1-3-g733a5 From 504916c18b13f6585a2856b6d9337b7311f9b522 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 30 Mar 2018 09:55:52 -0700 Subject: fs_read_write_bytes stabilized in 1.26.0 --- src/libstd/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 3f0acfeea22..1b2ed2f6eb6 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -259,7 +259,7 @@ fn initial_buffer_size(file: &File) -> usize { /// Ok(()) /// } /// ``` -#[stable(feature = "fs_read_write_bytes", since = "1.27.0")] +#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] pub fn read>(path: P) -> io::Result> { let mut file = File::open(path)?; let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); @@ -330,7 +330,7 @@ pub fn read_string>(path: P) -> io::Result { /// Ok(()) /// } /// ``` -#[stable(feature = "fs_read_write_bytes", since = "1.27.0")] +#[stable(feature = "fs_read_write_bytes", since = "1.26.0")] pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { File::create(path)?.write_all(contents.as_ref()) } -- cgit 1.4.1-3-g733a5 From 6b7627f8c9858303d85a97217ddf38abec9425d3 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 30 Mar 2018 09:48:18 -0700 Subject: Rename fs::read_string to read_to_string and stabilize --- src/librustc/util/common.rs | 3 ++- src/librustdoc/html/render.rs | 2 +- src/libstd/fs.rs | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 96b77d351e2..6b896a889e3 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -244,7 +244,8 @@ fn get_resident() -> Option { use std::fs; let field = 1; - let contents = fs::read_string("/proc/self/statm").ok()?; + let contents = fs::read("/proc/self/statm").ok()?; + let contents = String::from_utf8(contents).ok()?; let s = contents.split_whitespace().nth(field)?; let npages = s.parse::().ok()?; Some(npages * 4096) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ff6cc56e5b4..d915bab7919 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1067,7 +1067,7 @@ impl<'a> SourceCollector<'a> { return Ok(()); } - let contents = fs::read_string(&p)?; + let contents = fs::read_to_string(&p)?; // Remove the utf-8 BOM if any let contents = if contents.starts_with("\u{feff}") { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 3f0acfeea22..3d8680cda9f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -297,12 +297,12 @@ pub fn read>(path: P) -> io::Result> { /// use std::net::SocketAddr; /// /// fn main() -> Result<(), Box> { -/// let foo: SocketAddr = fs::read_string("address.txt")?.parse()?; +/// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?; /// Ok(()) /// } /// ``` -#[unstable(feature = "fs_read_write", issue = "46588")] -pub fn read_string>(path: P) -> io::Result { +#[stable(feature = "fs_read_write", since = "1.26.0")] +pub fn read_to_string>(path: P) -> io::Result { let mut file = File::open(path)?; let mut string = String::with_capacity(initial_buffer_size(&file)); file.read_to_string(&mut string)?; @@ -3122,12 +3122,12 @@ mod tests { assert!(v == &bytes[..]); check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF])); - error_contains!(fs::read_string(&tmpdir.join("not-utf8")), + error_contains!(fs::read_to_string(&tmpdir.join("not-utf8")), "stream did not contain valid UTF-8"); let s = "𐁁𐀓𐀠𐀴𐀍"; check!(fs::write(&tmpdir.join("utf8"), s.as_bytes())); - let string = check!(fs::read_string(&tmpdir.join("utf8"))); + let string = check!(fs::read_to_string(&tmpdir.join("utf8"))); assert_eq!(string, s); } -- cgit 1.4.1-3-g733a5 From d4f5e89ee0e1ef0025a3e090f1e06af8272e97bc Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Sun, 1 Apr 2018 21:40:56 -0600 Subject: Stabilize `std::process::id()` Fixes #44971 --- src/libstd/process.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 92e9f48f7eb..b463a6d88fe 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1420,14 +1420,13 @@ pub fn abort() -> ! { /// Basic usage: /// /// ```no_run -/// #![feature(getpid)] /// use std::process; /// /// println!("My pid is {}", process::id()); /// ``` /// /// -#[unstable(feature = "getpid", issue = "44971", reason = "recently added")] +#[stable(feature = "getpid", since = "1.27.0")] pub fn id() -> u32 { ::sys::os::getpid() } -- cgit 1.4.1-3-g733a5 From b647583c2df155f4741fa2b3e1fa6e4fb1f5868f Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 2 Apr 2018 16:05:30 +0900 Subject: Use Alloc and Layout from core::heap. 94d1970bba87f2d2893f6e934e4c3f02ed50604d moved the alloc::allocator module to core::heap, moving e.g. Alloc and Layout out of the alloc crate. While alloc::heap reexports them, it's better to use them from where they really come from. --- src/liballoc/arc.rs | 3 ++- src/liballoc/boxed.rs | 3 ++- src/liballoc/btree/node.rs | 3 ++- src/liballoc/raw_vec.rs | 3 ++- src/liballoc/rc.rs | 3 ++- src/liballoc_jemalloc/lib.rs | 4 +--- src/liballoc_system/lib.rs | 11 ++++------- src/libstd/collections/hash/map.rs | 3 ++- src/libstd/collections/hash/table.rs | 3 ++- 9 files changed, 19 insertions(+), 17 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 6a77bf64bae..ccf2e2768d1 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -21,6 +21,7 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; use core::borrow; use core::fmt; use core::cmp::Ordering; +use core::heap::{Alloc, Layout}; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val, uninitialized}; use core::ops::Deref; @@ -31,7 +32,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use heap::{Heap, Alloc, Layout, box_free}; +use heap::{Heap, box_free}; use boxed::Box; use string::String; use vec::Vec; diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index fdc3ef4efb8..e59a6e9fdea 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -55,7 +55,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use heap::{Heap, Layout, Alloc}; +use heap::Heap; use raw_vec::RawVec; use core::any::Any; @@ -63,6 +63,7 @@ use core::borrow; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; +use core::heap::{Alloc, Layout}; use core::iter::FusedIterator; use core::marker::{self, Unpin, Unsize}; use core::mem::{self, Pin}; diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 464f8f2f4ec..49109d522e9 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -41,13 +41,14 @@ // - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges. // This implies that even an empty internal node has at least one edge. +use core::heap::{Alloc, Layout}; use core::marker::PhantomData; use core::mem; use core::ptr::{self, Unique, NonNull}; use core::slice; use boxed::Box; -use heap::{Heap, Alloc, Layout}; +use heap::Heap; const B: usize = 6; pub const MIN_LEN: usize = B - 1; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 229ae54d747..3edce8aebdf 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -9,11 +9,12 @@ // except according to those terms. use core::cmp; +use core::heap::{Alloc, Layout}; use core::mem; use core::ops::Drop; use core::ptr::{self, Unique}; use core::slice; -use heap::{Alloc, Layout, Heap}; +use heap::Heap; use super::boxed::Box; use super::allocator::CollectionAllocErr; use super::allocator::CollectionAllocErr::*; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 1fa5d34cb57..8bdc57f96a6 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -250,6 +250,7 @@ use core::cell::Cell; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; +use core::heap::{Alloc, Layout}; use core::intrinsics::abort; use core::marker; use core::marker::{Unsize, PhantomData}; @@ -259,7 +260,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use heap::{Heap, Alloc, Layout, box_free}; +use heap::{Heap, box_free}; use string::String; use vec::Vec; diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index d7370ae400d..7a8d01e4ef8 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -15,7 +15,6 @@ form or name", issue = "27783")] #![deny(warnings)] -#![feature(alloc)] #![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] @@ -25,7 +24,6 @@ #![cfg_attr(not(dummy_jemalloc), feature(allocator_api))] #![rustc_alloc_kind = "exe"] -extern crate alloc; extern crate alloc_system; extern crate libc; @@ -35,7 +33,7 @@ pub use contents::*; mod contents { use core::ptr; - use alloc::heap::{Alloc, AllocErr, Layout}; + use core::heap::{Alloc, AllocErr, Layout}; use alloc_system::System; use libc::{c_int, c_void, size_t}; diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 1d5e7b73be5..6c1e9cb0b9c 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -17,7 +17,6 @@ issue = "32838")] #![feature(global_allocator)] #![feature(allocator_api)] -#![feature(alloc)] #![feature(core_intrinsics)] #![feature(staged_api)] #![feature(rustc_attrs)] @@ -43,9 +42,7 @@ const MIN_ALIGN: usize = 8; #[allow(dead_code)] const MIN_ALIGN: usize = 16; -extern crate alloc; - -use self::alloc::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; +use core::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; #[unstable(feature = "allocator_api", issue = "32838")] pub struct System; @@ -125,7 +122,7 @@ mod platform { use MIN_ALIGN; use System; - use alloc::heap::{Alloc, AllocErr, Layout}; + use core::heap::{Alloc, AllocErr, Layout}; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl<'a> Alloc for &'a System { @@ -279,7 +276,7 @@ mod platform { use MIN_ALIGN; use System; - use alloc::heap::{Alloc, AllocErr, Layout, CannotReallocInPlace}; + use core::heap::{Alloc, AllocErr, Layout, CannotReallocInPlace}; type LPVOID = *mut u8; type HANDLE = LPVOID; @@ -491,7 +488,7 @@ mod platform { mod platform { extern crate dlmalloc; - use alloc::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; + use core::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; use System; use self::dlmalloc::GlobalDlmalloc; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 474999a6646..452fa4e471c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,9 +11,10 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::heap::{Heap, Alloc}; +use alloc::heap::Heap; use alloc::allocator::CollectionAllocErr; use cell::Cell; +use core::heap::Alloc; use borrow::Borrow; use cmp::max; use fmt::{self, Debug}; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 8e78dc546c6..c6861c82a23 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::heap::{Heap, Alloc, Layout}; +use alloc::heap::Heap; +use core::heap::{Alloc, Layout}; use cmp; use hash::{BuildHasher, Hash, Hasher}; -- cgit 1.4.1-3-g733a5 From 85310860c25c8525c03b2ffe12674c1914917aa0 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 2 Apr 2018 09:10:44 -0700 Subject: Add performance note to fs::read docs --- src/libstd/fs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 479e4d08f4b..7bd1adc411a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -231,7 +231,9 @@ fn initial_buffer_size(file: &File) -> usize { /// Read the entire contents of a file into a bytes vector. /// /// This is a convenience function for using [`File::open`] and [`read_to_end`] -/// with fewer imports and without an intermediate variable. +/// with fewer imports and without an intermediate variable. It pre-allocates a +/// buffer based on the file size when available, so it is generally faster than +/// reading into a vector created with `Vec::new()`. /// /// [`File::open`]: struct.File.html#method.open /// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end @@ -270,7 +272,9 @@ pub fn read>(path: P) -> io::Result> { /// Read the entire contents of a file into a string. /// /// This is a convenience function for using [`File::open`] and [`read_to_string`] -/// with fewer imports and without an intermediate variable. +/// with fewer imports and without an intermediate variable. It pre-allocates a +/// buffer based on the file size when available, so it is generally faster than +/// reading into a string created with `String::new()`. /// /// [`File::open`]: struct.File.html#method.open /// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string -- cgit 1.4.1-3-g733a5 From a2a0f21ba1d2d0d54e8a34d39d7435cbb4efe7e9 Mon Sep 17 00:00:00 2001 From: Rolf van de Krol Date: Mon, 2 Apr 2018 21:48:56 +0200 Subject: Fix typo --- src/libstd/io/buffered.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index cefff2f143c..3e9ae261ab6 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -180,7 +180,7 @@ impl BufReader { /// /// # Examples /// - /// ```no_ru + /// ```no_run /// # #![feature(bufreader_buffer)] /// use std::io::{BufReader, BufRead}; /// use std::fs::File; -- cgit 1.4.1-3-g733a5 From 9ab5788e0e73d1d7edbc025627e34bb8d4fa9bdd Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Mon, 2 Apr 2018 19:34:06 -0600 Subject: Fix "since" version for getpid feature. It was stabilized right before the beta branch was cut for 1.26.0. See https://github.com/rust-lang/rust/pull/49523#issuecomment-377996315 --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index b463a6d88fe..40bc84f4bc1 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1426,7 +1426,7 @@ pub fn abort() -> ! { /// ``` /// /// -#[stable(feature = "getpid", since = "1.27.0")] +#[stable(feature = "getpid", since = "1.26.0")] pub fn id() -> u32 { ::sys::os::getpid() } -- cgit 1.4.1-3-g733a5 From 7db854b36f9598e44fb4d61428d42d7769233e19 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Tue, 3 Apr 2018 12:42:36 +0900 Subject: Fix imports --- src/libstd/sys/unix/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 775289f393b..2db3d4a5744 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -223,7 +223,7 @@ pub mod guard { #[cfg_attr(test, allow(dead_code))] pub mod guard { use libc; - use libc::mmap; + use libc::{mmap, mprotect}; use libc::{PROT_NONE, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED}; use ops::Range; use sys::os; -- cgit 1.4.1-3-g733a5 From 9b5859aea199d5f34a4d4b5ae7112c5c41f3b242 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Sun, 18 Feb 2018 17:39:40 +0000 Subject: Remove all unstable placement features Closes #22181, #27779 --- src/grammar/parser-lalr.y | 3 - src/liballoc/binary_heap.rs | 66 +------- src/liballoc/boxed.rs | 151 +---------------- src/liballoc/lib.rs | 12 +- src/liballoc/linked_list.rs | 178 +-------------------- src/liballoc/tests/binary_heap.rs | 20 --- src/liballoc/tests/lib.rs | 2 - src/liballoc/tests/vec.rs | 20 +-- src/liballoc/tests/vec_deque.rs | 22 --- src/liballoc/vec.rs | 76 +-------- src/liballoc/vec_deque.rs | 144 +---------------- src/libcore/ops/mod.rs | 4 - src/libcore/ops/place.rs | 143 ----------------- src/librustc/hir/lowering.rs | 133 --------------- src/librustc/ich/impls_syntax.rs | 1 - src/librustc_lint/unused.rs | 1 - src/librustc_mir/build/matches/test.rs | 7 +- src/librustc_mir/lib.rs | 2 - src/librustc_typeck/diagnostics.rs | 10 -- src/libstd/collections/hash/map.rs | 151 +---------------- src/libstd/collections/hash/table.rs | 26 --- src/libstd/lib.rs | 1 - src/libsyntax/ast.rs | 3 - src/libsyntax/feature_gate.rs | 7 - src/libsyntax/fold.rs | 3 - src/libsyntax/parse/parser.rs | 13 -- src/libsyntax/print/pprust.rs | 13 -- src/libsyntax/util/parser.rs | 14 +- src/libsyntax/visit.rs | 4 - src/libsyntax_pos/hygiene.rs | 2 - src/test/compile-fail/issue-14084.rs | 17 -- src/test/compile-fail/placement-expr-unsafe.rs | 24 --- src/test/compile-fail/placement-expr-unstable.rs | 21 --- src/test/parse-fail/assoc-oddities-1.rs | 3 +- src/test/pretty/stmt_expr_attributes.rs | 1 - src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs | 10 -- .../run-pass-fulldeps/pprust-expr-roundtrip.rs | 39 ++--- src/test/run-pass/new-box-syntax.rs | 10 +- src/test/run-pass/placement-in-syntax.rs | 37 ----- src/test/ui/feature-gate-placement-expr.rs | 26 --- src/test/ui/feature-gate-placement-expr.stderr | 11 -- 41 files changed, 39 insertions(+), 1392 deletions(-) delete mode 100644 src/libcore/ops/place.rs delete mode 100644 src/test/compile-fail/issue-14084.rs delete mode 100644 src/test/compile-fail/placement-expr-unsafe.rs delete mode 100644 src/test/compile-fail/placement-expr-unstable.rs delete mode 100644 src/test/run-pass/placement-in-syntax.rs delete mode 100644 src/test/ui/feature-gate-placement-expr.rs delete mode 100644 src/test/ui/feature-gate-placement-expr.stderr (limited to 'src/libstd') diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index de1f96aac50..a7da69f65fa 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -1400,7 +1400,6 @@ nonblock_expr | BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); } | YIELD { $$ = mk_node("ExprYield", 0); } | YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } | nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } | nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } | nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } @@ -1463,7 +1462,6 @@ expr | BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } | YIELD { $$ = mk_node("ExprYield", 0); } | YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } | expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } | expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } | expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } @@ -1527,7 +1525,6 @@ expr_nostruct | BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } | YIELD { $$ = mk_node("ExprYield", 0); } | YIELD expr { $$ = mk_node("ExprYield", 1, $2); } -| expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); } | expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); } | expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); } | expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); } diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs index f6a666b599b..668b61c51d8 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/binary_heap.rs @@ -155,7 +155,7 @@ #![allow(missing_docs)] #![stable(feature = "rust1", since = "1.0.0")] -use core::ops::{Deref, DerefMut, Place, Placer, InPlace}; +use core::ops::{Deref, DerefMut}; use core::iter::{FromIterator, FusedIterator}; use core::mem::{swap, size_of}; use core::ptr; @@ -1195,67 +1195,3 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap { self.extend(iter.into_iter().cloned()); } } - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -pub struct BinaryHeapPlace<'a, T: 'a> -where T: Clone + Ord { - heap: *mut BinaryHeap, - place: vec::PlaceBack<'a, T>, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T: Clone + Ord + fmt::Debug> fmt::Debug for BinaryHeapPlace<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("BinaryHeapPlace") - .field(&self.place) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T: 'a> Placer for &'a mut BinaryHeap -where T: Clone + Ord { - type Place = BinaryHeapPlace<'a, T>; - - fn make_place(self) -> Self::Place { - let ptr = self as *mut BinaryHeap; - let place = Placer::make_place(self.data.place_back()); - BinaryHeapPlace { - heap: ptr, - place, - } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for BinaryHeapPlace<'a, T> -where T: Clone + Ord { - fn pointer(&mut self) -> *mut T { - self.place.pointer() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for BinaryHeapPlace<'a, T> -where T: Clone + Ord { - type Owner = &'a T; - - unsafe fn finalize(self) -> &'a T { - self.place.finalize(); - - let heap: &mut BinaryHeap = &mut *self.heap; - let len = heap.len(); - let i = heap.sift_up(0, len - 1); - heap.data.get_unchecked(i) - } -} diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index e59a6e9fdea..4f9dc61ce19 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -55,7 +55,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use heap::Heap; use raw_vec::RawVec; use core::any::Any; @@ -63,47 +62,14 @@ use core::borrow; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; -use core::heap::{Alloc, Layout}; use core::iter::FusedIterator; -use core::marker::{self, Unpin, Unsize}; +use core::marker::{Unpin, Unsize}; use core::mem::{self, Pin}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; -use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, NonNull, Unique}; use core::convert::From; use str::from_boxed_utf8_unchecked; -/// A value that represents the heap. This is the default place that the `box` -/// keyword allocates into when no place is supplied. -/// -/// The following two examples are equivalent: -/// -/// ``` -/// #![feature(box_heap)] -/// -/// #![feature(box_syntax, placement_in_syntax)] -/// use std::boxed::HEAP; -/// -/// fn main() { -/// let foo: Box = in HEAP { 5 }; -/// let foo = box 5; -/// } -/// ``` -#[unstable(feature = "box_heap", - reason = "may be renamed; uncertain about custom allocator design", - issue = "27779")] -pub const HEAP: ExchangeHeapSingleton = ExchangeHeapSingleton { _force_singleton: () }; - -/// This the singleton type used solely for `boxed::HEAP`. -#[unstable(feature = "box_heap", - reason = "may be renamed; uncertain about custom allocator design", - issue = "27779")] -#[allow(missing_debug_implementations)] -#[derive(Copy, Clone)] -pub struct ExchangeHeapSingleton { - _force_singleton: (), -} - /// A pointer type for heap allocation. /// /// See the [module-level documentation](../../std/boxed/index.html) for more. @@ -112,121 +78,6 @@ pub struct ExchangeHeapSingleton { #[stable(feature = "rust1", since = "1.0.0")] pub struct Box(Unique); -/// `IntermediateBox` represents uninitialized backing storage for `Box`. -/// -/// FIXME (pnkfelix): Ideally we would just reuse `Box` instead of -/// introducing a separate `IntermediateBox`; but then you hit -/// issues when you e.g. attempt to destructure an instance of `Box`, -/// since it is a lang item and so it gets special handling by the -/// compiler. Easier just to make this parallel type for now. -/// -/// FIXME (pnkfelix): Currently the `box` protocol only supports -/// creating instances of sized types. This IntermediateBox is -/// designed to be forward-compatible with a future protocol that -/// supports creating instances of unsized types; that is why the type -/// parameter has the `?Sized` generalization marker, and is also why -/// this carries an explicit size. However, it probably does not need -/// to carry the explicit alignment; that is just a work-around for -/// the fact that the `align_of` intrinsic currently requires the -/// input type to be Sized (which I do not think is strictly -/// necessary). -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -#[allow(missing_debug_implementations)] -pub struct IntermediateBox { - ptr: *mut u8, - layout: Layout, - marker: marker::PhantomData<*mut T>, -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -unsafe impl Place for IntermediateBox { - fn pointer(&mut self) -> *mut T { - self.ptr as *mut T - } -} - -unsafe fn finalize(b: IntermediateBox) -> Box { - let p = b.ptr as *mut T; - mem::forget(b); - Box::from_raw(p) -} - -fn make_place() -> IntermediateBox { - let layout = Layout::new::(); - - let p = if layout.size() == 0 { - mem::align_of::() as *mut u8 - } else { - unsafe { - Heap.alloc(layout.clone()).unwrap_or_else(|err| { - Heap.oom(err) - }) - } - }; - - IntermediateBox { - ptr: p, - layout, - marker: marker::PhantomData, - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl BoxPlace for IntermediateBox { - fn make_place() -> IntermediateBox { - make_place() - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl InPlace for IntermediateBox { - type Owner = Box; - unsafe fn finalize(self) -> Box { - finalize(self) - } -} - -#[unstable(feature = "placement_new_protocol", issue = "27779")] -impl Boxed for Box { - type Data = T; - type Place = IntermediateBox; - unsafe fn finalize(b: IntermediateBox) -> Box { - finalize(b) - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl Placer for ExchangeHeapSingleton { - type Place = IntermediateBox; - - fn make_place(self) -> IntermediateBox { - make_place() - } -} - -#[unstable(feature = "placement_in", - reason = "placement box design is still being worked out.", - issue = "27779")] -impl Drop for IntermediateBox { - fn drop(&mut self) { - if self.layout.size() > 0 { - unsafe { - Heap.dealloc(self.ptr, self.layout.clone()) - } - } - } -} - impl Box { /// Allocates memory on the heap and then places `x` into it. /// diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index e6a311041f5..2fad3b0bad4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -76,7 +76,6 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(test, feature(placement_in))] #![cfg_attr(not(test), feature(core_float))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] @@ -108,8 +107,6 @@ #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] -#![feature(placement_in_syntax)] -#![feature(placement_new_protocol)] #![feature(ptr_internals)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] @@ -128,8 +125,8 @@ #![feature(pointer_methods)] #![feature(inclusive_range_fields)] -#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))] -#![cfg_attr(test, feature(test, box_heap))] +#![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))] +#![cfg_attr(test, feature(test))] // Allow testing this library @@ -159,13 +156,12 @@ pub mod heap; // Need to conditionally define the mod from `boxed.rs` to avoid // duplicating the lang-items when building in test cfg; but also need -// to allow code to have `use boxed::HEAP;` -// and `use boxed::Box;` declarations. +// to allow code to have `use boxed::Box;` declarations. #[cfg(not(test))] pub mod boxed; #[cfg(test)] mod boxed { - pub use std::boxed::{Box, IntermediateBox, HEAP}; + pub use std::boxed::Box; } #[cfg(test)] mod boxed_test; diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 097d2e414f5..129b3bc6764 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -28,10 +28,9 @@ use core::hash::{Hasher, Hash}; use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem; -use core::ops::{BoxPlace, InPlace, Place, Placer}; -use core::ptr::{self, NonNull}; +use core::ptr::NonNull; -use boxed::{Box, IntermediateBox}; +use boxed::Box; use super::SpecExtend; /// A doubly-linked list with owned nodes. @@ -786,62 +785,6 @@ impl LinkedList { old_len: old_len, } } - - /// Returns a place for insertion at the front of the list. - /// - /// Using this method with placement syntax is equivalent to - /// [`push_front`](#method.push_front), but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::LinkedList; - /// - /// let mut list = LinkedList::new(); - /// list.front_place() <- 2; - /// list.front_place() <- 4; - /// assert!(list.iter().eq(&[4, 2])); - /// ``` - #[unstable(feature = "collection_placement", - reason = "method name and placement protocol are subject to change", - issue = "30172")] - pub fn front_place(&mut self) -> FrontPlace { - FrontPlace { - list: self, - node: IntermediateBox::make_place(), - } - } - - /// Returns a place for insertion at the back of the list. - /// - /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::LinkedList; - /// - /// let mut list = LinkedList::new(); - /// list.back_place() <- 2; - /// list.back_place() <- 4; - /// assert!(list.iter().eq(&[2, 4])); - /// ``` - #[unstable(feature = "collection_placement", - reason = "method name and placement protocol are subject to change", - issue = "30172")] - pub fn back_place(&mut self) -> BackPlace { - BackPlace { - list: self, - node: IntermediateBox::make_place(), - } - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1242,123 +1185,6 @@ impl Hash for LinkedList { } } -unsafe fn finalize(node: IntermediateBox>) -> Box> { - let mut node = node.finalize(); - ptr::write(&mut node.next, None); - ptr::write(&mut node.prev, None); - node -} - -/// A place for insertion at the front of a `LinkedList`. -/// -/// See [`LinkedList::front_place`](struct.LinkedList.html#method.front_place) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -pub struct FrontPlace<'a, T: 'a> { - list: &'a mut LinkedList, - node: IntermediateBox>, -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("FrontPlace") - .field(&self.list) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for FrontPlace<'a, T> { - type Place = Self; - - fn make_place(self) -> Self { - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for FrontPlace<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { &mut (*self.node.pointer()).element } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for FrontPlace<'a, T> { - type Owner = (); - - unsafe fn finalize(self) { - let FrontPlace { list, node } = self; - list.push_front_node(finalize(node)); - } -} - -/// A place for insertion at the back of a `LinkedList`. -/// -/// See [`LinkedList::back_place`](struct.LinkedList.html#method.back_place) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -pub struct BackPlace<'a, T: 'a> { - list: &'a mut LinkedList, - node: IntermediateBox>, -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("BackPlace") - .field(&self.list) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for BackPlace<'a, T> { - type Place = Self; - - fn make_place(self) -> Self { - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for BackPlace<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { &mut (*self.node.pointer()).element } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for BackPlace<'a, T> { - type Owner = (); - - unsafe fn finalize(self) { - let BackPlace { list, node } = self; - list.push_back_node(finalize(node)); - } -} - // Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters. #[allow(dead_code)] fn assert_covariance() { diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 5c979d82e55..8494463463c 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -278,26 +278,6 @@ fn test_extend_specialization() { assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); } -#[test] -fn test_placement() { - let mut a = BinaryHeap::new(); - &mut a <- 2; - &mut a <- 4; - &mut a <- 3; - assert_eq!(a.peek(), Some(&4)); - assert_eq!(a.len(), 3); - &mut a <- 1; - assert_eq!(a.into_sorted_vec(), vec![1, 2, 3, 4]); -} - -#[test] -fn test_placement_panic() { - let mut heap = BinaryHeap::from(vec![1, 2, 3]); - fn mkpanic() -> usize { panic!() } - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { &mut heap <- mkpanic(); })); - assert_eq!(heap.len(), 3); -} - #[allow(dead_code)] fn assert_covariance() { fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 0a7e9a8be94..1a49fb9964a 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -15,13 +15,11 @@ #![feature(attr_literals)] #![feature(box_syntax)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] -#![feature(collection_placement)] #![feature(const_fn)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(iterator_step_by)] #![feature(pattern)] -#![feature(placement_in_syntax)] #![feature(rand)] #![feature(slice_sort_by_cached_key)] #![feature(splice)] diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 3c17a401bba..2895c53009d 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -10,7 +10,7 @@ use std::borrow::Cow; use std::mem::size_of; -use std::{usize, isize, panic}; +use std::{usize, isize}; use std::vec::{Drain, IntoIter}; use std::collections::CollectionAllocErr::*; @@ -753,24 +753,6 @@ fn assert_covariance() { } } -#[test] -fn test_placement() { - let mut vec = vec![1]; - assert_eq!(vec.place_back() <- 2, &2); - assert_eq!(vec.len(), 2); - assert_eq!(vec.place_back() <- 3, &3); - assert_eq!(vec.len(), 3); - assert_eq!(&vec, &[1, 2, 3]); -} - -#[test] -fn test_placement_panic() { - let mut vec = vec![1, 2, 3]; - fn mkpanic() -> usize { panic!() } - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); })); - assert_eq!(vec.len(), 3); -} - #[test] fn from_into_inner() { let vec = vec![1, 2, 3]; diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index fc1a0b624a5..75d3f01f8b6 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1004,28 +1004,6 @@ fn test_is_empty() { assert!(v.into_iter().is_empty()); } -#[test] -fn test_placement_in() { - let mut buf: VecDeque = VecDeque::new(); - buf.place_back() <- 1; - buf.place_back() <- 2; - assert_eq!(buf, [1,2]); - - buf.place_front() <- 3; - buf.place_front() <- 4; - assert_eq!(buf, [4,3,1,2]); - - { - let ptr_head = buf.place_front() <- 5; - assert_eq!(*ptr_head, 5); - } - { - let ptr_tail = buf.place_back() <- 6; - assert_eq!(*ptr_tail, 6); - } - assert_eq!(buf, [5,4,3,1,2,6]); -} - #[test] fn test_reserve_exact_2() { // This is all the same as test_reserve diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2eedb964f88..47c92028b14 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -76,7 +76,7 @@ use core::mem; #[cfg(not(test))] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{InPlace, Index, IndexMut, Place, Placer, RangeBounds}; +use core::ops::{Index, IndexMut, RangeBounds}; use core::ops; use core::ptr; use core::ptr::NonNull; @@ -1065,29 +1065,6 @@ impl Vec { } } - /// Returns a place for insertion at the back of the `Vec`. - /// - /// Using this method with placement syntax is equivalent to [`push`](#method.push), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// let mut vec = vec![1, 2]; - /// vec.place_back() <- 3; - /// vec.place_back() <- 4; - /// assert_eq!(&vec, &[1, 2, 3, 4]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_back(&mut self) -> PlaceBack { - PlaceBack { vec: self } - } - /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// @@ -2492,57 +2469,6 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> { #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Drain<'a, T> {} -/// A place for insertion at the back of a `Vec`. -/// -/// See [`Vec::place_back`](struct.Vec.html#method.place_back) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -#[derive(Debug)] -pub struct PlaceBack<'a, T: 'a> { - vec: &'a mut Vec, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for PlaceBack<'a, T> { - type Place = PlaceBack<'a, T>; - - fn make_place(self) -> Self { - // This will panic or abort if we would allocate > isize::MAX bytes - // or if the length increment would overflow for zero-sized types. - if self.vec.len == self.vec.buf.cap() { - self.vec.buf.double(); - } - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for PlaceBack<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for PlaceBack<'a, T> { - type Owner = &'a mut T; - - unsafe fn finalize(mut self) -> &'a mut T { - let ptr = self.pointer(); - self.vec.len += 1; - &mut *ptr - } -} - - /// A splicing iterator for `Vec`. /// /// This struct is created by the [`splice()`] method on [`Vec`]. See its diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 94d042a45aa..f28c8e38996 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -22,7 +22,7 @@ use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, Place, Placer, InPlace, RangeBounds}; +use core::ops::{Index, IndexMut, RangeBounds}; use core::ptr; use core::ptr::NonNull; use core::slice; @@ -1885,56 +1885,6 @@ impl VecDeque { debug_assert!(!self.is_full()); } } - - /// Returns a place for insertion at the back of the `VecDeque`. - /// - /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.place_back() <- 3; - /// buf.place_back() <- 4; - /// assert_eq!(&buf, &[3, 4]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_back(&mut self) -> PlaceBack { - PlaceBack { vec_deque: self } - } - - /// Returns a place for insertion at the front of the `VecDeque`. - /// - /// Using this method with placement syntax is equivalent to [`push_front`](#method.push_front), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.place_front() <- 3; - /// buf.place_front() <- 4; - /// assert_eq!(&buf, &[4, 3]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_front(&mut self) -> PlaceFront { - PlaceFront { vec_deque: self } - } } impl VecDeque { @@ -2662,98 +2612,6 @@ impl From> for Vec { } } -/// A place for insertion at the back of a `VecDeque`. -/// -/// See [`VecDeque::place_back`](struct.VecDeque.html#method.place_back) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -#[derive(Debug)] -pub struct PlaceBack<'a, T: 'a> { - vec_deque: &'a mut VecDeque, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for PlaceBack<'a, T> { - type Place = PlaceBack<'a, T>; - - fn make_place(self) -> Self { - self.vec_deque.grow_if_necessary(); - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for PlaceBack<'a, T> { - fn pointer(&mut self) -> *mut T { - unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for PlaceBack<'a, T> { - type Owner = &'a mut T; - - unsafe fn finalize(self) -> &'a mut T { - let head = self.vec_deque.head; - self.vec_deque.head = self.vec_deque.wrap_add(head, 1); - &mut *(self.vec_deque.ptr().offset(head as isize)) - } -} - -/// A place for insertion at the front of a `VecDeque`. -/// -/// See [`VecDeque::place_front`](struct.VecDeque.html#method.place_front) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol are subject to change", - issue = "30172")] -#[derive(Debug)] -pub struct PlaceFront<'a, T: 'a> { - vec_deque: &'a mut VecDeque, -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> Placer for PlaceFront<'a, T> { - type Place = PlaceFront<'a, T>; - - fn make_place(self) -> Self { - self.vec_deque.grow_if_necessary(); - self - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, T> Place for PlaceFront<'a, T> { - fn pointer(&mut self) -> *mut T { - let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); - unsafe { self.vec_deque.ptr().offset(tail as isize) } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, T> InPlace for PlaceFront<'a, T> { - type Owner = &'a mut T; - - unsafe fn finalize(self) -> &'a mut T { - self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); - &mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize)) - } -} - #[cfg(test)] mod tests { use test; diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 0b480b618fc..ce4f45762de 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -161,7 +161,6 @@ mod drop; mod function; mod generator; mod index; -mod place; mod range; mod try; mod unsize; @@ -200,8 +199,5 @@ pub use self::try::Try; #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace}; - #[unstable(feature = "coerce_unsized", issue = "27732")] pub use self::unsize::CoerceUnsized; diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs deleted file mode 100644 index b3dcf4e7ee9..00000000000 --- a/src/libcore/ops/place.rs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Both `PLACE <- EXPR` and `box EXPR` desugar into expressions -/// that allocate an intermediate "place" that holds uninitialized -/// state. The desugaring evaluates EXPR, and writes the result at -/// the address returned by the `pointer` method of this trait. -/// -/// A `Place` can be thought of as a special representation for a -/// hypothetical `&uninit` reference (which Rust cannot currently -/// express directly). That is, it represents a pointer to -/// uninitialized storage. -/// -/// The client is responsible for two steps: First, initializing the -/// payload (it can access its address via `pointer`). Second, -/// converting the agent to an instance of the owning pointer, via the -/// appropriate `finalize` method (see the `InPlace`. -/// -/// If evaluating EXPR fails, then it is up to the destructor for the -/// implementation of Place to clean up any intermediate state -/// (e.g. deallocate box storage, pop a stack, etc). -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub unsafe trait Place { - /// Returns the address where the input value will be written. - /// Note that the data at this address is generally uninitialized, - /// and thus one should use `ptr::write` for initializing it. - /// - /// This function must return a pointer through which a value - /// of type `Data` can be written. - fn pointer(&mut self) -> *mut Data; -} - -/// Interface to implementations of `PLACE <- EXPR`. -/// -/// `PLACE <- EXPR` effectively desugars into: -/// -/// ``` -/// # #![feature(placement_new_protocol, box_heap)] -/// # use std::ops::{Placer, Place, InPlace}; -/// # #[allow(non_snake_case)] -/// # fn main() { -/// # let PLACE = std::boxed::HEAP; -/// # let EXPR = 1; -/// let p = PLACE; -/// let mut place = Placer::make_place(p); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// unsafe { -/// std::ptr::write(raw_place, value); -/// InPlace::finalize(place) -/// } -/// # ; } -/// ``` -/// -/// The type of `PLACE <- EXPR` is derived from the type of `PLACE`; -/// if the type of `PLACE` is `P`, then the final type of the whole -/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` -/// traits). -/// -/// Values for types implementing this trait usually are transient -/// intermediate values (e.g. the return value of `Vec::emplace_back`) -/// or `Copy`, since the `make_place` method takes `self` by value. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Placer { - /// `Place` is the intermediate agent guarding the - /// uninitialized state for `Data`. - type Place: InPlace; - - /// Creates a fresh place from `self`. - fn make_place(self) -> Self::Place; -} - -/// Specialization of `Place` trait supporting `PLACE <- EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait InPlace: Place { - /// `Owner` is the type of the end value of `PLACE <- EXPR` - /// - /// Note that when `PLACE <- EXPR` is solely used for - /// side-effecting an existing data-structure, - /// e.g. `Vec::emplace_back`, then `Owner` need not carry any - /// information at all (e.g. it can be the unit type `()` in that - /// case). - type Owner; - - /// Converts self into the final value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// the returned instance of `Owner` and forgetting self. - unsafe fn finalize(self) -> Self::Owner; -} - -/// Core trait for the `box EXPR` form. -/// -/// `box EXPR` effectively desugars into: -/// -/// ``` -/// # #![feature(placement_new_protocol)] -/// # use std::ops::{BoxPlace, Place, Boxed}; -/// # #[allow(non_snake_case)] -/// # fn main() { -/// # let EXPR = 1; -/// let mut place = BoxPlace::make_place(); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// # let _: Box<_> = -/// unsafe { -/// ::std::ptr::write(raw_place, value); -/// Boxed::finalize(place) -/// } -/// # ; } -/// ``` -/// -/// The type of `box EXPR` is supplied from its surrounding -/// context; in the above expansion, the result type `T` is used -/// to determine which implementation of `Boxed` to use, and that -/// `` in turn dictates determines which -/// implementation of `BoxPlace` to use, namely: -/// `<::Place as BoxPlace>`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Boxed { - /// The kind of data that is stored in this kind of box. - type Data; /* (`Data` unused b/c cannot yet express below bound.) */ - /// The place that will negotiate the storage of the data. - type Place: BoxPlace; - - /// Converts filled place into final owning value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// returned instance of `Self` and forgetting `filled`. - unsafe fn finalize(filled: Self::Place) -> Self; -} - -/// Specialization of `Place` trait supporting `box EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait BoxPlace : Place { - /// Creates a globally fresh place. - fn make_place() -> Self; -} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 536d682566a..5f9f37094f5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2911,118 +2911,8 @@ impl<'a> LoweringContext<'a> { fn lower_expr(&mut self, e: &Expr) -> hir::Expr { let kind = match e.node { - // Issue #22181: - // Eventually a desugaring for `box EXPR` - // (similar to the desugaring above for `in PLACE BLOCK`) - // should go here, desugaring - // - // to: - // - // let mut place = BoxPlace::make_place(); - // let raw_place = Place::pointer(&mut place); - // let value = $value; - // unsafe { - // ::std::ptr::write(raw_place, value); - // Boxed::finalize(place) - // } - // - // But for now there are type-inference issues doing that. ExprKind::Box(ref inner) => hir::ExprBox(P(self.lower_expr(inner))), - // Desugar ExprBox: `in (PLACE) EXPR` - ExprKind::InPlace(ref placer, ref value_expr) => { - // to: - // - // let p = PLACE; - // let mut place = Placer::make_place(p); - // let raw_place = Place::pointer(&mut place); - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let placer_expr = P(self.lower_expr(placer)); - let value_expr = P(self.lower_expr(value_expr)); - - let placer_ident = self.str_to_ident("placer"); - let place_ident = self.str_to_ident("place"); - let p_ptr_ident = self.str_to_ident("p_ptr"); - - let make_place = ["ops", "Placer", "make_place"]; - let place_pointer = ["ops", "Place", "pointer"]; - let move_val_init = ["intrinsics", "move_val_init"]; - let inplace_finalize = ["ops", "InPlace", "finalize"]; - - let unstable_span = - self.allow_internal_unstable(CompilerDesugaringKind::BackArrow, e.span); - let make_call = |this: &mut LoweringContext, p, args| { - let path = P(this.expr_std_path(unstable_span, p, ThinVec::new())); - P(this.expr_call(e.span, path, args)) - }; - - let mk_stmt_let = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, false, bind, expr) - }; - - let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| { - this.stmt_let(e.span, true, bind, expr) - }; - - // let placer = ; - let (s1, placer_binding) = { mk_stmt_let(self, placer_ident, placer_expr) }; - - // let mut place = Placer::make_place(placer); - let (s2, place_binding) = { - let placer = self.expr_ident(e.span, placer_ident, placer_binding); - let call = make_call(self, &make_place, hir_vec![placer]); - mk_stmt_let_mut(self, place_ident, call) - }; - - // let p_ptr = Place::pointer(&mut place); - let (s3, p_ptr_binding) = { - let agent = P(self.expr_ident(e.span, place_ident, place_binding)); - let args = hir_vec![self.expr_mut_addr_of(e.span, agent)]; - let call = make_call(self, &place_pointer, args); - mk_stmt_let(self, p_ptr_ident, call) - }; - - // pop_unsafe!(EXPR)); - let pop_unsafe_expr = { - self.signal_block_expr( - hir_vec![], - value_expr, - e.span, - hir::PopUnsafeBlock(hir::CompilerGenerated), - ThinVec::new(), - ) - }; - - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let expr = { - let ptr = self.expr_ident(e.span, p_ptr_ident, p_ptr_binding); - let call_move_val_init = hir::StmtSemi( - make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), - self.next_id().node_id, - ); - let call_move_val_init = respan(e.span, call_move_val_init); - - let place = self.expr_ident(e.span, place_ident, place_binding); - let call = make_call(self, &inplace_finalize, hir_vec![place]); - P(self.signal_block_expr( - hir_vec![call_move_val_init], - call, - e.span, - hir::PushUnsafeBlock(hir::CompilerGenerated), - ThinVec::new(), - )) - }; - - let block = self.block_all(e.span, hir_vec![s1, s2, s3], Some(expr)); - hir::ExprBlock(P(block)) - } - ExprKind::Array(ref exprs) => { hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) } @@ -4069,29 +3959,6 @@ impl<'a> LoweringContext<'a> { .resolve_str_path(span, self.crate_root, components, is_value) } - fn signal_block_expr( - &mut self, - stmts: hir::HirVec, - expr: P, - span: Span, - rule: hir::BlockCheckMode, - attrs: ThinVec, - ) -> hir::Expr { - let LoweredNodeId { node_id, hir_id } = self.next_id(); - - let block = P(hir::Block { - rules: rule, - span, - id: node_id, - hir_id, - stmts, - expr: Some(expr), - targeted_by_break: false, - recovered: false, - }); - self.expr_block(block, attrs) - } - fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> P { let mut id = id; let node = match qpath { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 0b037964981..425459f448f 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -371,7 +371,6 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { - BackArrow, DotFill, QuestionMark }); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 86f79c553c3..aa93b3098e0 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -301,7 +301,6 @@ impl EarlyLintPass for UnusedParens { Ret(Some(ref value)) => (value, "`return` value", false), Assign(_, ref value) => (value, "assigned value", false), AssignOp(.., ref value) => (value, "assigned value", false), - InPlace(_, ref value) => (value, "emplacement value", false), // either function/method call, or something this lint doesn't care about ref call_or_other => { let args_to_check; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 09579eaecb2..c50d84c10d8 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -196,15 +196,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let mut values = Vec::with_capacity(used_variants); let tcx = self.hir.tcx(); for (idx, discr) in adt_def.discriminants(tcx).enumerate() { - target_blocks.place_back() <- if variants.contains(idx) { + target_blocks.push(if variants.contains(idx) { values.push(discr.val); - *(targets.place_back() <- self.cfg.start_new_block()) + targets.push(self.cfg.start_new_block()); + *targets.last().unwrap() } else { if otherwise_block.is_none() { otherwise_block = Some(self.cfg.start_new_block()); } otherwise_block.unwrap() - }; + }); } if let Some(otherwise_block) = otherwise_block { targets.push(otherwise_block); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 7af3a397666..84baa8c5417 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -34,8 +34,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(placement_in_syntax)] -#![feature(collection_placement)] #![feature(nonzero)] #![cfg_attr(stage0, feature(underscore_lifetimes))] #![cfg_attr(stage0, feature(never_type))] diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 1f882676f61..ca5858299c5 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -721,16 +721,6 @@ fn main() { ``` "##, -E0066: r##" -Box placement expressions (like C++'s "placement new") do not yet support any -place expression except the exchange heap (i.e. `std::boxed::HEAP`). -Furthermore, the syntax is changing to use `in` instead of `box`. See [RFC 470] -and [RFC 809] for more details. - -[RFC 470]: https://github.com/rust-lang/rfcs/pull/470 -[RFC 809]: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md -"##, - E0067: r##" The left-hand side of a compound assignment expression must be a place expression. A place expression represents a memory location and includes diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 452fa4e471c..e0b48e565d0 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -22,8 +22,7 @@ use fmt::{self, Debug}; use hash::{Hash, Hasher, BuildHasher, SipHasher13}; use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; -use ops::{Deref, Index, InPlace, Place, Placer}; -use ptr; +use ops::{Deref, Index}; use sys; use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; @@ -2043,80 +2042,6 @@ impl<'a, K, V> fmt::Debug for Drain<'a, K, V> } } -/// A place for insertion to a `Entry`. -/// -/// See [`HashMap::entry`](struct.HashMap.html#method.entry) for details. -#[must_use = "places do nothing unless written to with `<-` syntax"] -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -pub struct EntryPlace<'a, K: 'a, V: 'a> { - bucket: FullBucketMut<'a, K, V>, -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for EntryPlace<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("EntryPlace") - .field("key", self.bucket.read().0) - .field("value", self.bucket.read().1) - .finish() - } -} - -#[unstable(feature = "collection_placement", - reason = "struct name and placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> Drop for EntryPlace<'a, K, V> { - fn drop(&mut self) { - // Inplacement insertion failed. Only key need to drop. - // The value is failed to insert into map. - unsafe { self.bucket.remove_key() }; - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> Placer for Entry<'a, K, V> { - type Place = EntryPlace<'a, K, V>; - - fn make_place(self) -> EntryPlace<'a, K, V> { - let b = match self { - Occupied(mut o) => { - unsafe { ptr::drop_in_place(o.elem.read_mut().1); } - o.elem - } - Vacant(v) => { - unsafe { v.insert_key() } - } - }; - EntryPlace { bucket: b } - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -unsafe impl<'a, K, V> Place for EntryPlace<'a, K, V> { - fn pointer(&mut self) -> *mut V { - self.bucket.read_mut().1 - } -} - -#[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] -impl<'a, K, V> InPlace for EntryPlace<'a, K, V> { - type Owner = (); - - unsafe fn finalize(self) { - mem::forget(self); - } -} - impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns @@ -2539,26 +2464,6 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { }; b.into_mut_refs().1 } - - // Only used for InPlacement insert. Avoid unnecessary value copy. - // The value remains uninitialized. - unsafe fn insert_key(self) -> FullBucketMut<'a, K, V> { - match self.elem { - NeqElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - let uninit = mem::uninitialized(); - robin_hood(bucket, disp, self.hash, self.key, uninit) - }, - NoElem(mut bucket, disp) => { - if disp >= DISPLACEMENT_THRESHOLD { - bucket.table_mut().set_tag(true); - } - bucket.put_key(self.hash, self.key) - }, - } - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2823,7 +2728,6 @@ mod test_map { use super::RandomState; use cell::RefCell; use rand::{thread_rng, Rng}; - use panic; use realstd::collections::CollectionAllocErr::*; use realstd::mem::size_of; use realstd::usize; @@ -3709,59 +3613,6 @@ mod test_map { panic!("Adaptive early resize failed"); } - #[test] - fn test_placement_in() { - let mut map = HashMap::new(); - map.extend((0..10).map(|i| (i, i))); - - map.entry(100) <- 100; - assert_eq!(map[&100], 100); - - map.entry(0) <- 10; - assert_eq!(map[&0], 10); - - assert_eq!(map.len(), 11); - } - - #[test] - fn test_placement_panic() { - let mut map = HashMap::new(); - map.extend((0..10).map(|i| (i, i))); - - fn mkpanic() -> usize { panic!() } - - // modify existing key - // when panic happens, previous key is removed. - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(0) <- mkpanic(); })); - assert_eq!(map.len(), 9); - assert!(!map.contains_key(&0)); - - // add new key - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { map.entry(100) <- mkpanic(); })); - assert_eq!(map.len(), 9); - assert!(!map.contains_key(&100)); - } - - #[test] - fn test_placement_drop() { - // correctly drop - struct TestV<'a>(&'a mut bool); - impl<'a> Drop for TestV<'a> { - fn drop(&mut self) { - if !*self.0 { panic!("value double drop!"); } // no double drop - *self.0 = false; - } - } - - fn makepanic<'a>() -> TestV<'a> { panic!() } - - let mut can_drop = true; - let mut hm = HashMap::new(); - hm.insert(0, TestV(&mut can_drop)); - let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { hm.entry(0) <- makepanic(); })); - assert_eq!(hm.len(), 0); - } - #[test] fn test_try_reserve() { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index c6861c82a23..fa6053d3f6d 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -486,21 +486,6 @@ impl EmptyBucket table: self.table, } } - - /// Puts given key, remain value uninitialized. - /// It is only used for inplacement insertion. - pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket { - *self.raw.hash() = hash.inspect(); - let pair_ptr = self.raw.pair(); - ptr::write(&mut (*pair_ptr).0, key); - - self.table.borrow_table_mut().size += 1; - - FullBucket { - raw: self.raw, - table: self.table, - } - } } impl>> FullBucket { @@ -576,17 +561,6 @@ impl<'t, K, V> FullBucket> { v) } } - - /// Remove this bucket's `key` from the hashtable. - /// Only used for inplacement insertion. - /// NOTE: `Value` is uninitialized when this function is called, don't try to drop the `Value`. - pub unsafe fn remove_key(&mut self) { - self.table.size -= 1; - - *self.raw.hash() = EMPTY_BUCKET; - let pair_ptr = self.raw.pair(); - ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key - } } // This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 68d3b946d9e..e18e055654b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -290,7 +290,6 @@ #![feature(panic_internals)] #![feature(panic_unwind)] #![feature(peek)] -#![feature(placement_in_syntax)] #![feature(placement_new_protocol)] #![feature(prelude_import)] #![feature(ptr_internals)] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c90b0aecfc0..31bb1c88b87 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1011,7 +1011,6 @@ impl Expr { pub fn precedence(&self) -> ExprPrecedence { match self.node { ExprKind::Box(_) => ExprPrecedence::Box, - ExprKind::InPlace(..) => ExprPrecedence::InPlace, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, @@ -1071,8 +1070,6 @@ pub enum RangeLimits { pub enum ExprKind { /// A `box x` expression. Box(P), - /// First expr is the place; second expr is the value. - InPlace(P, P), /// An array (`[a, b, c, d]`) Array(Vec>), /// A function call diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 463e76e1461..e734a4e3735 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -146,7 +146,6 @@ declare_features! ( (active, rustc_diagnostic_macros, "1.0.0", None, None), (active, rustc_const_unstable, "1.0.0", None, None), (active, box_syntax, "1.0.0", Some(27779), None), - (active, placement_in_syntax, "1.0.0", Some(27779), None), (active, unboxed_closures, "1.0.0", Some(29625), None), (active, fundamental, "1.0.0", Some(29635), None), @@ -1287,9 +1286,6 @@ pub const EXPLAIN_VIS_MATCHER: &'static str = pub const EXPLAIN_LIFETIME_MATCHER: &'static str = ":lifetime fragment specifier is experimental and subject to change"; -pub const EXPLAIN_PLACEMENT_IN: &'static str = - "placement-in expression syntax is experimental and subject to change."; - pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = "Unsized tuple coercion is not stable enough for use and is subject to change"; @@ -1636,9 +1632,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, type_ascription, e.span, "type ascription is experimental"); } - ast::ExprKind::InPlace(..) => { - gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); - } ast::ExprKind::Yield(..) => { gate_feature_post!(&self, generators, e.span, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 05a3150c139..e702bf56e7f 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1167,9 +1167,6 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Box(e) => { ExprKind::Box(folder.fold_expr(e)) } - ExprKind::InPlace(p, e) => { - ExprKind::InPlace(folder.fold_expr(p), folder.fold_expr(e)) - } ExprKind::Array(exprs) => { ExprKind::Array(folder.fold_exprs(exprs)) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f7cdd4ba2b4..f5ab023b30e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2850,17 +2850,6 @@ impl<'a> Parser<'a> { let (span, e) = self.interpolated_or_expr_span(e)?; (lo.to(span), ExprKind::AddrOf(m, e)) } - token::Ident(..) if self.token.is_keyword(keywords::In) => { - self.bump(); - let place = self.parse_expr_res( - Restrictions::NO_STRUCT_LITERAL, - None, - )?; - let blk = self.parse_block()?; - let span = blk.span; - let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); - (lo.to(span), ExprKind::InPlace(place, blk_expr)) - } token::Ident(..) if self.token.is_keyword(keywords::Box) => { self.bump(); let e = self.parse_prefix_expr(None); @@ -3023,8 +3012,6 @@ impl<'a> Parser<'a> { } AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), - AssocOp::Inplace => - self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ae045fc095a..c3785c10f69 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1877,16 +1877,6 @@ impl<'a> State<'a> { Ok(()) } - fn print_expr_in_place(&mut self, - place: &ast::Expr, - expr: &ast::Expr) -> io::Result<()> { - let prec = AssocOp::Inplace.precedence() as i8; - self.print_expr_maybe_paren(place, prec + 1)?; - self.s.space()?; - self.word_space("<-")?; - self.print_expr_maybe_paren(expr, prec) - } - fn print_expr_vec(&mut self, exprs: &[P], attrs: &[Attribute]) -> io::Result<()> { self.ibox(INDENT_UNIT)?; @@ -2056,9 +2046,6 @@ impl<'a> State<'a> { self.word_space("box")?; self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)?; } - ast::ExprKind::InPlace(ref place, ref expr) => { - self.print_expr_in_place(place, expr)?; - } ast::ExprKind::Array(ref exprs) => { self.print_expr_vec(&exprs[..], attrs)?; } diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 86963c4000b..4770273e8c4 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -56,8 +56,6 @@ pub enum AssocOp { GreaterEqual, /// `=` Assign, - /// `<-` - Inplace, /// `?=` where ? is one of the BinOpToken AssignOp(BinOpToken), /// `as` @@ -86,7 +84,6 @@ impl AssocOp { use self::AssocOp::*; match *t { Token::BinOpEq(k) => Some(AssignOp(k)), - Token::LArrow => Some(Inplace), Token::Eq => Some(Assign), Token::BinOp(BinOpToken::Star) => Some(Multiply), Token::BinOp(BinOpToken::Slash) => Some(Divide), @@ -156,7 +153,6 @@ impl AssocOp { LAnd => 6, LOr => 5, DotDot | DotDotEq => 4, - Inplace => 3, Assign | AssignOp(_) => 2, } } @@ -166,7 +162,7 @@ impl AssocOp { use self::AssocOp::*; // NOTE: it is a bug to have an operators that has same precedence but different fixities! match *self { - Inplace | Assign | AssignOp(_) => Fixity::Right, + Assign | AssignOp(_) => Fixity::Right, As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | LAnd | LOr | Colon => Fixity::Left, @@ -178,7 +174,7 @@ impl AssocOp { use self::AssocOp::*; match *self { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, - Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | + Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false } @@ -187,7 +183,7 @@ impl AssocOp { pub fn is_assign_like(&self) -> bool { use self::AssocOp::*; match *self { - Assign | AssignOp(_) | Inplace => true, + Assign | AssignOp(_) => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false @@ -215,7 +211,7 @@ impl AssocOp { BitOr => Some(BinOpKind::BitOr), LAnd => Some(BinOpKind::And), LOr => Some(BinOpKind::Or), - Inplace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None + Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None } } } @@ -242,7 +238,6 @@ pub enum ExprPrecedence { Binary(BinOpKind), - InPlace, Cast, Type, @@ -310,7 +305,6 @@ impl ExprPrecedence { // Binop-like expr kinds, handled by `AssocOp`. ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8, - ExprPrecedence::InPlace => AssocOp::Inplace.precedence() as i8, ExprPrecedence::Cast => AssocOp::As.precedence() as i8, ExprPrecedence::Type => AssocOp::Colon.precedence() as i8, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bbf1fe124f1..d8de78054ab 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -654,10 +654,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression) } - ExprKind::InPlace(ref place, ref subexpression) => { - visitor.visit_expr(place); - visitor.visit_expr(subexpression) - } ExprKind::Array(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 85a2940ec44..aba71bd0468 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -430,7 +430,6 @@ pub enum ExpnFormat { /// The kind of compiler desugaring. #[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { - BackArrow, DotFill, QuestionMark, } @@ -439,7 +438,6 @@ impl CompilerDesugaringKind { pub fn as_symbol(&self) -> Symbol { use CompilerDesugaringKind::*; let s = match *self { - BackArrow => "<-", DotFill => "...", QuestionMark => "?", }; diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs deleted file mode 100644 index 446514c8dd4..00000000000 --- a/src/test/compile-fail/issue-14084.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(box_syntax)] -#![feature(placement_in_syntax)] - -fn main() { - () <- 0; - //~^ ERROR: `(): std::ops::Placer<_>` is not satisfied -} diff --git a/src/test/compile-fail/placement-expr-unsafe.rs b/src/test/compile-fail/placement-expr-unsafe.rs deleted file mode 100644 index bf6f4c52f1f..00000000000 --- a/src/test/compile-fail/placement-expr-unsafe.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Check that placement in respects unsafe code checks. - -#![feature(box_heap)] -#![feature(placement_in_syntax)] - -fn main() { - use std::boxed::HEAP; - - let p: *const i32 = &42; - let _ = HEAP <- *p; //~ ERROR requires unsafe - - let p: *const _ = &HEAP; - let _ = *p <- 42; //~ ERROR requires unsafe -} diff --git a/src/test/compile-fail/placement-expr-unstable.rs b/src/test/compile-fail/placement-expr-unstable.rs deleted file mode 100644 index 35695efe1a9..00000000000 --- a/src/test/compile-fail/placement-expr-unstable.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Check that placement in respects unstable code checks. - -#![feature(placement_in_syntax)] - -fn main() { - use std::boxed::HEAP; //~ ERROR use of unstable library feature - - let _ = HEAP <- { //~ ERROR use of unstable library feature - HEAP //~ ERROR use of unstable library feature - }; -} diff --git a/src/test/parse-fail/assoc-oddities-1.rs b/src/test/parse-fail/assoc-oddities-1.rs index 5c0c47de58a..63408b76b15 100644 --- a/src/test/parse-fail/assoc-oddities-1.rs +++ b/src/test/parse-fail/assoc-oddities-1.rs @@ -13,10 +13,9 @@ fn that_odd_parse() { // following lines below parse and must not fail x = if c { a } else { b }(); - x <- if c { a } else { b }[n]; x = if true { 1 } else { 0 } as *mut _; // however this does not parse and probably should fail to retain compat? - // NB: `..` here is arbitrary, failure happens/should happen ∀ops that aren’t `=` or `<-` + // NB: `..` here is arbitrary, failure happens/should happen ∀ops that aren’t `=` // see assoc-oddities-2 and assoc-oddities-3 ..if c { a } else { b }[n]; //~ ERROR expected one of } diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 17e6119f968..b34e1852079 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -12,7 +12,6 @@ #![feature(custom_attribute)] #![feature(box_syntax)] -#![feature(placement_in_syntax)] #![feature(stmt_expr_attributes)] fn main() { } diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index f3f7777d8d4..62cb870c7bb 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -126,16 +126,6 @@ fn run() { check_expr_attrs("#[attr] box 0", outer); reject_expr_parse("box #![attr] 0"); - check_expr_attrs("#[attr] 0 <- #[attr] 0", none); - check_expr_attrs("#[attr] (0 <- 0)", outer); - reject_expr_parse("0 #[attr] <- 0"); - reject_expr_parse("0 <- #![attr] 0"); - - check_expr_attrs("in #[attr] 0 {#[attr] 0}", none); - check_expr_attrs("#[attr] (in 0 {0})", outer); - reject_expr_parse("in 0 #[attr] {0}"); - reject_expr_parse("in 0 {#![attr] 0}"); - check_expr_attrs("#[attr] [#![attr]]", both); check_expr_attrs("#[attr] [#![attr] 0]", both); check_expr_attrs("#[attr] [#![attr] 0; 0]", both); diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs index 05fe274c49f..920760cd34a 100644 --- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs @@ -84,18 +84,11 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { let mut g = |e| f(expr(e)); - for kind in 0 .. 17 { + for kind in 0 .. 16 { match kind { 0 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Box(e))), - 1 => { - // Note that for binary expressions, we explore each side separately. The - // parenthesization decisions for the LHS and RHS should be independent, and this - // way produces `O(n)` results instead of `O(n^2)`. - iter_exprs(depth - 1, &mut |e| g(ExprKind::InPlace(e, make_x()))); - iter_exprs(depth - 1, &mut |e| g(ExprKind::InPlace(make_x(), e))); - }, - 2 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))), - 3 => { + 1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))), + 2 => { let seg = PathSegment { identifier: Ident::from_str("x"), span: DUMMY_SP, @@ -107,25 +100,25 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall( seg.clone(), vec![make_x(), e]))); }, - 4 => { + 3 => { let op = Spanned { span: DUMMY_SP, node: BinOpKind::Add }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); }, - 5 => { + 4 => { let op = Spanned { span: DUMMY_SP, node: BinOpKind::Mul }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); }, - 6 => { + 5 => { let op = Spanned { span: DUMMY_SP, node: BinOpKind::Shl }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e))); }, - 7 => { + 6 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e))); }, - 8 => { + 7 => { let block = P(Block { stmts: Vec::new(), id: DUMMY_NODE_ID, @@ -135,7 +128,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, - 9 => { + 8 => { let decl = P(FnDecl { inputs: vec![], output: FunctionRetTy::Default(DUMMY_SP), @@ -148,28 +141,28 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { e, DUMMY_SP))); }, - 10 => { + 9 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x()))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e))); }, - 11 => { + 10 => { let ident = Spanned { span: DUMMY_SP, node: Ident::from_str("f") }; iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, ident))); }, - 12 => { + 11 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( Some(e), Some(make_x()), RangeLimits::HalfOpen))); iter_exprs(depth - 1, &mut |e| g(ExprKind::Range( Some(make_x()), Some(e), RangeLimits::HalfOpen))); }, - 13 => { + 12 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::AddrOf(Mutability::Immutable, e))); }, - 14 => { + 13 => { g(ExprKind::Ret(None)); iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e)))); }, - 15 => { + 14 => { let seg = PathSegment { identifier: Ident::from_str("S"), span: DUMMY_SP, @@ -181,7 +174,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { }; g(ExprKind::Struct(path, vec![], Some(make_x()))); }, - 16 => { + 15 => { iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e))); }, _ => panic!("bad counter value in iter_exprs"), diff --git a/src/test/run-pass/new-box-syntax.rs b/src/test/run-pass/new-box-syntax.rs index 34687c6ca1d..6598b70b3d5 100644 --- a/src/test/run-pass/new-box-syntax.rs +++ b/src/test/run-pass/new-box-syntax.rs @@ -14,16 +14,11 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ #![allow(dead_code, unused_variables)] -#![feature(box_syntax, box_heap)] -#![feature(placement_in_syntax)] - -// during check-pretty, the expanded code needs to opt into these -// features -#![feature(placement_new_protocol, core_intrinsics)] +#![feature(box_syntax)] // Tests that the new `box` syntax works with unique pointers. -use std::boxed::{Box, HEAP}; +use std::boxed::Box; struct Structure { x: isize, @@ -31,7 +26,6 @@ struct Structure { } pub fn main() { - let x: Box = in HEAP { 2 }; let y: Box = box 2; let b: Box = box (1 + 2); let c = box (3 + 4); diff --git a/src/test/run-pass/placement-in-syntax.rs b/src/test/run-pass/placement-in-syntax.rs deleted file mode 100644 index 7bda9ae2524..00000000000 --- a/src/test/run-pass/placement-in-syntax.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code, unused_variables)] -#![feature(box_heap)] -#![feature(placement_in_syntax)] - -// Tests that the new `in` syntax works with unique pointers. -// -// Compare with new-box-syntax.rs - -use std::boxed::{Box, HEAP}; - -struct Structure { - x: isize, - y: isize, -} - -pub fn main() { - let x: Box = in HEAP { 2 }; - let b: Box = in HEAP { 1 + 2 }; - let c = in HEAP { 3 + 4 }; - - let s: Box = in HEAP { - Structure { - x: 3, - y: 4, - } - }; -} diff --git a/src/test/ui/feature-gate-placement-expr.rs b/src/test/ui/feature-gate-placement-expr.rs deleted file mode 100644 index e3478876763..00000000000 --- a/src/test/ui/feature-gate-placement-expr.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// gate-test-placement_in_syntax - -// Check that `in PLACE { EXPR }` is feature-gated. -// -// See also feature-gate-box-expr.rs -// -// (Note that the two tests are separated since the checks appear to -// be performed at distinct phases, with an abort_if_errors call -// separating them.) - -fn main() { - use std::boxed::HEAP; - - let x = HEAP <- 'c'; //~ ERROR placement-in expression syntax is experimental - println!("x: {}", x); -} diff --git a/src/test/ui/feature-gate-placement-expr.stderr b/src/test/ui/feature-gate-placement-expr.stderr deleted file mode 100644 index b5c091763a1..00000000000 --- a/src/test/ui/feature-gate-placement-expr.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: placement-in expression syntax is experimental and subject to change. (see issue #27779) - --> $DIR/feature-gate-placement-expr.rs:24:13 - | -LL | let x = HEAP <- 'c'; //~ ERROR placement-in expression syntax is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(placement_in_syntax)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 333b0a0471c2593e46c8f13124ee28178f5c9643 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Tue, 3 Apr 2018 09:20:04 -0400 Subject: tweak format_args! docs Swap the variable names in the example. --- src/libstd/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 47609f17221..5ef7c159655 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -341,8 +341,8 @@ pub mod builtin { /// format string in `format_args!`. /// /// ```rust - /// let display = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); - /// let debug = format!("{}", format_args!("{} foo {:?}", 1, 2)); + /// let debug = format!("{:?}", format_args!("{} foo {:?}", 1, 2)); + /// let display = format!("{}", format_args!("{} foo {:?}", 1, 2)); /// assert_eq!("1 foo 2", display); /// assert_eq!(display, debug); /// ``` -- cgit 1.4.1-3-g733a5 From 1ce98f34d38fa9338ff696f904bcb8c01856f935 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 2 Apr 2018 09:11:07 -0700 Subject: Cross-reference fs::read functions from io::Read docs --- src/libstd/io/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 63b631ace96..3b8c42ddb39 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -595,6 +595,11 @@ pub trait Read { /// Ok(()) /// } /// ``` + /// + /// (See also the [`std::fs::read`] convenience function for reading from a + /// file.) + /// + /// [`std::fs::read`]: ../fs/fn.read.html #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec) -> Result { read_to_end(self, buf) @@ -633,6 +638,11 @@ pub trait Read { /// Ok(()) /// } /// ``` + /// + /// (See also the [`std::fs::read_to_string`] convenience function for + /// reading from a file.) + /// + /// [`std::fs::read_to_string`]: ../fs/fn.read_to_string.html #[stable(feature = "rust1", since = "1.0.0")] fn read_to_string(&mut self, buf: &mut String) -> Result { // Note that we do *not* call `.read_to_end()` here. We are passing -- cgit 1.4.1-3-g733a5 From 390f8367e74d72317ab4aa5097048243073968fa Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Mon, 2 Apr 2018 09:31:04 -0700 Subject: Add performance notes to BufReader/BufWriter docs --- src/libstd/io/buffered.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index cefff2f143c..91f07ecc663 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -25,6 +25,12 @@ use memchr; /// results in a system call. A `BufReader` performs large, infrequent reads on /// the underlying [`Read`] and maintains an in-memory buffer of the results. /// +/// `BufReader` can improve the speed of programs that make *small* and +/// *repeated* read calls to the same file or network socket. It does not +/// help when reading very large amounts at once, or reading just one or a few +/// times. It also provides no advantage when reading from a source that is +/// already in memory, like a `Vec`. +/// /// [`Read`]: ../../std/io/trait.Read.html /// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html @@ -359,6 +365,12 @@ impl Seek for BufReader { /// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying /// writer in large, infrequent batches. /// +/// `BufWriter` can improve the speed of programs that make *small* and +/// *repeated* write calls to the same file or network socket. It does not +/// help when writing very large amounts at once, or writing just one or a few +/// times. It also provides no advantage when writing to a destination that is +/// in memory, like a `Vec`. +/// /// When the `BufWriter` is dropped, the contents of its buffer will be written /// out. However, any errors that happen in the process of flushing the buffer /// when the writer is dropped will be ignored. Code that wishes to handle such -- cgit 1.4.1-3-g733a5 From 97ac479066a16d06ad4eb2cc2a4f58d1e7aa37b8 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Tue, 3 Apr 2018 19:47:37 -0600 Subject: Stabilize parent_id() Fixes #46104 --- src/libstd/sys/unix/ext/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 60309bec6d4..7b4ec20d91f 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -193,7 +193,7 @@ impl IntoRawFd for process::ChildStderr { } /// Returns the OS-assigned process identifier associated with this process's parent. -#[unstable(feature = "unix_ppid", issue = "46104")] +#[stable(feature = "unix_ppid", since = "1.27.0")] pub fn parent_id() -> u32 { ::sys::os::getppid() } -- cgit 1.4.1-3-g733a5 From 4577da75f4badd66a337eb15da76ca836ab1ad6e Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 4 Apr 2018 19:30:46 +0900 Subject: Use box syntax instead of Box::new in Mutex::remutex on Windows The Box::new(mem::uninitialized()) pattern actually actively copies uninitialized bytes from the stack into the box, which is a waste of time. Using the box syntax instead avoids the useless copy. --- src/libstd/sys/windows/mutex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 85560368590..9bf9f749d4d 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -117,7 +117,7 @@ impl Mutex { 0 => {} n => return n as *mut _, } - let mut re = Box::new(ReentrantMutex::uninitialized()); + let mut re = box ReentrantMutex::uninitialized(); re.init(); let re = Box::into_raw(re); match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { -- cgit 1.4.1-3-g733a5 From 5c58eec0bd8cee8fb2a191396d5ad5b5c9b0116a Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Wed, 4 Apr 2018 19:10:38 -0400 Subject: Replace manual iter exhaust with for_each(drop). --- src/liballoc/btree/map.rs | 3 +-- src/liballoc/linked_list.rs | 2 +- src/liballoc/vec.rs | 9 +++------ src/liballoc/vec_deque.rs | 2 +- src/librustc_data_structures/array_vec.rs | 4 ++-- src/libstd/collections/hash/table.rs | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index ed9c8c18f0d..37274a3c3ec 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -1260,8 +1260,7 @@ impl IntoIterator for BTreeMap { #[stable(feature = "btree_drop", since = "1.7.0")] impl Drop for IntoIter { fn drop(&mut self) { - for _ in &mut *self { - } + self.for_each(drop); unsafe { let leaf_node = ptr::read(&self.front).into_node(); if let Some(first_parent) = leaf_node.deallocate_and_ascend() { diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs index 097d2e414f5..b633787fadf 100644 --- a/src/liballoc/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -1076,7 +1076,7 @@ impl<'a, T, F> Drop for DrainFilter<'a, T, F> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - for _ in self { } + self.for_each(drop); } } diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2f57c53a6d8..635ffe08e9c 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2354,7 +2354,7 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> { impl<'a, T> Drop for Drain<'a, T> { fn drop(&mut self) { // exhaust self first - while let Some(_) = self.next() {} + self.for_each(drop); if self.tail_len > 0 { unsafe { @@ -2474,9 +2474,7 @@ impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {} #[stable(feature = "vec_splice", since = "1.21.0")] impl<'a, I: Iterator> Drop for Splice<'a, I> { fn drop(&mut self) { - // exhaust drain first - while let Some(_) = self.drain.next() {} - + self.drain.by_ref().for_each(drop); unsafe { if self.drain.tail_len == 0 { @@ -2605,8 +2603,7 @@ impl<'a, T, F> Drop for DrainFilter<'a, T, F> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - for _ in self.by_ref() { } - + self.for_each(drop); unsafe { self.vec.set_len(self.old_len - self.del); } diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 68add3cbd51..ee9d8e796ab 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -2177,7 +2177,7 @@ unsafe impl<'a, T: Send> Send for Drain<'a, T> {} #[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { - for _ in self.by_ref() {} + self.for_each(drop); let source_deque = unsafe { self.deque.as_mut() }; diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 511c407d45a..34e19bba08b 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -207,7 +207,7 @@ pub struct Iter { impl Drop for Iter { fn drop(&mut self) { - for _ in self {} + self.for_each(drop); } } @@ -251,7 +251,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> { impl<'a, A: Array> Drop for Drain<'a, A> { fn drop(&mut self) { // exhaust self first - while let Some(_) = self.next() {} + self.for_each(drop); if self.tail_len > 0 { unsafe { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 73bd5747c10..4ed1e159a0a 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1129,7 +1129,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { fn drop(&mut self) { - for _ in self {} + self.for_each(drop); } } -- cgit 1.4.1-3-g733a5 From 1a2a23447e451faee7ffbffab2be8831f3098f6d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 8 Mar 2018 22:24:10 +0300 Subject: Stabilize attributes on generic parameters --- src/liballoc/lib.rs | 2 +- src/libarena/lib.rs | 2 +- src/librustc_typeck/diagnostics.rs | 1 - src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 20 +-- .../attrs-with-no-formal-in-generics-1.rs | 3 +- .../attrs-with-no-formal-in-generics-2.rs | 3 +- src/test/compile-fail/synthetic-param.rs | 2 +- .../mir-opt/end_region_destruction_extents_1.rs | 1 - src/test/run-pass/attr-on-generic-formals.rs | 2 +- .../auxiliary/dropck_eyepatch_extern_crate.rs | 1 - src/test/run-pass/dropck-eyepatch-reorder.rs | 1 - src/test/run-pass/dropck-eyepatch.rs | 1 - .../auxiliary/dropck_eyepatch_extern_crate.rs | 1 - .../dropck/dropck-eyepatch-implies-unsafe-impl.rs | 1 - .../dropck-eyepatch-implies-unsafe-impl.stderr | 4 +- src/test/ui/dropck/dropck-eyepatch-reorder.rs | 1 - src/test/ui/dropck/dropck-eyepatch-reorder.stderr | 8 +- src/test/ui/dropck/dropck-eyepatch.rs | 1 - src/test/ui/dropck/dropck-eyepatch.stderr | 8 +- src/test/ui/feature-gate-custom_attribute2.rs | 7 -- src/test/ui/feature-gate-custom_attribute2.stderr | 34 ++--- src/test/ui/feature-gate-generic_param_attrs.rs | 76 ----------- .../ui/feature-gate-generic_param_attrs.stderr | 139 --------------------- src/test/ui/feature-gate-may-dangle.rs | 2 - src/test/ui/feature-gate-may-dangle.stderr | 2 +- src/test/ui/generic-param-attrs.rs | 54 ++++++++ src/test/ui/nll/drop-may-dangle.rs | 1 - src/test/ui/nll/drop-no-may-dangle.rs | 1 - src/test/ui/nll/drop-no-may-dangle.stderr | 4 +- 30 files changed, 93 insertions(+), 292 deletions(-) delete mode 100644 src/test/ui/feature-gate-generic_param_attrs.rs delete mode 100644 src/test/ui/feature-gate-generic_param_attrs.stderr create mode 100644 src/test/ui/generic-param-attrs.rs (limited to 'src/libstd') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2fad3b0bad4..cbbea6c19c8 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,7 +97,7 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![feature(generic_param_attrs)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(stage0, feature(i128_type))] #![feature(iter_rfold)] #![feature(lang_items)] diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 72fa3148fe5..7eaf67e6ea6 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -27,7 +27,7 @@ #![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(generic_param_attrs)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(test, feature(test))] #![allow(deprecated)] diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 99726bb65f3..79d7c8e7282 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3784,7 +3784,6 @@ that impl must be declared as an `unsafe impl. Erroneous code example: ```compile_fail,E0569 -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] struct Foo(X); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index e18e055654b..3f1fec4c317 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -266,7 +266,7 @@ #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] -#![feature(generic_param_attrs)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(hashmap_internals)] #![feature(heap_api)] #![cfg_attr(stage0, feature(i128_type, i128))] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e734a4e3735..1cf62a8bf33 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -288,9 +288,6 @@ declare_features! ( // rustc internal (active, compiler_builtins, "1.13.0", None, None), - // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) - (active, generic_param_attrs, "1.11.0", Some(34761), None), - // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406), None), @@ -566,6 +563,8 @@ declare_features! ( (accepted, match_default_bindings, "1.26.0", Some(42640), None), // allow `'_` placeholder lifetimes (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), + // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) + (accepted, generic_param_attrs, "1.26.0", Some(48848), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1775,21 +1774,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } visit::walk_vis(self, vis); } - - fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { - let (attrs, explain) = match *param { - ast::GenericParam::Lifetime(ref ld) => - (&ld.attrs, "attributes on lifetime bindings are experimental"), - ast::GenericParam::Type(ref t) => - (&t.attrs, "attributes on type parameter bindings are experimental"), - }; - - if !attrs.is_empty() { - gate_feature_post!(&self, generic_param_attrs, attrs[0].span, explain); - } - - visit::walk_generic_param(self, param) - } } pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs index 53e287cda20..ec7885f1f44 100644 --- a/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs +++ b/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs @@ -12,8 +12,7 @@ // `#[oops]` is left dangling (that is, it is unattached, with no // formal binding following it). -#![feature(generic_param_attrs, rustc_attrs)] -#![allow(dead_code)] +#![feature(rustc_attrs)] struct RefIntPair<'a, 'b>(&'a u32, &'b u32); diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs index 5e09473ab77..efe2d5561a8 100644 --- a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs +++ b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs @@ -12,8 +12,7 @@ // `#[oops]` is left dangling (that is, it is unattached, with no // formal binding following it). -#![feature(generic_param_attrs, rustc_attrs)] -#![allow(dead_code)] +#![feature(rustc_attrs)] struct RefAny<'a, T>(&'a T); diff --git a/src/test/compile-fail/synthetic-param.rs b/src/test/compile-fail/synthetic-param.rs index a9762e383fe..337cae1369e 100644 --- a/src/test/compile-fail/synthetic-param.rs +++ b/src/test/compile-fail/synthetic-param.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs, rustc_attrs)] +#![feature(rustc_attrs)] fn func<#[rustc_synthetic] T>(_: T) {} diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs index 69c5cdccf49..e189f2e3b34 100644 --- a/src/test/mir-opt/end_region_destruction_extents_1.rs +++ b/src/test/mir-opt/end_region_destruction_extents_1.rs @@ -14,7 +14,6 @@ // A scenario with significant destruction code extents (which have // suffix "dce" in current `-Z identify_regions` rendering). -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] fn main() { diff --git a/src/test/run-pass/attr-on-generic-formals.rs b/src/test/run-pass/attr-on-generic-formals.rs index 5985284d849..e87b9e3d82a 100644 --- a/src/test/run-pass/attr-on-generic-formals.rs +++ b/src/test/run-pass/attr-on-generic-formals.rs @@ -17,7 +17,7 @@ // using `rustc_attrs` feature. There is a separate compile-fail/ test // ensuring that the attribute feature-gating works in this context.) -#![feature(generic_param_attrs, rustc_attrs)] +#![feature(rustc_attrs)] #![allow(dead_code)] struct StLt<#[rustc_lt_struct] 'a>(&'a u32); diff --git a/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs b/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs index 1266e589b12..d8912943441 100644 --- a/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs +++ b/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] // The point of this test is to illustrate that the `#[may_dangle]` diff --git a/src/test/run-pass/dropck-eyepatch-reorder.rs b/src/test/run-pass/dropck-eyepatch-reorder.rs index bbf8bb8c352..a99a7232e9e 100644 --- a/src/test/run-pass/dropck-eyepatch-reorder.rs +++ b/src/test/run-pass/dropck-eyepatch-reorder.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] // The point of this test is to test uses of `#[may_dangle]` attribute diff --git a/src/test/run-pass/dropck-eyepatch.rs b/src/test/run-pass/dropck-eyepatch.rs index 4a09ba05dff..c0c091d78eb 100644 --- a/src/test/run-pass/dropck-eyepatch.rs +++ b/src/test/run-pass/dropck-eyepatch.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] // The point of this test is to illustrate that the `#[may_dangle]` diff --git a/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs index 1b00d88dcb3..08722ca62ac 100644 --- a/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs +++ b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] // This is a support file for ../dropck-eyepatch-extern-crate.rs diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs index f92c8703dc9..cba438b02a9 100644 --- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] // This test ensures that a use of `#[may_dangle]` is rejected if diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr index f4ea7f1bc50..9d68ff13ef3 100644 --- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -1,5 +1,5 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute - --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1 + --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:31:1 | LL | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { LL | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute @@ -10,7 +10,7 @@ LL | | } | |_^ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute - --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1 + --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:37:1 | LL | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { LL | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.rs b/src/test/ui/dropck/dropck-eyepatch-reorder.rs index 3bd9efb32b3..eda8d85f6ec 100644 --- a/src/test/ui/dropck/dropck-eyepatch-reorder.rs +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] // The point of this test is to test uses of `#[may_dangle]` attribute diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr index e6ce53402f4..1a35996a0ca 100644 --- a/src/test/ui/dropck/dropck-eyepatch-reorder.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr @@ -1,5 +1,5 @@ error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:57:20 + --> $DIR/dropck-eyepatch-reorder.rs:56:20 | LL | dt = Dt("dt", &c); | ^ borrowed value does not live long enough @@ -10,7 +10,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:59:20 + --> $DIR/dropck-eyepatch-reorder.rs:58:20 | LL | dr = Dr("dr", &c); | ^ borrowed value does not live long enough @@ -21,7 +21,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:67:29 + --> $DIR/dropck-eyepatch-reorder.rs:66:29 | LL | pt = Pt("pt", &c_long, &c); | ^ borrowed value does not live long enough @@ -32,7 +32,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch-reorder.rs:69:29 + --> $DIR/dropck-eyepatch-reorder.rs:68:29 | LL | pr = Pr("pr", &c_long, &c); | ^ borrowed value does not live long enough diff --git a/src/test/ui/dropck/dropck-eyepatch.rs b/src/test/ui/dropck/dropck-eyepatch.rs index abaae47189f..af173a2e979 100644 --- a/src/test/ui/dropck/dropck-eyepatch.rs +++ b/src/test/ui/dropck/dropck-eyepatch.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generic_param_attrs)] #![feature(dropck_eyepatch)] // The point of this test is to illustrate that the `#[may_dangle]` diff --git a/src/test/ui/dropck/dropck-eyepatch.stderr b/src/test/ui/dropck/dropck-eyepatch.stderr index 5e0a4a74421..4d291642022 100644 --- a/src/test/ui/dropck/dropck-eyepatch.stderr +++ b/src/test/ui/dropck/dropck-eyepatch.stderr @@ -1,5 +1,5 @@ error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch.rs:80:20 + --> $DIR/dropck-eyepatch.rs:79:20 | LL | dt = Dt("dt", &c); | ^ borrowed value does not live long enough @@ -10,7 +10,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch.rs:82:20 + --> $DIR/dropck-eyepatch.rs:81:20 | LL | dr = Dr("dr", &c); | ^ borrowed value does not live long enough @@ -21,7 +21,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch.rs:90:29 + --> $DIR/dropck-eyepatch.rs:89:29 | LL | pt = Pt("pt", &c_long, &c); | ^ borrowed value does not live long enough @@ -32,7 +32,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c` does not live long enough - --> $DIR/dropck-eyepatch.rs:92:29 + --> $DIR/dropck-eyepatch.rs:91:29 | LL | pr = Pr("pr", &c_long, &c); | ^ borrowed value does not live long enough diff --git a/src/test/ui/feature-gate-custom_attribute2.rs b/src/test/ui/feature-gate-custom_attribute2.rs index 0d89c52d885..30fd89f091b 100644 --- a/src/test/ui/feature-gate-custom_attribute2.rs +++ b/src/test/ui/feature-gate-custom_attribute2.rs @@ -10,16 +10,9 @@ // This test ensures that attributes on formals in generic parameter // lists are included when we are checking for unstable attributes. -// -// Note that feature(generic_param_attrs) *is* enabled here. We are -// checking feature-gating of the attributes themselves, not the -// capability to parse such attributes in that context. // gate-test-custom_attribute -#![feature(generic_param_attrs)] -#![allow(dead_code)] - struct StLt<#[lt_struct] 'a>(&'a u32); //~^ ERROR The attribute `lt_struct` is currently unknown to the compiler struct StTy<#[ty_struct] I>(I); diff --git a/src/test/ui/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gate-custom_attribute2.stderr index 90be45a33ea..1c1f50366d6 100644 --- a/src/test/ui/feature-gate-custom_attribute2.stderr +++ b/src/test/ui/feature-gate-custom_attribute2.stderr @@ -1,5 +1,5 @@ error[E0658]: The attribute `lt_struct` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:23:13 + --> $DIR/feature-gate-custom_attribute2.rs:16:13 | LL | struct StLt<#[lt_struct] 'a>(&'a u32); | ^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct StLt<#[lt_struct] 'a>(&'a u32); = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_struct` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:25:13 + --> $DIR/feature-gate-custom_attribute2.rs:18:13 | LL | struct StTy<#[ty_struct] I>(I); | ^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | struct StTy<#[ty_struct] I>(I); = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_enum` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:28:11 + --> $DIR/feature-gate-custom_attribute2.rs:21:11 | LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } | ^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_enum` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:30:11 + --> $DIR/feature-gate-custom_attribute2.rs:23:11 | LL | enum EnTy<#[ty_enum] J> { A(J), B } | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | enum EnTy<#[ty_enum] J> { A(J), B } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_trait` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:33:12 + --> $DIR/feature-gate-custom_attribute2.rs:26:12 | LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } | ^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_trait` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:35:12 + --> $DIR/feature-gate-custom_attribute2.rs:28:12 | LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } | ^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_type` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:38:11 + --> $DIR/feature-gate-custom_attribute2.rs:31:11 | LL | type TyLt<#[lt_type] 'd> = &'d u32; | ^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | type TyLt<#[lt_type] 'd> = &'d u32; = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_type` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:40:11 + --> $DIR/feature-gate-custom_attribute2.rs:33:11 | LL | type TyTy<#[ty_type] L> = (L, ); | ^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | type TyTy<#[ty_type] L> = (L, ); = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_inherent` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:43:6 + --> $DIR/feature-gate-custom_attribute2.rs:36:6 | LL | impl<#[lt_inherent] 'e> StLt<'e> { } | ^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | impl<#[lt_inherent] 'e> StLt<'e> { } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_inherent` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:45:6 + --> $DIR/feature-gate-custom_attribute2.rs:38:6 | LL | impl<#[ty_inherent] M> StTy { } | ^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | impl<#[ty_inherent] M> StTy { } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_impl_for` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:48:6 + --> $DIR/feature-gate-custom_attribute2.rs:41:6 | LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { | ^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_impl_for` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:52:6 + --> $DIR/feature-gate-custom_attribute2.rs:45:6 | LL | impl<#[ty_impl_for] N> TrTy for StTy { | ^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | impl<#[ty_impl_for] N> TrTy for StTy { = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_fn` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:57:9 + --> $DIR/feature-gate-custom_attribute2.rs:50:9 | LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } | ^^^^^^^^ @@ -103,7 +103,7 @@ LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_fn` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:59:9 + --> $DIR/feature-gate-custom_attribute2.rs:52:9 | LL | fn f_ty<#[ty_fn] O>(_: O) { } | ^^^^^^^^ @@ -111,7 +111,7 @@ LL | fn f_ty<#[ty_fn] O>(_: O) { } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_meth` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:63:13 + --> $DIR/feature-gate-custom_attribute2.rs:56:13 | LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } | ^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `ty_meth` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:65:13 + --> $DIR/feature-gate-custom_attribute2.rs:58:13 | LL | fn m_ty<#[ty_meth] P>(_: P) { } | ^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | fn m_ty<#[ty_meth] P>(_: P) { } = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0658]: The attribute `lt_hof` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) - --> $DIR/feature-gate-custom_attribute2.rs:70:19 + --> $DIR/feature-gate-custom_attribute2.rs:63:19 | LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 | ^^^^^^^^^ diff --git a/src/test/ui/feature-gate-generic_param_attrs.rs b/src/test/ui/feature-gate-generic_param_attrs.rs deleted file mode 100644 index 944802f450a..00000000000 --- a/src/test/ui/feature-gate-generic_param_attrs.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This test ensures that attributes on formals in generic parameter -// lists are rejected if feature(generic_param_attrs) is not enabled. -// -// (We are prefixing all tested features with `rustc_`, to ensure that -// the attributes themselves won't be rejected by the compiler when -// using `rustc_attrs` feature. There is a separate compile-fail/ test -// ensuring that the attribute feature-gating works in this context.) - -#![feature(rustc_attrs)] -#![allow(dead_code)] - -struct StLt<#[rustc_lt_struct] 'a>(&'a u32); -//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) -struct StTy<#[rustc_ty_struct] I>(I); -//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) - -enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B } -//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) -enum EnTy<#[rustc_ty_enum] J> { A(J), B } -//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) - -trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } -//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) -trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); } -//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) - -type TyLt<#[rustc_lt_type] 'd> = &'d u32; -//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) -type TyTy<#[rustc_ty_type] L> = (L, ); -//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) - -impl<#[rustc_lt_inherent] 'e> StLt<'e> { } -//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) -impl<#[rustc_ty_inherent] M> StTy { } -//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) - -impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> { - //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) - fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } } -} -impl<#[rustc_ty_impl_for] N> TrTy for StTy { - //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) - fn foo(&self, _: N) { } -} - -fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } -//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) -fn f_ty<#[rustc_ty_fn] O>(_: O) { } -//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) - -impl StTy { - fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } - //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) - fn m_ty<#[rustc_ty_meth] P>(_: P) { } - //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) -} - -fn hof_lt(_: Q) - where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 - //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) -{ -} - -fn main() { - -} diff --git a/src/test/ui/feature-gate-generic_param_attrs.stderr b/src/test/ui/feature-gate-generic_param_attrs.stderr deleted file mode 100644 index 7b449242c32..00000000000 --- a/src/test/ui/feature-gate-generic_param_attrs.stderr +++ /dev/null @@ -1,139 +0,0 @@ -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:22:13 - | -LL | struct StLt<#[rustc_lt_struct] 'a>(&'a u32); - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:24:13 - | -LL | struct StTy<#[rustc_ty_struct] I>(I); - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:27:11 - | -LL | enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B } - | ^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:29:11 - | -LL | enum EnTy<#[rustc_ty_enum] J> { A(J), B } - | ^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:32:12 - | -LL | trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } - | ^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:34:12 - | -LL | trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); } - | ^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:37:11 - | -LL | type TyLt<#[rustc_lt_type] 'd> = &'d u32; - | ^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:39:11 - | -LL | type TyTy<#[rustc_ty_type] L> = (L, ); - | ^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:42:6 - | -LL | impl<#[rustc_lt_inherent] 'e> StLt<'e> { } - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:44:6 - | -LL | impl<#[rustc_ty_inherent] M> StTy { } - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:47:6 - | -LL | impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> { - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:51:6 - | -LL | impl<#[rustc_ty_impl_for] N> TrTy for StTy { - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:56:9 - | -LL | fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } - | ^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:58:9 - | -LL | fn f_ty<#[rustc_ty_fn] O>(_: O) { } - | ^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:62:13 - | -LL | fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } - | ^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on type parameter bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:64:13 - | -LL | fn m_ty<#[rustc_ty_meth] P>(_: P) { } - | ^^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error[E0658]: attributes on lifetime bindings are experimental (see issue #34761) - --> $DIR/feature-gate-generic_param_attrs.rs:69:19 - | -LL | where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 - | ^^^^^^^^^^^^^^^ - | - = help: add #![feature(generic_param_attrs)] to the crate attributes to enable - -error: aborting due to 17 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-may-dangle.rs b/src/test/ui/feature-gate-may-dangle.rs index ace9fe9ab27..a67ece04488 100644 --- a/src/test/ui/feature-gate-may-dangle.rs +++ b/src/test/ui/feature-gate-may-dangle.rs @@ -12,8 +12,6 @@ // Check that `may_dangle` is rejected if `dropck_eyepatch` feature gate is absent. -#![feature(generic_param_attrs)] - struct Pt(A); impl<#[may_dangle] A> Drop for Pt { //~^ ERROR may_dangle has unstable semantics and may be removed in the future diff --git a/src/test/ui/feature-gate-may-dangle.stderr b/src/test/ui/feature-gate-may-dangle.stderr index 85707f6e921..aad725dfe65 100644 --- a/src/test/ui/feature-gate-may-dangle.stderr +++ b/src/test/ui/feature-gate-may-dangle.stderr @@ -1,5 +1,5 @@ error[E0658]: may_dangle has unstable semantics and may be removed in the future (see issue #34761) - --> $DIR/feature-gate-may-dangle.rs:18:6 + --> $DIR/feature-gate-may-dangle.rs:16:6 | LL | impl<#[may_dangle] A> Drop for Pt { | ^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-param-attrs.rs b/src/test/ui/generic-param-attrs.rs new file mode 100644 index 00000000000..37fabcd7e1e --- /dev/null +++ b/src/test/ui/generic-param-attrs.rs @@ -0,0 +1,54 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test previously ensured that attributes on formals in generic parameter +// lists are rejected without a feature gate. +// +// (We are prefixing all tested features with `rustc_`, to ensure that +// the attributes themselves won't be rejected by the compiler when +// using `rustc_attrs` feature. There is a separate compile-fail/ test +// ensuring that the attribute feature-gating works in this context.) + +// must-compile-successfully + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct StLt<#[rustc_lt_struct] 'a>(&'a u32); +struct StTy<#[rustc_ty_struct] I>(I); +enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B } +enum EnTy<#[rustc_ty_enum] J> { A(J), B } +trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } +trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); } +type TyLt<#[rustc_lt_type] 'd> = &'d u32; +type TyTy<#[rustc_ty_type] L> = (L, ); + +impl<#[rustc_lt_inherent] 'e> StLt<'e> { } +impl<#[rustc_ty_inherent] M> StTy { } +impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } } +} +impl<#[rustc_ty_impl_for] N> TrTy for StTy { + fn foo(&self, _: N) { } +} + +fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } +fn f_ty<#[rustc_ty_fn] O>(_: O) { } + +impl StTy { + fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + fn m_ty<#[rustc_ty_meth] P>(_: P) { } +} + +fn hof_lt(_: Q) + where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 +{} + +fn main() {} diff --git a/src/test/ui/nll/drop-may-dangle.rs b/src/test/ui/nll/drop-may-dangle.rs index 2780b347463..55c9f5de302 100644 --- a/src/test/ui/nll/drop-may-dangle.rs +++ b/src/test/ui/nll/drop-may-dangle.rs @@ -17,7 +17,6 @@ #![allow(warnings)] #![feature(dropck_eyepatch)] -#![feature(generic_param_attrs)] fn use_x(_: usize) -> bool { true } diff --git a/src/test/ui/nll/drop-no-may-dangle.rs b/src/test/ui/nll/drop-no-may-dangle.rs index 3d9a5456cbb..e5478e39fec 100644 --- a/src/test/ui/nll/drop-no-may-dangle.rs +++ b/src/test/ui/nll/drop-no-may-dangle.rs @@ -17,7 +17,6 @@ #![allow(warnings)] #![feature(dropck_eyepatch)] -#![feature(generic_param_attrs)] fn use_x(_: usize) -> bool { true } diff --git a/src/test/ui/nll/drop-no-may-dangle.stderr b/src/test/ui/nll/drop-no-may-dangle.stderr index 6454413901b..a35271bdcfe 100644 --- a/src/test/ui/nll/drop-no-may-dangle.stderr +++ b/src/test/ui/nll/drop-no-may-dangle.stderr @@ -1,5 +1,5 @@ error[E0506]: cannot assign to `v[..]` because it is borrowed - --> $DIR/drop-no-may-dangle.rs:31:9 + --> $DIR/drop-no-may-dangle.rs:30:9 | LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] }; | ----- borrow of `v[..]` occurs here @@ -11,7 +11,7 @@ LL | } | - borrow later used here, when `p` is dropped error[E0506]: cannot assign to `v[..]` because it is borrowed - --> $DIR/drop-no-may-dangle.rs:34:5 + --> $DIR/drop-no-may-dangle.rs:33:5 | LL | let p: WrapMayNotDangle<&usize> = WrapMayNotDangle { value: &v[0] }; | ----- borrow of `v[..]` occurs here -- cgit 1.4.1-3-g733a5 From 210a2a2b9e5f7bc105897654bfea0f9cc7c8d89f Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Thu, 5 Apr 2018 00:30:49 -0600 Subject: Stabilize take_set_limit Fixes #42781 --- src/libstd/io/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 3b8c42ddb39..b02e133ee4d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1829,7 +1829,6 @@ impl Take { /// # Examples /// /// ```no_run - /// #![feature(take_set_limit)] /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; @@ -1845,7 +1844,7 @@ impl Take { /// Ok(()) /// } /// ``` - #[unstable(feature = "take_set_limit", issue = "42781")] + #[stable(feature = "take_set_limit", since = "1.27.0")] pub fn set_limit(&mut self, limit: u64) { self.limit = limit; } -- cgit 1.4.1-3-g733a5 From 64ddb390efb2143f11c1583d52c78da5a290e097 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Thu, 5 Apr 2018 13:04:00 +0200 Subject: typos --- src/libstd/lib.rs | 2 +- src/libstd/panic.rs | 2 +- src/libstd/sys/windows/pipe.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 36eb7291822..67ef47569d6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -380,7 +380,7 @@ extern crate compiler_builtins; // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they -// wolud generate duplicate lang item errors), and any globals it defines are +// would generate duplicate lang item errors), and any globals it defines are // _not_ the globals used by "real" std. So this import, defined only during // testing gives test-std access to real-std lang items and globals. See #2912 #[cfg(test)] extern crate std as realstd; diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 79857104b9b..28c178307a5 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -188,7 +188,7 @@ pub struct AssertUnwindSafe( // * By default everything is unwind safe // * pointers T contains mutability of some form are not unwind safe // * Unique, an owning pointer, lifts an implementation -// * Types like Mutex/RwLock which are explicilty poisoned are unwind safe +// * Types like Mutex/RwLock which are explicitly poisoned are unwind safe // * Our custom AssertUnwindSafe wrapper is indeed unwind safe #[stable(feature = "catch_unwind", since = "1.9.0")] diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index f3b1185c6ea..df1dd7401af 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -236,7 +236,7 @@ enum State { impl<'a> AsyncPipe<'a> { fn new(pipe: Handle, dst: &'a mut Vec) -> io::Result> { // Create an event which we'll use to coordinate our overlapped - // opreations, this event will be used in WaitForMultipleObjects + // operations, this event will be used in WaitForMultipleObjects // and passed as part of the OVERLAPPED handle. // // Note that we do a somewhat clever thing here by flagging the -- cgit 1.4.1-3-g733a5 From 8958815916201421b0a6648c68d7eb31bd3197ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 4 Apr 2018 07:16:25 -0700 Subject: Bump the bootstrap compiler to 1.26.0 beta Holy cow that's a lot of `cfg(stage0)` removed and a lot of new stable language features! --- src/bootstrap/lib.rs | 5 ++- src/bootstrap/tool.rs | 1 - src/liballoc/benches/lib.rs | 1 - src/liballoc/lib.rs | 3 +- src/liballoc/tests/lib.rs | 1 - src/libcore/cmp.rs | 5 ++- src/libcore/intrinsics.rs | 7 ---- src/libcore/lib.rs | 5 --- src/libcore/macros.rs | 65 ------------------------------------- src/libcore/panicking.rs | 3 +- src/libcore/tests/lib.rs | 3 -- src/libpanic_unwind/gcc.rs | 3 +- src/libpanic_unwind/lib.rs | 3 +- src/libpanic_unwind/seh64_gnu.rs | 3 +- src/libpanic_unwind/windows.rs | 9 ++--- src/libproc_macro/lib.rs | 1 - src/librustc/lib.rs | 7 ---- src/librustc_apfloat/lib.rs | 4 --- src/librustc_apfloat/tests/ieee.rs | 2 -- src/librustc_borrowck/lib.rs | 1 - src/librustc_const_math/lib.rs | 2 -- src/librustc_data_structures/lib.rs | 4 --- src/librustc_errors/lib.rs | 2 -- src/librustc_incremental/lib.rs | 3 -- src/librustc_lint/lib.rs | 2 -- src/librustc_metadata/lib.rs | 2 -- src/librustc_mir/lib.rs | 6 ---- src/librustc_traits/lib.rs | 2 -- src/librustc_trans/lib.rs | 4 --- src/librustc_trans_utils/lib.rs | 2 -- src/librustc_typeck/lib.rs | 6 ---- src/librustdoc/lib.rs | 1 - src/libserialize/lib.rs | 1 - src/libstd/lib.rs | 4 --- src/libstd/panicking.rs | 6 ++-- src/libsyntax/lib.rs | 2 -- src/libsyntax_pos/lib.rs | 1 - src/libunwind/libunwind.rs | 9 ++--- src/stage0.txt | 2 +- 39 files changed, 18 insertions(+), 175 deletions(-) (limited to 'src/libstd') diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2eeb2691eae..6c46f3e58cf 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -114,8 +114,7 @@ //! also check out the `src/bootstrap/README.md` file for more information. #![deny(warnings)] -#![feature(conservative_impl_trait, fs_read_write, core_intrinsics)] -#![feature(slice_concat_ext)] +#![feature(core_intrinsics)] #[macro_use] extern crate build_helper; @@ -1149,7 +1148,7 @@ impl Build { fn read(&self, path: &Path) -> String { if self.config.dry_run { return String::new(); } - t!(fs::read_string(path)) + t!(fs::read_to_string(path)) } fn create_dir(&self, dir: &Path) { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 93b6153fcb2..5fc92611e65 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -12,7 +12,6 @@ use std::fs; use std::env; use std::path::PathBuf; use std::process::{Command, exit}; -use std::slice::SliceConcatExt; use Mode; use Compiler; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index a43aadfe9a2..4d92fc67b2a 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(rand)] #![feature(repr_simd)] #![feature(slice_sort_by_cached_key)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 6ce2547ef6e..da26e7c852c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,8 +97,6 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] -#![cfg_attr(stage0, feature(generic_param_attrs))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(lang_items)] #![feature(needs_allocator)] #![feature(nonzero)] @@ -123,6 +121,7 @@ #![feature(exact_chunks)] #![feature(pointer_methods)] #![feature(inclusive_range_fields)] +#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))] #![cfg_attr(test, feature(test))] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 1a49fb9964a..a173ef10a81 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -14,7 +14,6 @@ #![feature(alloc_system)] #![feature(attr_literals)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(const_fn)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 67445daa436..3ae9b05b865 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -427,7 +427,7 @@ impl Ord for Reverse { /// } /// } /// ``` -#[cfg_attr(not(stage0), lang = "ord")] +#[lang = "ord"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -597,8 +597,7 @@ impl PartialOrd for Ordering { /// assert_eq!(x < y, true); /// assert_eq!(x.lt(&y), true); /// ``` -#[cfg_attr(stage0, lang = "ord")] -#[cfg_attr(not(stage0), lang = "partial_ord")] +#[lang = "partial_ord"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3b740adc468..83274682250 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1293,7 +1293,6 @@ extern "rust-intrinsic" { pub fn bswap(x: T) -> T; /// Reverses the bits in an integer type `T`. - #[cfg(not(stage0))] pub fn bitreverse(x: T) -> T; /// Performs checked integer addition. @@ -1316,7 +1315,6 @@ extern "rust-intrinsic" { /// Performs an exact division, resulting in undefined behavior where /// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - #[cfg(not(stage0))] pub fn exact_div(x: T, y: T) -> T; /// Performs an unchecked division, resulting in undefined behavior @@ -1401,8 +1399,3 @@ extern "rust-intrinsic" { /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); } - -#[cfg(stage0)] -pub unsafe fn exact_div(a: T, b: T) -> T { - unchecked_div(a, b) -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5a62b8438f9..cf9abb26d3e 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -78,8 +78,6 @@ #![feature(doc_spotlight)] #![feature(fn_must_use)] #![feature(fundamental)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(intrinsics)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] @@ -103,9 +101,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] -#![cfg_attr(stage0, allow(unused_attributes))] -#![cfg_attr(stage0, feature(never_type))] - #[prelude_import] #[allow(unused)] use prelude::v1::*; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 8a87bea71e2..90a9cb3379b 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -28,71 +28,6 @@ macro_rules! panic { }); } -/// Ensure that a boolean expression is `true` at runtime. -/// -/// This will invoke the [`panic!`] macro if the provided expression cannot be -/// evaluated to `true` at runtime. -/// -/// # Uses -/// -/// Assertions are always checked in both debug and release builds, and cannot -/// be disabled. See [`debug_assert!`] for assertions that are not enabled in -/// release builds by default. -/// -/// Unsafe code relies on `assert!` to enforce run-time invariants that, if -/// violated could lead to unsafety. -/// -/// Other use-cases of `assert!` include [testing] and enforcing run-time -/// invariants in safe code (whose violation cannot result in unsafety). -/// -/// # Custom Messages -/// -/// This macro has a second form, where a custom panic message can -/// be provided with or without arguments for formatting. See [`std::fmt`] -/// for syntax for this form. -/// -/// [`panic!`]: macro.panic.html -/// [`debug_assert!`]: macro.debug_assert.html -/// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro -/// [`std::fmt`]: ../std/fmt/index.html -/// -/// # Examples -/// -/// ``` -/// // the panic message for these assertions is the stringified value of the -/// // expression given. -/// assert!(true); -/// -/// fn some_computation() -> bool { true } // a very simple function -/// -/// assert!(some_computation()); -/// -/// // assert with a custom message -/// let x = true; -/// assert!(x, "x wasn't true!"); -/// -/// let a = 3; let b = 27; -/// assert!(a + b == 30, "a = {}, b = {}", a, b); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[cfg(stage0)] -macro_rules! assert { - ($cond:expr) => ( - if !$cond { - panic!(concat!("assertion failed: ", stringify!($cond))) - } - ); - ($cond:expr,) => ( - assert!($cond) - ); - ($cond:expr, $($arg:tt)+) => ( - if !$cond { - panic!($($arg)+) - } - ); -} - /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print the values of the expressions with their diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 94db0baa3f9..6b3dc75af46 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -64,8 +64,7 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; } let (file, line, col) = *file_line_col; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index de7211e718c..971759dcdd0 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,10 +23,7 @@ #![feature(fmt_internals)] #![feature(hashmap_internals)] #![feature(iterator_step_by)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(iterator_flatten)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(iterator_repeat_with)] #![feature(nonzero)] #![feature(pattern)] diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index ca2fd561cad..eb6dc5b5488 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -286,8 +286,7 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) // See docs in the `unwind` module. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] #[lang = "eh_unwind_resume"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception); } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5cebc3e4d0..a5c227cb401 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -112,8 +112,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 090cd095380..c3715f96c64 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -108,8 +108,7 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO } #[lang = "eh_unwind_resume"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { let params = [panic_ctx as c::ULONG_PTR]; c::RaiseException(RUST_PANIC, diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs index 50fba5faee7..5f1dda36a88 100644 --- a/src/libpanic_unwind/windows.rs +++ b/src/libpanic_unwind/windows.rs @@ -79,21 +79,18 @@ pub enum EXCEPTION_DISPOSITION { pub use self::EXCEPTION_DISPOSITION::*; extern "system" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn RaiseException(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, lpArguments: *const ULONG_PTR); - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn RtlUnwindEx(TargetFrame: LPVOID, TargetIp: LPVOID, ExceptionRecord: *const EXCEPTION_RECORD, ReturnValue: LPVOID, OriginalContext: *const CONTEXT, HistoryTable: *const UNWIND_HISTORY_TABLE); - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8); } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 007093981d3..6b2b68b1faa 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -34,7 +34,6 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index dcad8132c2b..7da664e6d02 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -43,19 +43,14 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] -#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(dyn_trait)] #![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type, i128))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![cfg_attr(windows, feature(libc))] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] @@ -68,8 +63,6 @@ #![feature(slice_patterns)] #![feature(specialization)] #![feature(unboxed_closures)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] -#![cfg_attr(stage0, feature(universal_impl_trait))] #![feature(trace_macros)] #![feature(trusted_len)] #![feature(catch_expr)] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 6f08fcf7025..276f6cd09bf 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -46,10 +46,6 @@ #![deny(warnings)] #![forbid(unsafe_code)] -#![cfg_attr(stage0, feature(slice_patterns))] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(try_from))] - // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index 627d79724b2..6e06ea858ef 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(stage0, feature(i128_type))] - #[macro_use] extern crate rustc_apfloat; diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index d54654c6086..6fe2ac2b0ca 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -16,7 +16,6 @@ #![allow(non_camel_case_types)] #![feature(from_ref)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(quote)] #[macro_use] extern crate log; diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 7177e2818fb..c4c5886d465 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -19,8 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(i128_type, i128))] - extern crate rustc_apfloat; extern crate syntax; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 622fb423b51..1e1628936d5 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -26,14 +26,10 @@ #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(specialization)] #![feature(optin_builtin_traits)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] -#![cfg_attr(stage0, feature(universal_impl_trait))] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 37ae64cef57..c283df6ec0f 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -17,8 +17,6 @@ #![allow(unused_attributes)] #![feature(range_contains)] #![cfg_attr(unix, feature(libc))] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] extern crate atty; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index cad72ff778b..9e72ede309d 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -15,10 +15,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(specialization)] extern crate graphviz; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index d024adad9d0..c915181213d 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -27,11 +27,9 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(macro_vis_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate syntax; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 4af5ec9ae08..e89b5a7fc1b 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -14,9 +14,7 @@ #![deny(warnings)] #![feature(box_patterns)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(libc)] #![feature(macro_lifetime_matcher)] #![feature(proc_macro_internals)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 84baa8c5417..8762e7550cd 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -21,22 +21,16 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(box_patterns)] #![feature(box_syntax)] #![feature(catch_expr)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] #![feature(dyn_trait)] #![feature(fs_read_write)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(macro_vis_matcher)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(nonzero)] -#![cfg_attr(stage0, feature(underscore_lifetimes))] -#![cfg_attr(stage0, feature(never_type))] #![feature(inclusive_range_fields)] extern crate arena; diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 90f368edeec..cfa3b6912f2 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -14,8 +14,6 @@ #![deny(warnings)] #![feature(crate_visibility_modifier)] -#![cfg_attr(stage0, feature(match_default_bindings))] -#![cfg_attr(stage0, feature(underscore_lifetimes))] #[macro_use] extern crate log; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index e8a1eb3071a..2ce13a2627f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -24,13 +24,9 @@ #![feature(custom_attribute)] #![feature(fs_read_write)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type, i128))] -#![cfg_attr(stage0, feature(inclusive_range_syntax))] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(slice_patterns))] -#![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 99de124c6e1..cf47d9b62a9 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -21,10 +21,8 @@ #![feature(box_syntax)] #![feature(custom_attribute)] #![allow(unused_attributes)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] extern crate ar; extern crate flate2; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 44ecb32a0bf..6f71db998bd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -72,22 +72,16 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] -#![cfg_attr(stage0, feature(advanced_slice_patterns))] #![feature(box_patterns)] #![feature(box_syntax)] -#![cfg_attr(stage0, feature(conservative_impl_trait))] -#![cfg_attr(stage0, feature(copy_closures, clone_closures))] #![feature(crate_visibility_modifier)] #![feature(from_ref)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(exhaustive_patterns)] #![feature(option_filter)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![cfg_attr(stage0, feature(i128_type))] -#![cfg_attr(stage0, feature(never_type))] #![feature(dyn_trait)] #[macro_use] extern crate log; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e31390f59e2..42e87f88fd4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![feature(box_syntax)] #![feature(fs_read_write)] #![feature(set_stdio)] -#![cfg_attr(stage0, feature(slice_patterns))] #![feature(test)] #![feature(unicode)] #![feature(vec_remove_item)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index ee952523462..f78eed30694 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -23,7 +23,6 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(specialization)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3f1fec4c317..7da2eeefaaa 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -269,7 +269,6 @@ #![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(hashmap_internals)] #![feature(heap_api)] -#![cfg_attr(stage0, feature(i128_type, i128))] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] @@ -321,8 +320,6 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] -#![cfg_attr(stage0, feature(never_type))] -#![cfg_attr(stage0, feature(termination_trait))] #![default_lib_allocator] @@ -355,7 +352,6 @@ use prelude::v1::*; // add a new crate name so we can attach the re-exports to it. #[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, unreachable, unimplemented, write, writeln, try)] -#[cfg_attr(stage0, macro_reexport(assert))] extern crate core as __core; #[macro_use] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 454ac64735c..fba3269204e 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -55,8 +55,7 @@ extern { data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] fn __rust_start_panic(data: usize, vtable: usize) -> u32; } @@ -316,8 +315,7 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] #[lang = "panic_fmt"] -#[cfg_attr(stage0, unwind)] -#[cfg_attr(not(stage0), unwind(allowed))] +#[unwind(allowed)] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index dc349c1a3e6..c456dc45d21 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -22,9 +22,7 @@ #![feature(unicode)] #![feature(rustc_diagnostic_macros)] -#![cfg_attr(stage0, feature(match_default_bindings))] #![feature(non_exhaustive)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index eb345200f41..b6315900485 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -21,7 +21,6 @@ #![feature(const_fn)] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(i128_type))] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index aa73b11fb38..a640a2b7775 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -83,8 +83,7 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; @@ -221,8 +220,7 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, trace_argument: *mut c_void) @@ -231,8 +229,7 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { } else { // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() extern "C" { - #[cfg_attr(stage0, unwind)] - #[cfg_attr(not(stage0), unwind(allowed))] + #[unwind(allowed)] pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } diff --git a/src/stage0.txt b/src/stage0.txt index 96ec1e6834d..e8db3358cf0 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-03-18 +date: 2018-04-04 rustc: beta cargo: beta -- cgit 1.4.1-3-g733a5 From 521e41e77d0c9213ff3ed3f2a5e863b600ce2c3a Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 5 Apr 2018 00:35:09 +0100 Subject: Correct a few stability attributes --- src/libcore/ascii.rs | 4 ++-- src/libcore/iter/range.rs | 2 +- src/libcore/panic.rs | 2 ++ src/libstd/env.rs | 8 ++++---- src/libsyntax/feature_gate.rs | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index 2c4bccebceb..e6b0569281f 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -31,7 +31,7 @@ use iter::FusedIterator; /// documentation for more. /// /// [`escape_default`]: fn.escape_default.html -#[stable(feature = "core_ascii", since = "1.26.0")] +#[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { range: Range, data: [u8; 4], @@ -99,7 +99,7 @@ pub struct EscapeDefault { /// assert_eq!(b'9', escaped.next().unwrap()); /// assert_eq!(b'd', escaped.next().unwrap()); /// ``` -#[stable(feature = "core_ascii", since = "1.26.0")] +#[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { let (data, len) = match c { b'\t' => ([b'\\', b't', 0, 0], 2), diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 72b48b56571..bcc0e1f05be 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -200,7 +200,7 @@ macro_rules! range_trusted_len_impl { macro_rules! range_incl_trusted_len_impl { ($($t:ty)*) => ($( - #[stable(feature = "inclusive_range", since = "1.26.0")] + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for ops::RangeInclusive<$t> { } )*) } diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 4e72eaa57c7..1720c9d8c60 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -120,6 +120,7 @@ impl<'a> PanicInfo<'a> { } } +#[stable(feature = "panic_hook_display", since = "1.26.0")] impl<'a> fmt::Display for PanicInfo<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("panicked at ")?; @@ -244,6 +245,7 @@ impl<'a> Location<'a> { } } +#[stable(feature = "panic_hook_display", since = "1.26.0")] impl<'a> fmt::Display for Location<'a> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "{}:{}:{}", self.file, self.line, self.col) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 320a9f935d4..a103c0bdd59 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -723,10 +723,10 @@ pub fn args_os() -> ArgsOs { ArgsOs { inner: sys::args::args() } } -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Send for Args {} -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Sync for Args {} #[stable(feature = "env", since = "1.0.0")] @@ -760,10 +760,10 @@ impl fmt::Debug for Args { } } -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Send for ArgsOs {} -#[stable(feature = "env_unimpl_send_sync", since = "1.25.0")] +#[stable(feature = "env_unimpl_send_sync", since = "1.26.0")] impl !Sync for ArgsOs {} #[stable(feature = "env", since = "1.0.0")] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e734a4e3735..d1348c89faf 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -483,7 +483,7 @@ declare_features! ( // allow empty structs and enum variants with braces (accepted, braced_empty_structs, "1.8.0", Some(29720), None), // Allows indexing into constant arrays. - (accepted, const_indexing, "1.24.0", Some(29947), None), + (accepted, const_indexing, "1.26.0", Some(29947), None), (accepted, default_type_params, "1.0.0", None, None), (accepted, globs, "1.0.0", None, None), (accepted, if_let, "1.0.0", None, None), -- cgit 1.4.1-3-g733a5 From 323f8087910b0d63815003970bb8a45e3ccfdb17 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 5 Apr 2018 11:07:19 -0700 Subject: std: Inline some Termination-related methods These were showing up in tests and in binaries but are trivially optimize-able away, so add `#[inline]` attributes so LLVM has an opportunity to optimize them out. --- src/libstd/process.rs | 2 ++ src/libstd/sys/unix/process/process_common.rs | 1 + src/libstd/sys/windows/process.rs | 1 + 3 files changed, 4 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 40bc84f4bc1..92f0406c09b 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1452,6 +1452,7 @@ pub trait Termination { #[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for () { + #[inline] fn report(self) -> i32 { ExitCode::SUCCESS.report() } } @@ -1481,6 +1482,7 @@ impl Termination for Result { #[unstable(feature = "termination_trait_lib", issue = "43301")] impl Termination for ExitCode { + #[inline] fn report(self) -> i32 { self.0.as_i32() } diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index b7f30600b8a..6396bb3a49e 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -404,6 +404,7 @@ impl ExitCode { pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + #[inline] pub fn as_i32(&self) -> i32 { self.0 as i32 } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index afa8e3e1369..bd5507e8f89 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -414,6 +414,7 @@ impl ExitCode { pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); + #[inline] pub fn as_i32(&self) -> i32 { self.0 as i32 } -- cgit 1.4.1-3-g733a5 From 679657b863c2a53a3052d8af9defbce48e12db10 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 30 Mar 2018 13:06:34 +0200 Subject: Inject the `compiler_builtins` crate whenever the `core` crate is injected --- src/Cargo.lock | 14 +++++++++++++ src/liballoc/Cargo.toml | 1 + src/liballoc_jemalloc/Cargo.toml | 1 + src/liballoc_system/Cargo.toml | 1 + src/libpanic_abort/Cargo.toml | 1 + src/libpanic_unwind/Cargo.toml | 1 + src/libprofiler_builtins/Cargo.toml | 1 + src/librustc_asan/Cargo.toml | 1 + src/librustc_lsan/Cargo.toml | 1 + src/librustc_msan/Cargo.toml | 1 + src/librustc_tsan/Cargo.toml | 1 + src/libstd/lib.rs | 1 + src/libstd_unicode/Cargo.toml | 1 + src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/std_inject.rs | 41 +++++++++++++++++++++++-------------- src/libunwind/Cargo.toml | 1 + src/rustc/dlmalloc_shim/Cargo.toml | 1 + src/rustc/libc_shim/Cargo.toml | 2 ++ 18 files changed, 57 insertions(+), 16 deletions(-) (limited to 'src/libstd') diff --git a/src/Cargo.lock b/src/Cargo.lock index f70fc81829f..004d1c0ffc9 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ name = "alloc" version = "0.0.0" dependencies = [ + "compiler_builtins 0.0.0", "core 0.0.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "std_unicode 0.0.0", @@ -23,6 +24,7 @@ dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", ] @@ -32,6 +34,7 @@ name = "alloc_system" version = "0.0.0" dependencies = [ "alloc 0.0.0", + "compiler_builtins 0.0.0", "core 0.0.0", "dlmalloc 0.0.0", "libc 0.0.0", @@ -541,6 +544,7 @@ name = "dlmalloc" version = "0.0.0" dependencies = [ "alloc 0.0.0", + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -976,6 +980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "libc" version = "0.0.0" dependencies = [ + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1254,6 +1259,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ + "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", ] @@ -1263,6 +1269,7 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc 0.0.0", + "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", "unwind 0.0.0", @@ -1401,6 +1408,7 @@ name = "profiler_builtins" version = "0.0.0" dependencies = [ "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1797,6 +1805,7 @@ dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1942,6 +1951,7 @@ dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1991,6 +2001,7 @@ dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2130,6 +2141,7 @@ dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2343,6 +2355,7 @@ dependencies = [ name = "std_unicode" version = "0.0.0" dependencies = [ + "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2725,6 +2738,7 @@ dependencies = [ name = "unwind" version = "0.0.0" dependencies = [ + "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", ] diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 3bf919b0c00..2eb8ea12604 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -10,6 +10,7 @@ path = "lib.rs" [dependencies] core = { path = "../libcore" } std_unicode = { path = "../libstd_unicode" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } [dev-dependencies] rand = "0.4" diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 6d7d83dd993..fd4a4553046 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -16,6 +16,7 @@ alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/liballoc_system/Cargo.toml b/src/liballoc_system/Cargo.toml index f9a57f7d97a..936e20a32e1 100644 --- a/src/liballoc_system/Cargo.toml +++ b/src/liballoc_system/Cargo.toml @@ -13,6 +13,7 @@ doc = false alloc = { path = "../liballoc" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } # See comments in the source for what this dependency is [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] diff --git a/src/libpanic_abort/Cargo.toml b/src/libpanic_abort/Cargo.toml index e0eac41f49e..633d273b3b9 100644 --- a/src/libpanic_abort/Cargo.toml +++ b/src/libpanic_abort/Cargo.toml @@ -12,3 +12,4 @@ doc = false [dependencies] core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/libpanic_unwind/Cargo.toml b/src/libpanic_unwind/Cargo.toml index a978ea16e9e..74aaa4d5ae3 100644 --- a/src/libpanic_unwind/Cargo.toml +++ b/src/libpanic_unwind/Cargo.toml @@ -14,3 +14,4 @@ alloc = { path = "../liballoc" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } unwind = { path = "../libunwind" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/libprofiler_builtins/Cargo.toml b/src/libprofiler_builtins/Cargo.toml index 04f456917b9..79192fbb681 100644 --- a/src/libprofiler_builtins/Cargo.toml +++ b/src/libprofiler_builtins/Cargo.toml @@ -13,6 +13,7 @@ doc = false [dependencies] core = { path = "../libcore" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } [build-dependencies] cc = "1.0.1" diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml index 8f8ef1cc4a0..34d8b75a5bf 100644 --- a/src/librustc_asan/Cargo.toml +++ b/src/librustc_asan/Cargo.toml @@ -17,3 +17,4 @@ cmake = "0.1.18" alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml index 087c3162119..9c19b537426 100644 --- a/src/librustc_lsan/Cargo.toml +++ b/src/librustc_lsan/Cargo.toml @@ -17,3 +17,4 @@ cmake = "0.1.18" alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml index 8d7279b29eb..17ec2b96438 100644 --- a/src/librustc_msan/Cargo.toml +++ b/src/librustc_msan/Cargo.toml @@ -17,3 +17,4 @@ cmake = "0.1.18" alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/librustc_tsan/Cargo.toml b/src/librustc_tsan/Cargo.toml index 7b83985ba67..8bb67c0bbac 100644 --- a/src/librustc_tsan/Cargo.toml +++ b/src/librustc_tsan/Cargo.toml @@ -17,3 +17,4 @@ cmake = "0.1.18" alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 6f6abfdd31e..f9041ac8546 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -373,6 +373,7 @@ extern crate unwind; // compiler-rt intrinsics #[doc(masked)] +#[cfg(stage0)] extern crate compiler_builtins; // During testing, this crate is not actually the "real" std library, but rather diff --git a/src/libstd_unicode/Cargo.toml b/src/libstd_unicode/Cargo.toml index b3346dbe2fb..283070a0e2c 100644 --- a/src/libstd_unicode/Cargo.toml +++ b/src/libstd_unicode/Cargo.toml @@ -15,3 +15,4 @@ path = "tests/lib.rs" [dependencies] core = { path = "../libcore" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8d42206c5cc..8168db19058 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -94,7 +94,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, is_expanded: bool) -> io::Result<()> { let mut s = State::new_from_input(cm, sess, filename, input, out, ann, is_expanded); - if is_expanded && !std_inject::injected_crate_name().is_none() { + if is_expanded && std_inject::injected_crate_name().is_some() { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. // However we don't want these attributes in the AST because diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 63d7b3336a8..bba7a2d7377 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -44,27 +44,38 @@ thread_local! { } pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<&str>) -> ast::Crate { - let name = if attr::contains_name(&krate.attrs, "no_core") { + // the first name in this list is the crate name of the crate with the prelude + let names: &[&str] = if attr::contains_name(&krate.attrs, "no_core") { return krate; } else if attr::contains_name(&krate.attrs, "no_std") { - "core" + if attr::contains_name(&krate.attrs, "compiler_builtins") { + &["core"] + } else { + &["core", "compiler_builtins"] + } } else { - "std" + &["std"] }; - INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name))); + for name in names { + krate.module.items.insert(0, P(ast::Item { + attrs: vec![attr::mk_attr_outer(DUMMY_SP, + attr::mk_attr_id(), + attr::mk_word_item(ast::Ident::from_str("macro_use")))], + vis: dummy_spanned(ast::VisibilityKind::Inherited), + node: ast::ItemKind::ExternCrate(alt_std_name.map(Symbol::intern)), + ident: ast::Ident::from_str(name), + id: ast::DUMMY_NODE_ID, + span: DUMMY_SP, + tokens: None, + })); + } - krate.module.items.insert(0, P(ast::Item { - attrs: vec![attr::mk_attr_outer(DUMMY_SP, - attr::mk_attr_id(), - attr::mk_word_item(ast::Ident::from_str("macro_use")))], - vis: dummy_spanned(ast::VisibilityKind::Inherited), - node: ast::ItemKind::ExternCrate(alt_std_name.map(Symbol::intern)), - ident: ast::Ident::from_str(name), - id: ast::DUMMY_NODE_ID, - span: DUMMY_SP, - tokens: None, - })); + // the crates have been injected, the assumption is that the first one is the one with + // the prelude. + let name = names[0]; + + INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name))); let span = ignored_span(DUMMY_SP); krate.module.items.insert(0, P(ast::Item { diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml index fbd9789d2f5..4760461df64 100644 --- a/src/libunwind/Cargo.toml +++ b/src/libunwind/Cargo.toml @@ -14,3 +14,4 @@ doc = false [dependencies] core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/rustc/dlmalloc_shim/Cargo.toml b/src/rustc/dlmalloc_shim/Cargo.toml index cf8440c40da..d2fe159d806 100644 --- a/src/rustc/dlmalloc_shim/Cargo.toml +++ b/src/rustc/dlmalloc_shim/Cargo.toml @@ -11,4 +11,5 @@ doc = false [dependencies] core = { path = "../../libcore" } +compiler_builtins = { path = "../../rustc/compiler_builtins_shim" } alloc = { path = "../../liballoc" } diff --git a/src/rustc/libc_shim/Cargo.toml b/src/rustc/libc_shim/Cargo.toml index 0c04402124a..e77897d6433 100644 --- a/src/rustc/libc_shim/Cargo.toml +++ b/src/rustc/libc_shim/Cargo.toml @@ -29,6 +29,8 @@ doc = false # # See https://github.com/rust-lang/rfcs/pull/1133. core = { path = "../../libcore" } +compiler_builtins = { path = "../compiler_builtins_shim" } + [features] # Certain parts of libc are conditionally compiled differently than when used -- cgit 1.4.1-3-g733a5 From fd2afa01aa614114811ff68ed31c146f7aab1d28 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Sun, 8 Apr 2018 16:20:15 +0100 Subject: fixup! std: Child::kill() returns error if process has already exited --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index c3d681a8962..60759de8afc 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1146,7 +1146,7 @@ impl Child { /// /// [`ErrorKind`]: ../io/enum.ErrorKind.html /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput - /// [`Other]: ../io/enum.ErrorKind.html#variant.Other + /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other #[stable(feature = "process", since = "1.0.0")] pub fn kill(&mut self) -> io::Result<()> { self.handle.kill() -- cgit 1.4.1-3-g733a5 From c115cc655c8bb3077ff349e4ddd704a2239438a6 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 1 Apr 2018 09:35:53 -0600 Subject: Move deny(warnings) into rustbuild This permits easier iteration without having to worry about warnings being denied. Fixes #49517 --- config.toml.example | 3 +++ src/bootstrap/bin/rustc.rs | 4 ++++ src/bootstrap/builder.rs | 5 +++++ src/bootstrap/config.rs | 8 ++++++++ src/bootstrap/flags.rs | 6 ++++++ src/build_helper/lib.rs | 1 - src/liballoc/benches/lib.rs | 2 -- src/liballoc/lib.rs | 1 - src/liballoc/tests/lib.rs | 2 -- src/liballoc_jemalloc/lib.rs | 1 - src/liballoc_system/lib.rs | 1 - src/libarena/lib.rs | 1 - src/libcore/benches/lib.rs | 2 -- src/libcore/lib.rs | 1 - src/libcore/tests/lib.rs | 2 -- src/libfmt_macros/lib.rs | 1 - src/libgraphviz/lib.rs | 1 - src/libpanic_abort/lib.rs | 1 - src/libpanic_unwind/lib.rs | 1 - src/libproc_macro/lib.rs | 1 - src/librustc/benches/lib.rs | 2 -- src/librustc/lib.rs | 1 - src/librustc_allocator/lib.rs | 2 -- src/librustc_apfloat/lib.rs | 1 - src/librustc_back/lib.rs | 1 - src/librustc_borrowck/lib.rs | 1 - src/librustc_const_math/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_driver/lib.rs | 1 - src/librustc_errors/lib.rs | 1 - src/librustc_incremental/lib.rs | 1 - src/librustc_lint/lib.rs | 1 - src/librustc_llvm/lib.rs | 1 - src/librustc_metadata/lib.rs | 1 - src/librustc_mir/lib.rs | 2 -- src/librustc_passes/lib.rs | 1 - src/librustc_platform_intrinsics/lib.rs | 1 - src/librustc_plugin/lib.rs | 1 - src/librustc_privacy/lib.rs | 1 - src/librustc_resolve/lib.rs | 1 - src/librustc_save_analysis/lib.rs | 1 - src/librustc_traits/lib.rs | 2 -- src/librustc_trans/lib.rs | 1 - src/librustc_trans_utils/lib.rs | 1 - src/librustc_typeck/lib.rs | 1 - src/librustdoc/lib.rs | 1 - src/libserialize/lib.rs | 1 - src/libstd/lib.rs | 4 ---- src/libstd_unicode/lib.rs | 1 - src/libsyntax/lib.rs | 1 - src/libsyntax_ext/lib.rs | 1 - src/libsyntax_pos/lib.rs | 1 - src/libterm/lib.rs | 1 - src/libtest/lib.rs | 1 - src/libunwind/lib.rs | 1 - src/tools/tidy/src/lib.rs | 2 -- 56 files changed, 26 insertions(+), 63 deletions(-) (limited to 'src/libstd') diff --git a/config.toml.example b/config.toml.example index 9dd3002506e..68bc7dfe720 100644 --- a/config.toml.example +++ b/config.toml.example @@ -339,6 +339,9 @@ # rustc to execute. #lld = false +# Whether to deny warnings in crates +#deny-warnings = true + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 6701f58ba8e..3dd9b684059 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -279,6 +279,10 @@ fn main() { cmd.arg("--color=always"); } + if env::var_os("RUSTC_DENY_WARNINGS").is_some() { + cmd.arg("-Dwarnings"); + } + if verbose > 1 { eprintln!("rustc command: {:?}", cmd); eprintln!("sysroot: {:?}", sysroot); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 3f5ec4933d0..7ff64af9196 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -698,6 +698,11 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); + // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. + if self.config.deny_warnings && !(mode == Mode::Libstd && stage == 0) { + cargo.env("RUSTC_DENY_WARNINGS", "1"); + } + // Throughout the build Cargo can execute a number of build scripts // compiling C/C++ code and we need to pass compilers, archivers, flags, etc // obtained previously to those build scripts. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 95baf4f8cca..239316d45c4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -71,6 +71,8 @@ pub struct Config { pub incremental: bool, pub dry_run: bool, + pub deny_warnings: bool, + // llvm codegen options pub llvm_enabled: bool, pub llvm_assertions: bool, @@ -301,6 +303,7 @@ struct Rust { codegen_backends_dir: Option, wasm_syscall: Option, lld: Option, + deny_warnings: Option, } /// TOML representation of how each build target is configured. @@ -340,6 +343,7 @@ impl Config { config.test_miri = false; config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.rust_codegen_backends_dir = "codegen-backends".to_owned(); + config.deny_warnings = true; // set by bootstrap.py config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); @@ -366,6 +370,9 @@ impl Config { config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + if let Some(value) = flags.warnings { + config.deny_warnings = value; + } if config.dry_run { let dir = config.out.join("tmp-dry-run"); @@ -511,6 +518,7 @@ impl Config { config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings)); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = backends.iter() diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ef902c68d12..3eb9dca2aa8 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -42,6 +42,9 @@ pub struct Flags { pub exclude: Vec, pub rustc_error_format: Option, pub dry_run: bool, + + // true => deny + pub warnings: Option, } pub enum Subcommand { @@ -118,6 +121,8 @@ To learn more about a subcommand, run `./x.py -h`"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); + opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default", + "VALUE"); opts.optopt("", "error-format", "rustc error format", "FORMAT"); // fn usage() @@ -374,6 +379,7 @@ Arguments: incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) .into_iter().map(|p| p.into()).collect::>(), + warnings: matches.opt_str("warnings").map(|v| v == "deny"), } } } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 5a12afd03e1..e5c85ddb3a9 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] use std::fs::File; use std::path::{Path, PathBuf}; diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 4d92fc67b2a..4f69aa6670b 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rand)] #![feature(repr_simd)] #![feature(slice_sort_by_cached_key)] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index da26e7c852c..b08bd66b47c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,7 +72,6 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] #![needs_allocator] -#![deny(warnings)] #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index a173ef10a81..17f1d0464a5 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(allocator_api)] #![feature(alloc_system)] #![feature(attr_literals)] diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 7a8d01e4ef8..df7e3f61f5f 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,7 +14,6 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![deny(warnings)] #![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index d4404e564e0..cdcb732f635 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![allow(unused_attributes)] -#![deny(warnings)] #![unstable(feature = "alloc_system", reason = "this library is unlikely to be stabilized in its current \ form or name", diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 7eaf67e6ea6..b319f333342 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -22,7 +22,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(no_crate_inject, attr(deny(warnings))))] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index c947b003ccb..ced77d77918 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(flt2dec)] #![feature(test)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index cf9abb26d3e..e194b173aa7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -63,7 +63,6 @@ #![no_core] #![deny(missing_docs)] #![deny(missing_debug_implementations)] -#![deny(warnings)] #![feature(allow_internal_unstable)] #![feature(asm)] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 971759dcdd0..c3162899bbd 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(ascii_ctype)] #![feature(box_syntax)] #![feature(core_float)] diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 0f45f965104..a551b1b770a 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -19,7 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] -#![deny(warnings)] pub use self::Piece::*; pub use self::Position::*; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index d8c366d2413..158d0101515 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -287,7 +287,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(str_escape)] diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 5f768ef4399..43c5bbbc618 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -19,7 +19,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![panic_runtime] #![allow(unused_features)] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5c227cb401..9321d6917d1 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -28,7 +28,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 6aa5572721d..dafdacfdd72 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -24,7 +24,6 @@ //! See [the book](../book/first-edition/procedural-macros.html) for more. #![stable(feature = "proc_macro_lib", since = "1.15.0")] -#![deny(warnings)] #![deny(missing_docs)] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", diff --git a/src/librustc/benches/lib.rs b/src/librustc/benches/lib.rs index 278e0f9a26e..5496df1342f 100644 --- a/src/librustc/benches/lib.rs +++ b/src/librustc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(test)] extern crate test; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 7da664e6d02..b54699901fa 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -39,7 +39,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index e17fce5a2ec..0c7a9a91711 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rustc_private)] extern crate rustc; diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 276f6cd09bf..0f051ea5981 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -43,7 +43,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![forbid(unsafe_code)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 9baee267709..027a9c45555 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -24,7 +24,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(const_fn)] diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 6fe2ac2b0ca..52a357e1a1d 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index c4c5886d465..499c330be1d 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1e1628936d5..ba1d73dc268 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -19,7 +19,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(collections_range)] #![feature(nonzero)] diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6f88b0aecb6..f6903d26e70 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index a723e455222..8d5f9ac93f0 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![allow(unused_attributes)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 9e72ede309d..a5e07bcec24 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(fs_read_write)] #![feature(specialization)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c915181213d..16e8600f2d8 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -22,7 +22,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![cfg_attr(test, feature(test))] #![feature(box_patterns)] diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 16bee5b987e..bf8a087ab55 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -16,7 +16,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(concat_idents)] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index e89b5a7fc1b..f02a34c65a9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(fs_read_write)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 8762e7550cd..51256c4d96f 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,8 +14,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![deny(warnings)] - #![feature(slice_patterns)] #![feature(from_ref)] #![feature(box_patterns)] diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 1f6cc1f71fc..e65c9de8df1 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 4cc65ee28e8..b57debdd994 100644 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] #![allow(bad_style)] pub struct Intrinsic { diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index c0f830f1fbe..622d8e51a6c 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -63,7 +63,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] #![feature(staged_api)] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d951a7f1cc1..ef710ff7a7e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2bf17cd1317..61ff326b2af 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4f46fb3545b..fefedd4e1c8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![feature(macro_lifetime_matcher)] #![allow(unused_attributes)] diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index cfa3b6912f2..8136f6857a5 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -11,8 +11,6 @@ //! New recursive solver modeled on Chalk's recursive solver. Most of //! the guts are broken up into modules; see the comments in those modules. -#![deny(warnings)] - #![feature(crate_visibility_modifier)] #[macro_use] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 344f959c141..b9fa5b1353c 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index cf47d9b62a9..b297fd99865 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -15,7 +15,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 6f71db998bd..eb9a26855c6 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -68,7 +68,6 @@ This API is completely unstable and subject to change. #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 42e87f88fd4..730f61e0aa6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -12,7 +12,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] -#![deny(warnings)] #![feature(ascii_ctype)] #![feature(rustc_private)] diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index f78eed30694..22d27b6697a 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -19,7 +19,6 @@ Core encoding and decoding interfaces. html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(box_syntax)] #![feature(core_intrinsics)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3227aa9acff..672723341eb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -227,10 +227,6 @@ // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] -// Turn warnings into errors, but only after stage0, where it can be useful for -// code to emit warnings during language transitions -#![cfg_attr(not(stage0), deny(warnings))] - // std may use features in a platform-specific way #![allow(unused_features)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index c22ea1671fa..cf8c101a2f9 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -27,7 +27,6 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![deny(missing_debug_implementations)] #![no_std] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index c456dc45d21..b2976f71d49 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -18,7 +18,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] #![feature(unicode)] #![feature(rustc_diagnostic_macros)] diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 249a64b353f..97e34c554d1 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(proc_macro_internals)] #![feature(decl_macro)] diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 33428eb271a..9a7d1fd8ee6 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(const_fn)] #![feature(custom_attribute)] diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index ad0e582b1c3..a012f4e776f 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -46,7 +46,6 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] #![deny(missing_docs)] -#![deny(warnings)] #![cfg_attr(windows, feature(libc))] // Handle rustfmt skips diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index b8be1aeff17..9291eaa910b 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -31,7 +31,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] #![feature(asm)] #![feature(fnbox)] #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 5347c781218..2b3c19c067e 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] -#![deny(warnings)] #![feature(cfg_target_vendor)] #![feature(link_cfg)] diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 06eb055f68e..fa227436640 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -13,8 +13,6 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. -#![deny(warnings)] - extern crate serde; extern crate serde_json; #[macro_use] -- cgit 1.4.1-3-g733a5 From 7ab31f6556c2cce433695b113f53d6275edd724d Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 10 Apr 2018 23:55:41 +0100 Subject: Prevent EPIPE causing ICEs in rustc and rustdoc --- src/librustc_driver/lib.rs | 12 ++++++++++++ src/librustdoc/lib.rs | 1 + src/libstd/sys/unix/mod.rs | 4 ++-- src/rustc/rustc.rs | 5 ++++- 4 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6f88b0aecb6..4f23c62ab06 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -548,6 +548,18 @@ fn run_compiler_impl<'a>(args: &[String], (result, Some(sess)) } +#[cfg(unix)] +pub fn set_sigpipe_handler() { + unsafe { + // Set the SIGPIPE signal handler, so that an EPIPE + // will cause rustc to terminate, as expected. + assert!(libc::signal(libc::SIGPIPE, libc::SIG_DFL) != libc::SIG_ERR); + } +} + +#[cfg(windows)] +pub fn set_sigpipe_handler() {} + // Extract output directory and file from matches. fn make_output(matches: &getopts::Matches) -> (Option, Option) { let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 42e87f88fd4..1e51f45f149 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -101,6 +101,7 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32_000_000; // 32MB + rustc_driver::set_sigpipe_handler(); env_logger::init(); let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { syntax::with_globals(move || { diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 9bdea945ea4..c1298e5040d 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -80,11 +80,11 @@ pub fn init() { reset_sigpipe(); } - #[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))] + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } - #[cfg(any(target_os = "emscripten", target_os="fuchsia"))] + #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] unsafe fn reset_sigpipe() {} } diff --git a/src/rustc/rustc.rs b/src/rustc/rustc.rs index 9fa33f911a1..c07fb41d13b 100644 --- a/src/rustc/rustc.rs +++ b/src/rustc/rustc.rs @@ -22,4 +22,7 @@ extern {} extern crate rustc_driver; -fn main() { rustc_driver::main() } +fn main() { + rustc_driver::set_sigpipe_handler(); + rustc_driver::main() +} -- cgit 1.4.1-3-g733a5 From f87d4a15a82a76e7510629173c366d084f2c02ca Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 15:55:28 +0200 Subject: Move Utf8Lossy decoder to libcore --- src/liballoc/string.rs | 2 +- src/libcore/str/lossy.rs | 212 +++++++++++++++++++++++++++++++++++ src/libcore/str/mod.rs | 4 + src/libcore/tests/lib.rs | 2 + src/libcore/tests/str_lossy.rs | 91 +++++++++++++++ src/libstd/sys/redox/os_str.rs | 2 +- src/libstd/sys/unix/os_str.rs | 2 +- src/libstd/sys/wasm/os_str.rs | 2 +- src/libstd/sys_common/bytestring.rs | 2 +- src/libstd_unicode/Cargo.toml | 4 - src/libstd_unicode/lib.rs | 1 - src/libstd_unicode/lossy.rs | 213 ------------------------------------ src/libstd_unicode/tests/lib.rs | 15 --- src/libstd_unicode/tests/lossy.rs | 91 --------------- 14 files changed, 314 insertions(+), 329 deletions(-) create mode 100644 src/libcore/str/lossy.rs create mode 100644 src/libcore/tests/str_lossy.rs delete mode 100644 src/libstd_unicode/lossy.rs delete mode 100644 src/libstd_unicode/tests/lib.rs delete mode 100644 src/libstd_unicode/tests/lossy.rs (limited to 'src/libstd') diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index b95aae02894..5f90e28cb3c 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -63,7 +63,7 @@ use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; -use std_unicode::lossy; +use core::str::lossy; use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs new file mode 100644 index 00000000000..30b7267da7c --- /dev/null +++ b/src/libcore/str/lossy.rs @@ -0,0 +1,212 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use char; +use str as core_str; +use fmt; +use fmt::Write; +use mem; + +/// Lossy UTF-8 string. +#[unstable(feature = "str_internals", issue = "0")] +pub struct Utf8Lossy { + bytes: [u8] +} + +impl Utf8Lossy { + pub fn from_str(s: &str) -> &Utf8Lossy { + Utf8Lossy::from_bytes(s.as_bytes()) + } + + pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { + unsafe { mem::transmute(bytes) } + } + + pub fn chunks(&self) -> Utf8LossyChunksIter { + Utf8LossyChunksIter { source: &self.bytes } + } +} + + +/// Iterator over lossy UTF-8 string +#[unstable(feature = "str_internals", issue = "0")] +#[allow(missing_debug_implementations)] +pub struct Utf8LossyChunksIter<'a> { + source: &'a [u8], +} + +#[unstable(feature = "str_internals", issue = "0")] +#[derive(PartialEq, Eq, Debug)] +pub struct Utf8LossyChunk<'a> { + /// Sequence of valid chars. + /// Can be empty between broken UTF-8 chars. + pub valid: &'a str, + /// Single broken char, empty if none. + /// Empty iff iterator item is last. + pub broken: &'a [u8], +} + +impl<'a> Iterator for Utf8LossyChunksIter<'a> { + type Item = Utf8LossyChunk<'a>; + + fn next(&mut self) -> Option> { + if self.source.len() == 0 { + return None; + } + + const TAG_CONT_U8: u8 = 128; + fn unsafe_get(xs: &[u8], i: usize) -> u8 { + unsafe { *xs.get_unchecked(i) } + } + fn safe_get(xs: &[u8], i: usize) -> u8 { + if i >= xs.len() { 0 } else { unsafe_get(xs, i) } + } + + let mut i = 0; + while i < self.source.len() { + let i_ = i; + + let byte = unsafe_get(self.source, i); + i += 1; + + if byte < 128 { + + } else { + let w = core_str::utf8_char_width(byte); + + macro_rules! error { () => ({ + unsafe { + let r = Utf8LossyChunk { + valid: core_str::from_utf8_unchecked(&self.source[0..i_]), + broken: &self.source[i_..i], + }; + self.source = &self.source[i..]; + return Some(r); + } + })} + + match w { + 2 => { + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 3 => { + match (byte, safe_get(self.source, i)) { + (0xE0, 0xA0 ... 0xBF) => (), + (0xE1 ... 0xEC, 0x80 ... 0xBF) => (), + (0xED, 0x80 ... 0x9F) => (), + (0xEE ... 0xEF, 0x80 ... 0xBF) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 4 => { + match (byte, safe_get(self.source, i)) { + (0xF0, 0x90 ... 0xBF) => (), + (0xF1 ... 0xF3, 0x80 ... 0xBF) => (), + (0xF4, 0x80 ... 0x8F) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + _ => { + error!(); + } + } + } + } + + let r = Utf8LossyChunk { + valid: unsafe { core_str::from_utf8_unchecked(self.source) }, + broken: &[], + }; + self.source = &[]; + return Some(r); + } +} + + +impl fmt::Display for Utf8Lossy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // If we're the empty string then our iterator won't actually yield + // anything, so perform the formatting manually + if self.bytes.len() == 0 { + return "".fmt(f) + } + + for Utf8LossyChunk { valid, broken } in self.chunks() { + // If we successfully decoded the whole chunk as a valid string then + // we can return a direct formatting of the string which will also + // respect various formatting flags if possible. + if valid.len() == self.bytes.len() { + assert!(broken.is_empty()); + return valid.fmt(f) + } + + f.write_str(valid)?; + if !broken.is_empty() { + f.write_char(char::REPLACEMENT_CHARACTER)?; + } + } + Ok(()) + } +} + +impl fmt::Debug for Utf8Lossy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_char('"')?; + + for Utf8LossyChunk { valid, broken } in self.chunks() { + + // Valid part. + // Here we partially parse UTF-8 again which is suboptimal. + { + let mut from = 0; + for (i, c) in valid.char_indices() { + let esc = c.escape_debug(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.len() != 1 { + f.write_str(&valid[from..i])?; + for c in esc { + f.write_char(c)?; + } + from = i + c.len_utf8(); + } + } + f.write_str(&valid[from..])?; + } + + // Broken parts of string as hex escape. + for &b in broken { + write!(f, "\\x{:02x}", b)?; + } + } + + f.write_char('"') + } +} diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 1185b7acaae..7a97d89dcf9 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -26,6 +26,10 @@ use mem; pub mod pattern; +#[unstable(feature = "str_internals", issue = "0")] +#[allow(missing_docs)] +pub mod lossy; + /// A trait to abstract the idea of creating a new instance of a type from a /// string. /// diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index c3162899bbd..149269263dc 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -33,6 +33,7 @@ #![feature(sort_internals)] #![feature(specialization)] #![feature(step_trait)] +#![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] #![feature(try_trait)] @@ -68,4 +69,5 @@ mod ptr; mod result; mod slice; mod str; +mod str_lossy; mod tuple; diff --git a/src/libcore/tests/str_lossy.rs b/src/libcore/tests/str_lossy.rs new file mode 100644 index 00000000000..69e28256da9 --- /dev/null +++ b/src/libcore/tests/str_lossy.rs @@ -0,0 +1,91 @@ +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::str::lossy::*; + +#[test] +fn chunks() { + let mut iter = Utf8Lossy::from_bytes(b"hello").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + // surrogates + let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); +} + +#[test] +fn display() { + assert_eq!( + "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", + &format!("{}", Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye"))); +} + +#[test] +fn debug() { + assert_eq!( + "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"", + &format!("{:?}", Utf8Lossy::from_bytes( + b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa"))); +} diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index da27787babb..eb3a1ead58c 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index e43bc6da5f1..01c0fb830aa 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs index 84f560af69b..e0da5bdf36c 100644 --- a/src/libstd/sys/wasm/os_str.rs +++ b/src/libstd/sys/wasm/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys_common/bytestring.rs b/src/libstd/sys_common/bytestring.rs index eb9cad09915..971b83938c1 100644 --- a/src/libstd/sys_common/bytestring.rs +++ b/src/libstd/sys_common/bytestring.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] use fmt::{Formatter, Result, Write}; -use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk}; +use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { // Writes out a valid unicode string with the correct escape sequences diff --git a/src/libstd_unicode/Cargo.toml b/src/libstd_unicode/Cargo.toml index 283070a0e2c..b1c55c2e4b6 100644 --- a/src/libstd_unicode/Cargo.toml +++ b/src/libstd_unicode/Cargo.toml @@ -9,10 +9,6 @@ path = "lib.rs" test = false bench = false -[[test]] -name = "std_unicode_tests" -path = "tests/lib.rs" - [dependencies] core = { path = "../libcore" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index cf8c101a2f9..106a2c0f0c5 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -45,7 +45,6 @@ mod tables; mod u_str; mod version; pub mod char; -pub mod lossy; #[allow(deprecated)] pub mod str { diff --git a/src/libstd_unicode/lossy.rs b/src/libstd_unicode/lossy.rs deleted file mode 100644 index cc8e93308a5..00000000000 --- a/src/libstd_unicode/lossy.rs +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::str as core_str; -use core::fmt; -use core::fmt::Write; -use char; -use core::mem; - - -/// Lossy UTF-8 string. -#[unstable(feature = "str_internals", issue = "0")] -pub struct Utf8Lossy { - bytes: [u8] -} - -impl Utf8Lossy { - pub fn from_str(s: &str) -> &Utf8Lossy { - Utf8Lossy::from_bytes(s.as_bytes()) - } - - pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { - unsafe { mem::transmute(bytes) } - } - - pub fn chunks(&self) -> Utf8LossyChunksIter { - Utf8LossyChunksIter { source: &self.bytes } - } -} - - -/// Iterator over lossy UTF-8 string -#[unstable(feature = "str_internals", issue = "0")] -#[allow(missing_debug_implementations)] -pub struct Utf8LossyChunksIter<'a> { - source: &'a [u8], -} - -#[unstable(feature = "str_internals", issue = "0")] -#[derive(PartialEq, Eq, Debug)] -pub struct Utf8LossyChunk<'a> { - /// Sequence of valid chars. - /// Can be empty between broken UTF-8 chars. - pub valid: &'a str, - /// Single broken char, empty if none. - /// Empty iff iterator item is last. - pub broken: &'a [u8], -} - -impl<'a> Iterator for Utf8LossyChunksIter<'a> { - type Item = Utf8LossyChunk<'a>; - - fn next(&mut self) -> Option> { - if self.source.len() == 0 { - return None; - } - - const TAG_CONT_U8: u8 = 128; - fn unsafe_get(xs: &[u8], i: usize) -> u8 { - unsafe { *xs.get_unchecked(i) } - } - fn safe_get(xs: &[u8], i: usize) -> u8 { - if i >= xs.len() { 0 } else { unsafe_get(xs, i) } - } - - let mut i = 0; - while i < self.source.len() { - let i_ = i; - - let byte = unsafe_get(self.source, i); - i += 1; - - if byte < 128 { - - } else { - let w = core_str::utf8_char_width(byte); - - macro_rules! error { () => ({ - unsafe { - let r = Utf8LossyChunk { - valid: core_str::from_utf8_unchecked(&self.source[0..i_]), - broken: &self.source[i_..i], - }; - self.source = &self.source[i..]; - return Some(r); - } - })} - - match w { - 2 => { - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - } - 3 => { - match (byte, safe_get(self.source, i)) { - (0xE0, 0xA0 ... 0xBF) => (), - (0xE1 ... 0xEC, 0x80 ... 0xBF) => (), - (0xED, 0x80 ... 0x9F) => (), - (0xEE ... 0xEF, 0x80 ... 0xBF) => (), - _ => { - error!(); - } - } - i += 1; - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - } - 4 => { - match (byte, safe_get(self.source, i)) { - (0xF0, 0x90 ... 0xBF) => (), - (0xF1 ... 0xF3, 0x80 ... 0xBF) => (), - (0xF4, 0x80 ... 0x8F) => (), - _ => { - error!(); - } - } - i += 1; - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - if safe_get(self.source, i) & 192 != TAG_CONT_U8 { - error!(); - } - i += 1; - } - _ => { - error!(); - } - } - } - } - - let r = Utf8LossyChunk { - valid: unsafe { core_str::from_utf8_unchecked(self.source) }, - broken: &[], - }; - self.source = &[]; - return Some(r); - } -} - - -impl fmt::Display for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // If we're the empty string then our iterator won't actually yield - // anything, so perform the formatting manually - if self.bytes.len() == 0 { - return "".fmt(f) - } - - for Utf8LossyChunk { valid, broken } in self.chunks() { - // If we successfully decoded the whole chunk as a valid string then - // we can return a direct formatting of the string which will also - // respect various formatting flags if possible. - if valid.len() == self.bytes.len() { - assert!(broken.is_empty()); - return valid.fmt(f) - } - - f.write_str(valid)?; - if !broken.is_empty() { - f.write_char(char::REPLACEMENT_CHARACTER)?; - } - } - Ok(()) - } -} - -impl fmt::Debug for Utf8Lossy { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_char('"')?; - - for Utf8LossyChunk { valid, broken } in self.chunks() { - - // Valid part. - // Here we partially parse UTF-8 again which is suboptimal. - { - let mut from = 0; - for (i, c) in valid.char_indices() { - let esc = c.escape_debug(); - // If char needs escaping, flush backlog so far and write, else skip - if esc.len() != 1 { - f.write_str(&valid[from..i])?; - for c in esc { - f.write_char(c)?; - } - from = i + c.len_utf8(); - } - } - f.write_str(&valid[from..])?; - } - - // Broken parts of string as hex escape. - for &b in broken { - write!(f, "\\x{:02x}", b)?; - } - } - - f.write_char('"') - } -} diff --git a/src/libstd_unicode/tests/lib.rs b/src/libstd_unicode/tests/lib.rs deleted file mode 100644 index 9535ec18763..00000000000 --- a/src/libstd_unicode/tests/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(str_internals, unicode)] - -extern crate std_unicode; - -mod lossy; diff --git a/src/libstd_unicode/tests/lossy.rs b/src/libstd_unicode/tests/lossy.rs deleted file mode 100644 index e05d0668556..00000000000 --- a/src/libstd_unicode/tests/lossy.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std_unicode::lossy::*; - -#[test] -fn chunks() { - let mut iter = Utf8Lossy::from_bytes(b"hello").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); - - // surrogates - let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks(); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); - assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn display() { - assert_eq!( - "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - &format!("{}", Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye"))); -} - -#[test] -fn debug() { - assert_eq!( - "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"", - &format!("{:?}", Utf8Lossy::from_bytes( - b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa"))); -} -- cgit 1.4.1-3-g733a5 From b2027ef17c03e47a4d716d8ea8148ed785934b04 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 17:20:08 +0200 Subject: Deprecate the std_unicode crate --- src/Cargo.lock | 1 - src/ci/docker/wasm32-unknown/Dockerfile | 1 - src/doc/unstable-book/src/language-features/lang-items.md | 2 +- src/liballoc/Cargo.toml | 1 - src/liballoc/lib.rs | 2 -- src/liballoc/str.rs | 7 +++---- src/liballoc/string.rs | 2 +- src/liballoc/tests/lib.rs | 2 +- src/liballoc/tests/str.rs | 2 +- src/liballoc/tests/string.rs | 2 +- src/libcore/char.rs | 2 +- src/librustdoc/lib.rs | 1 - src/libstd/lib.rs | 3 +-- src/libstd_unicode/lib.rs | 1 + src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- 16 files changed, 13 insertions(+), 20 deletions(-) (limited to 'src/libstd') diff --git a/src/Cargo.lock b/src/Cargo.lock index a60679e417a..6e7c4b67acf 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -13,7 +13,6 @@ dependencies = [ "compiler_builtins 0.0.0", "core 0.0.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "std_unicode 0.0.0", ] [[package]] diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile index 6c0ec1ad9d4..853923ad947 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/wasm32-unknown/Dockerfile @@ -34,4 +34,3 @@ ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ src/test/mir-opt \ src/test/codegen-units \ src/libcore \ - src/libstd_unicode/ \ diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index c5167418614..6a7aea7f1c2 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -243,7 +243,7 @@ the source code. - `usize`: `libcore/num/mod.rs` - `f32`: `libstd/f32.rs` - `f64`: `libstd/f64.rs` - - `char`: `libstd_unicode/char.rs` + - `char`: `libcore/char.rs` - `slice`: `liballoc/slice.rs` - `str`: `liballoc/str.rs` - `const_ptr`: `libcore/ptr.rs` diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 2eb8ea12604..6383bd1e941 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -9,7 +9,6 @@ path = "lib.rs" [dependencies] core = { path = "../libcore" } -std_unicode = { path = "../libstd_unicode" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } [dev-dependencies] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index b08bd66b47c..d1a91ab4a9c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -135,8 +135,6 @@ extern crate test; #[cfg(test)] extern crate rand; -extern crate std_unicode; - // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] mod macros; diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index d5ef41df0d8..eaca9eb49f9 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -45,12 +45,11 @@ use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; -use std_unicode::str::{UnicodeStr, Utf16Encoder}; +use core::unicode::str::{UnicodeStr, Utf16Encoder}; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; use string::String; -use std_unicode; use vec::Vec; use slice::{SliceConcatExt, SliceIndex}; use boxed::Box; @@ -75,7 +74,7 @@ pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; #[stable(feature = "rust1", since = "1.0.0")] -pub use std_unicode::str::SplitWhitespace; +pub use core::unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; @@ -1960,7 +1959,7 @@ impl str { } fn case_ignoreable_then_cased>(iter: I) -> bool { - use std_unicode::derived_property::{Cased, Case_Ignorable}; + use core::unicode::derived_property::{Cased, Case_Ignorable}; match iter.skip_while(|&c| Case_Ignorable(c)).next() { Some(c) => Cased(c), None => false, diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 5f90e28cb3c..a902f0bb06b 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -64,7 +64,7 @@ use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; use core::str::lossy; -use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; +use core::unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 17f1d0464a5..fddf341d0d1 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -29,7 +29,7 @@ #![feature(inclusive_range_fields)] extern crate alloc_system; -extern crate std_unicode; +extern crate core; extern crate rand; use std::hash::{Hash, Hasher}; diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index a14a5d32738..763dbe675b9 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1204,7 +1204,7 @@ fn test_rev_split_char_iterator_no_trailing() { #[test] fn test_utf16_code_units() { - use std_unicode::str::Utf16Encoder; + use core::unicode::str::Utf16Encoder; assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::>(), [0xE9, 0xD83D, 0xDCA9]) } diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index cb4a17a22d8..33f20be100d 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -132,7 +132,7 @@ fn test_from_utf16() { let s_as_utf16 = s.encode_utf16().collect::>(); let u_as_string = String::from_utf16(&u).unwrap(); - assert!(::std_unicode::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); + assert!(::core::unicode::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); assert_eq!(s_as_utf16, u); assert_eq!(u_as_string, s); diff --git a/src/libcore/char.rs b/src/libcore/char.rs index b5554a59db5..6e2626cc362 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -10,7 +10,7 @@ //! Character manipulation. //! -//! For more details, see ::std_unicode::char (a.k.a. std::char) +//! For more details, see ::core::unicode::char (a.k.a. std::char) #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 730f61e0aa6..9ac034869ac 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -41,7 +41,6 @@ extern crate serialize; #[macro_use] extern crate syntax; extern crate syntax_pos; extern crate test as testing; -extern crate std_unicode; #[macro_use] extern crate log; extern crate rustc_errors as errors; extern crate pulldown_cmark; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 672723341eb..16bca9ddcd3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -354,7 +354,6 @@ extern crate core as __core; #[macro_reexport(vec, format)] extern crate alloc; extern crate alloc_system; -extern crate std_unicode; #[doc(masked)] extern crate libc; @@ -455,7 +454,7 @@ pub use alloc::string; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] -pub use std_unicode::char; +pub use core::unicode::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index 8cdeb6c8ad1..29de017c64d 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -31,5 +31,6 @@ #![feature(unicode)] #![feature(staged_api)] +#![rustc_deprecated(since = "1.27.0", reason = "moved into libcore")] pub use core::unicode::*; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d80430f609b..9de905c01d6 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -32,9 +32,9 @@ extern crate rustc_cratesio_shim; #[macro_use] extern crate bitflags; +extern crate core; extern crate serialize; #[macro_use] extern crate log; -extern crate std_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 39b2f77f230..cb3323c7eca 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -15,7 +15,7 @@ use errors::{FatalError, DiagnosticBuilder}; use parse::{token, ParseSess}; use str::char_at; use symbol::{Symbol, keywords}; -use std_unicode::property::Pattern_White_Space; +use core::unicode::property::Pattern_White_Space; use std::borrow::Cow; use std::char; -- cgit 1.4.1-3-g733a5 From 939692409da499ff3d498eae782620435f16a981 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 Apr 2018 17:56:46 +0200 Subject: Reexport from core::unicode::char in core::char rather than vice versa --- src/liballoc/string.rs | 2 +- src/liballoc/tests/string.rs | 2 +- src/libcore/char/mod.rs | 12 ++++++++++++ src/libcore/unicode/char.rs | 21 +-------------------- src/libcore/unicode/mod.rs | 6 +++--- src/libstd/lib.rs | 2 +- 6 files changed, 19 insertions(+), 26 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a902f0bb06b..29d759b1f00 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -56,6 +56,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; @@ -64,7 +65,6 @@ use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; use core::str::lossy; -use core::unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 33f20be100d..17d53e4cf3e 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -132,7 +132,7 @@ fn test_from_utf16() { let s_as_utf16 = s.encode_utf16().collect::>(); let u_as_string = String::from_utf16(&u).unwrap(); - assert!(::core::unicode::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); + assert!(::core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); assert_eq!(s_as_utf16, u); assert_eq!(u_as_string, s); diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index c6b620e5238..3efa8396331 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -15,6 +15,18 @@ #![allow(non_snake_case)] #![stable(feature = "core_char", since = "1.2.0")] +// stable re-exports +#[stable(feature = "rust1", since = "1.0.0")] +pub use unicode::char::{ToLowercase, ToUppercase}; +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub use unicode::char::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; + +// unstable re-exports +#[unstable(feature = "unicode", issue = "27783")] +pub use unicode::tables::{UNICODE_VERSION}; +#[unstable(feature = "unicode", issue = "27783")] +pub use unicode::version::UnicodeVersion; + mod printable; use self::printable::is_printable; diff --git a/src/libcore/unicode/char.rs b/src/libcore/unicode/char.rs index 0e8b09f621a..e75338aedf1 100644 --- a/src/libcore/unicode/char.rs +++ b/src/libcore/unicode/char.rs @@ -28,31 +28,12 @@ #![stable(feature = "rust1", since = "1.0.0")] +use char::*; use char::CharExt as C; use iter::FusedIterator; use fmt::{self, Write}; use unicode::tables::{conversions, derived_property, general_category, property}; -// stable re-exports -#[stable(feature = "rust1", since = "1.0.0")] -pub use char::{MAX, from_digit, from_u32, from_u32_unchecked}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use char::{EscapeDebug, EscapeDefault, EscapeUnicode}; -#[stable(feature = "decode_utf16", since = "1.9.0")] -pub use char::REPLACEMENT_CHARACTER; -#[stable(feature = "char_from_str", since = "1.20.0")] -pub use char::ParseCharError; - -// unstable re-exports -#[stable(feature = "try_from", since = "1.26.0")] -pub use char::CharTryFromError; -#[unstable(feature = "decode_utf8", issue = "33906")] -pub use char::{DecodeUtf8, decode_utf8}; -#[unstable(feature = "unicode", issue = "27783")] -pub use unicode::tables::{UNICODE_VERSION}; -#[unstable(feature = "unicode", issue = "27783")] -pub use unicode::version::UnicodeVersion; - /// Returns an iterator that yields the lowercase equivalent of a `char`. /// /// This `struct` is created by the [`to_lowercase`] method on [`char`]. See diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index aaf8081799f..0ea1aa12146 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -12,11 +12,11 @@ #![allow(missing_docs)] mod bool_trie; -mod tables; -mod version; +pub(crate) mod tables; +pub(crate) mod version; pub mod str; -pub mod char; +pub(crate) mod char; // For use in liballoc, not re-exported in libstd. pub mod derived_property { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 16bca9ddcd3..94e48732c26 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -454,7 +454,7 @@ pub use alloc::string; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::unicode::char; +pub use core::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; -- cgit 1.4.1-3-g733a5 From ef41788cf37074e44f70257508c97efd539a7f29 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Apr 2018 14:23:00 +0200 Subject: Mark the rest of the `unicode` feature flag as perma-unstable. --- src/liballoc/lib.rs | 2 +- src/liballoc/tests/lib.rs | 1 - src/libcore/unicode/mod.rs | 2 +- src/librustdoc/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd_unicode/lib.rs | 2 +- src/libsyntax/lib.rs | 2 +- 7 files changed, 4 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d1a91ab4a9c..69fc007ab7c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -113,7 +113,7 @@ #![feature(trusted_len)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index fddf341d0d1..32272169307 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -24,7 +24,6 @@ #![feature(string_retain)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] #![feature(exact_chunks)] #![feature(inclusive_range_fields)] diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index 0fbc4dcd175..b6b033adc04 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "unicode", issue = "27783")] +#![unstable(feature = "unicode_internals", issue = "0")] #![allow(missing_docs)] mod bool_trie; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 9ac034869ac..4a062e9a55b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,6 @@ #![feature(fs_read_write)] #![feature(set_stdio)] #![feature(test)] -#![feature(unicode)] #![feature(vec_remove_item)] #![feature(entry_and_modify)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 94e48732c26..c82d600e4a1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -307,7 +307,6 @@ #![feature(toowned_clone_into)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index 29de017c64d..c0d47f1fcb4 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -29,7 +29,7 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(staged_api)] #![rustc_deprecated(since = "1.27.0", reason = "moved into libcore")] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 9de905c01d6..4e1e9fa2b46 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -19,7 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(rustc_diagnostic_macros)] #![feature(non_exhaustive)] #![feature(const_atomic_usize_new)] -- cgit 1.4.1-3-g733a5 From 1569f8f812c97002fa54dd6a5778109766a320e1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 2 Apr 2018 10:38:07 +0200 Subject: Inline docs for the heap module’s reexports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/liballoc/heap.rs | 2 ++ src/libstd/heap.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 9296a113071..000c0123d9f 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -19,7 +19,9 @@ use core::intrinsics::{min_align_of_val, size_of_val}; use core::mem::{self, ManuallyDrop}; use core::usize; +#[doc(inline)] pub use core::heap::*; + #[doc(hidden)] pub mod __core { pub use core::*; diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs index 4a391372c3a..2cf06018087 100644 --- a/src/libstd/heap.rs +++ b/src/libstd/heap.rs @@ -14,7 +14,7 @@ pub use alloc::heap::Heap; pub use alloc_system::System; -pub use core::heap::*; +#[doc(inline)] pub use core::heap::*; #[cfg(not(test))] #[doc(hidden)] -- cgit 1.4.1-3-g733a5 From 1b895d8b88413f72230fbc0f00c67328870a2e9a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 14:36:57 +0200 Subject: Import the `alloc` crate as `alloc_crate` in std MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … to make the name `alloc` available. --- src/libstd/collections/hash/map.rs | 4 +--- src/libstd/collections/hash/table.rs | 5 +---- src/libstd/collections/mod.rs | 10 +++++----- src/libstd/error.rs | 10 +++++----- src/libstd/heap.rs | 2 +- src/libstd/lib.rs | 18 +++++++++--------- src/libstd/sync/mod.rs | 2 +- src/libstd/sync/mpsc/mpsc_queue.rs | 3 +-- src/libstd/sync/mpsc/spsc_queue.rs | 2 +- src/libstd/sys/cloudabi/thread.rs | 2 +- src/libstd/sys/redox/thread.rs | 2 +- src/libstd/sys/unix/thread.rs | 2 +- src/libstd/sys/wasm/thread.rs | 2 +- src/libstd/sys/windows/process.rs | 2 +- src/libstd/sys/windows/thread.rs | 2 +- src/libstd/sys_common/at_exit_imp.rs | 2 +- src/libstd/sys_common/process.rs | 2 +- src/libstd/sys_common/thread.rs | 2 +- 18 files changed, 34 insertions(+), 40 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e0b48e565d0..73a5df8dc28 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,15 +11,13 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::heap::Heap; -use alloc::allocator::CollectionAllocErr; use cell::Cell; -use core::heap::Alloc; use borrow::Borrow; use cmp::max; use fmt::{self, Debug}; #[allow(deprecated)] use hash::{Hash, Hasher, BuildHasher, SipHasher13}; +use heap::{Heap, Alloc, CollectionAllocErr}; use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; use ops::{Deref, Index}; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index fa6053d3f6d..878cd82a258 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,17 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::heap::Heap; -use core::heap::{Alloc, Layout}; - use cmp; use hash::{BuildHasher, Hash, Hasher}; +use heap::{Heap, Alloc, Layout, CollectionAllocErr}; use marker; use mem::{align_of, size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, NonNull}; -use alloc::allocator::CollectionAllocErr; use self::BucketState::*; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index c7ad27d8d26..9cf73824dea 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -424,13 +424,13 @@ #[doc(hidden)] pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; +pub use alloc_crate::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{LinkedList, VecDeque}; +pub use alloc_crate::{LinkedList, VecDeque}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{binary_heap, btree_map, btree_set}; +pub use alloc_crate::{binary_heap, btree_map, btree_set}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{linked_list, vec_deque}; +pub use alloc_crate::{linked_list, vec_deque}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_map::HashMap; @@ -446,7 +446,7 @@ pub mod range { } #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use alloc::allocator::CollectionAllocErr; +pub use heap::CollectionAllocErr; mod hash; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3d0c96585b5..4edb897350e 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -51,13 +51,13 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. -use alloc::allocator; use any::TypeId; use borrow::Cow; use cell; use char; use core::array; use fmt::{self, Debug, Display}; +use heap::{AllocErr, CannotReallocInPlace}; use mem::transmute; use num; use str; @@ -241,18 +241,18 @@ impl Error for ! { #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -impl Error for allocator::AllocErr { +impl Error for AllocErr { fn description(&self) -> &str { - allocator::AllocErr::description(self) + AllocErr::description(self) } } #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -impl Error for allocator::CannotReallocInPlace { +impl Error for CannotReallocInPlace { fn description(&self) -> &str { - allocator::CannotReallocInPlace::description(self) + CannotReallocInPlace::description(self) } } diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs index 2cf06018087..b42a1052c49 100644 --- a/src/libstd/heap.rs +++ b/src/libstd/heap.rs @@ -12,7 +12,7 @@ #![unstable(issue = "32838", feature = "allocator_api")] -pub use alloc::heap::Heap; +pub use alloc_crate::heap::Heap; pub use alloc_system::System; #[doc(inline)] pub use core::heap::*; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c82d600e4a1..ef4205e7a62 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -351,7 +351,7 @@ extern crate core as __core; #[macro_use] #[macro_reexport(vec, format)] -extern crate alloc; +extern crate alloc as alloc_crate; extern crate alloc_system; #[doc(masked)] extern crate libc; @@ -437,21 +437,21 @@ pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::u64; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::boxed; +pub use alloc_crate::boxed; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::rc; +pub use alloc_crate::rc; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::borrow; +pub use alloc_crate::borrow; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::fmt; +pub use alloc_crate::fmt; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::slice; +pub use alloc_crate::slice; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::str; +pub use alloc_crate::str; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::string; +pub use alloc_crate::string; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::vec; +pub use alloc_crate::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use core::char; #[stable(feature = "i128", since = "1.26.0")] diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 289b47b3484..642b284c6c7 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -18,7 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::arc::{Arc, Weak}; +pub use alloc_crate::arc::{Arc, Weak}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 296773d20f6..df945ac3859 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -23,10 +23,9 @@ pub use self::PopResult::*; -use alloc::boxed::Box; use core::ptr; use core::cell::UnsafeCell; - +use boxed::Box; use sync::atomic::{AtomicPtr, Ordering}; /// A result of the `pop` function. diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index cc4be92276a..9482f6958b3 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -16,7 +16,7 @@ // http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue -use alloc::boxed::Box; +use boxed::Box; use core::ptr; use core::cell::UnsafeCell; diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index a22d9053b69..5d66936b2a4 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use cmp; use ffi::CStr; use io; diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index f20350269b7..110d46ca3ab 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use ffi::CStr; use io; use mem; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 2db3d4a5744..9e388808030 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use cmp; use ffi::CStr; use io; diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 7345843b975..728e678a2e8 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use ffi::CStr; use io; use sys::{unsupported, Void}; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index bd5507e8f89..be442f41374 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -31,7 +31,7 @@ use sys::stdio; use sys::cvt; use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::process::{CommandEnv, EnvKey}; -use alloc::borrow::Borrow; +use borrow::Borrow; //////////////////////////////////////////////////////////////////////////////// // Command diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 4b3d1b586b5..b6f63303dc2 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use io; use ffi::CStr; use mem; diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index ce6fd4cb075..26da51c9825 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -12,7 +12,7 @@ //! //! Documentation can be found on the `rt::at_exit` function. -use alloc::boxed::FnBox; +use boxed::FnBox; use ptr; use sys_common::mutex::Mutex; diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index d0c5951bd6c..ddf0ebe603e 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -14,7 +14,7 @@ use ffi::{OsStr, OsString}; use env; use collections::BTreeMap; -use alloc::borrow::Borrow; +use borrow::Borrow; pub trait EnvKey: From + Into + diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs index f1379b6ec63..da6f58ef6bb 100644 --- a/src/libstd/sys_common/thread.rs +++ b/src/libstd/sys_common/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use env; use sync::atomic::{self, Ordering}; use sys::stack_overflow; -- cgit 1.4.1-3-g733a5 From 09e8db1e4f33ec82316e1eeaaedad94fe6e1acb5 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 14:41:15 +0200 Subject: Rename `heap` modules in the core, alloc, and std crates to `alloc` --- src/liballoc/alloc.rs | 291 +++++++++++++ src/liballoc/heap.rs | 291 ------------- src/liballoc/lib.rs | 8 +- src/libcore/alloc.rs | 1125 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libcore/heap.rs | 1125 ------------------------------------------------- src/libcore/lib.rs | 6 +- src/libstd/alloc.rs | 176 ++++++++ src/libstd/heap.rs | 176 -------- src/libstd/lib.rs | 6 +- 9 files changed, 1608 insertions(+), 1596 deletions(-) create mode 100644 src/liballoc/alloc.rs delete mode 100644 src/liballoc/heap.rs create mode 100644 src/libcore/alloc.rs delete mode 100644 src/libcore/heap.rs create mode 100644 src/libstd/alloc.rs delete mode 100644 src/libstd/heap.rs (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs new file mode 100644 index 00000000000..000c0123d9f --- /dev/null +++ b/src/liballoc/alloc.rs @@ -0,0 +1,291 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use core::intrinsics::{min_align_of_val, size_of_val}; +use core::mem::{self, ManuallyDrop}; +use core::usize; + +#[doc(inline)] +pub use core::heap::*; + +#[doc(hidden)] +pub mod __core { + pub use core::*; +} + +extern "Rust" { + #[allocator] + #[rustc_allocator_nounwind] + fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom(err: *const u8) -> !; + #[rustc_allocator_nounwind] + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); + #[rustc_allocator_nounwind] + fn __rust_usable_size(layout: *const u8, + min: *mut usize, + max: *mut usize); + #[rustc_allocator_nounwind] + fn __rust_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_alloc_excess(size: usize, + align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_realloc_excess(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_grow_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8; + #[rustc_allocator_nounwind] + fn __rust_shrink_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8; +} + +#[derive(Copy, Clone, Default, Debug)] +pub struct Heap; + +unsafe impl Alloc for Heap { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let ptr = __rust_alloc(layout.size(), + layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(ptr) + } + } + + #[inline] + #[cold] + fn oom(&mut self, err: AllocErr) -> ! { + unsafe { + __rust_oom(&err as *const AllocErr as *const u8) + } + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + __rust_dealloc(ptr, layout.size(), layout.align()) + } + + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + let mut min = 0; + let mut max = 0; + unsafe { + __rust_usable_size(layout as *const Layout as *const u8, + &mut min, + &mut max); + } + (min, max) + } + + #[inline] + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) + -> Result<*mut u8, AllocErr> + { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let ptr = __rust_realloc(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + mem::forget(err); + Ok(ptr) + } + } + + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let ptr = __rust_alloc_zeroed(layout.size(), + layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(ptr) + } + } + + #[inline] + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut size = 0; + let ptr = __rust_alloc_excess(layout.size(), + layout.align(), + &mut size, + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(Excess(ptr, size)) + } + } + + #[inline] + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result { + let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut size = 0; + let ptr = __rust_realloc_excess(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align(), + &mut size, + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(Excess(ptr, size)) + } + } + + #[inline] + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) + -> Result<(), CannotReallocInPlace> + { + debug_assert!(new_layout.size() >= layout.size()); + debug_assert!(new_layout.align() == layout.align()); + let ret = __rust_grow_in_place(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align()); + if ret != 0 { + Ok(()) + } else { + Err(CannotReallocInPlace) + } + } + + #[inline] + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + debug_assert!(new_layout.size() <= layout.size()); + debug_assert!(new_layout.align() == layout.align()); + let ret = __rust_shrink_in_place(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align()); + if ret != 0 { + Ok(()) + } else { + Err(CannotReallocInPlace) + } + } +} + +/// The allocator for unique pointers. +// This function must not unwind. If it does, MIR trans will fail. +#[cfg(not(test))] +#[lang = "exchange_malloc"] +#[inline] +unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { + if size == 0 { + align as *mut u8 + } else { + let layout = Layout::from_size_align_unchecked(size, align); + Heap.alloc(layout).unwrap_or_else(|err| { + Heap.oom(err) + }) + } +} + +#[cfg_attr(not(test), lang = "box_free")] +#[inline] +pub(crate) unsafe fn box_free(ptr: *mut T) { + let size = size_of_val(&*ptr); + let align = min_align_of_val(&*ptr); + // We do not allocate for Box when T is ZST, so deallocation is also not necessary. + if size != 0 { + let layout = Layout::from_size_align_unchecked(size, align); + Heap.dealloc(ptr as *mut u8, layout); + } +} + +#[cfg(test)] +mod tests { + extern crate test; + use self::test::Bencher; + use boxed::Box; + use heap::{Heap, Alloc, Layout}; + + #[test] + fn allocate_zeroed() { + unsafe { + let layout = Layout::from_size_align(1024, 1).unwrap(); + let ptr = Heap.alloc_zeroed(layout.clone()) + .unwrap_or_else(|e| Heap.oom(e)); + + let end = ptr.offset(layout.size() as isize); + let mut i = ptr; + while i < end { + assert_eq!(*i, 0); + i = i.offset(1); + } + Heap.dealloc(ptr, layout); + } + } + + #[bench] + fn alloc_owned_small(b: &mut Bencher) { + b.iter(|| { + let _: Box<_> = box 10; + }) + } +} diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs deleted file mode 100644 index 000c0123d9f..00000000000 --- a/src/liballoc/heap.rs +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] - -use core::intrinsics::{min_align_of_val, size_of_val}; -use core::mem::{self, ManuallyDrop}; -use core::usize; - -#[doc(inline)] -pub use core::heap::*; - -#[doc(hidden)] -pub mod __core { - pub use core::*; -} - -extern "Rust" { - #[allocator] - #[rustc_allocator_nounwind] - fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom(err: *const u8) -> !; - #[rustc_allocator_nounwind] - fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[rustc_allocator_nounwind] - fn __rust_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize); - #[rustc_allocator_nounwind] - fn __rust_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; - #[rustc_allocator_nounwind] - fn __rust_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; -} - -#[derive(Copy, Clone, Default, Debug)] -pub struct Heap; - -unsafe impl Alloc for Heap { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let ptr = __rust_alloc(layout.size(), - layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(ptr) - } - } - - #[inline] - #[cold] - fn oom(&mut self, err: AllocErr) -> ! { - unsafe { - __rust_oom(&err as *const AllocErr as *const u8) - } - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - __rust_dealloc(ptr, layout.size(), layout.align()) - } - - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - let mut min = 0; - let mut max = 0; - unsafe { - __rust_usable_size(layout as *const Layout as *const u8, - &mut min, - &mut max); - } - (min, max) - } - - #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) - -> Result<*mut u8, AllocErr> - { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let ptr = __rust_realloc(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - mem::forget(err); - Ok(ptr) - } - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let ptr = __rust_alloc_zeroed(layout.size(), - layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(ptr) - } - } - - #[inline] - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let mut size = 0; - let ptr = __rust_alloc_excess(layout.size(), - layout.align(), - &mut size, - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(Excess(ptr, size)) - } - } - - #[inline] - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); - let mut size = 0; - let ptr = __rust_realloc_excess(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut size, - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(Excess(ptr, size)) - } - } - - #[inline] - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) - -> Result<(), CannotReallocInPlace> - { - debug_assert!(new_layout.size() >= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_grow_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) - } - } - - #[inline] - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - debug_assert!(new_layout.size() <= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_shrink_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) - } - } -} - -/// The allocator for unique pointers. -// This function must not unwind. If it does, MIR trans will fail. -#[cfg(not(test))] -#[lang = "exchange_malloc"] -#[inline] -unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { - if size == 0 { - align as *mut u8 - } else { - let layout = Layout::from_size_align_unchecked(size, align); - Heap.alloc(layout).unwrap_or_else(|err| { - Heap.oom(err) - }) - } -} - -#[cfg_attr(not(test), lang = "box_free")] -#[inline] -pub(crate) unsafe fn box_free(ptr: *mut T) { - let size = size_of_val(&*ptr); - let align = min_align_of_val(&*ptr); - // We do not allocate for Box when T is ZST, so deallocation is also not necessary. - if size != 0 { - let layout = Layout::from_size_align_unchecked(size, align); - Heap.dealloc(ptr as *mut u8, layout); - } -} - -#[cfg(test)] -mod tests { - extern crate test; - use self::test::Bencher; - use boxed::Box; - use heap::{Heap, Alloc, Layout}; - - #[test] - fn allocate_zeroed() { - unsafe { - let layout = Layout::from_size_align(1024, 1).unwrap(); - let ptr = Heap.alloc_zeroed(layout.clone()) - .unwrap_or_else(|e| Heap.oom(e)); - - let end = ptr.offset(layout.size() as isize); - let mut i = ptr; - while i < end { - assert_eq!(*i, 0); - i = i.offset(1); - } - Heap.dealloc(ptr, layout); - } - } - - #[bench] - fn alloc_owned_small(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = box 10; - }) - } -} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5ca39442342..617bc5c52b3 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -57,7 +57,7 @@ //! //! ## Heap interfaces //! -//! The [`heap`](heap/index.html) module defines the low-level interface to the +//! The [`alloc`](alloc/index.html) module defines the low-level interface to the //! default global allocator. It is not compatible with the libc allocator API. #![allow(unused_attributes)] @@ -145,7 +145,11 @@ pub use core::heap as allocator; // Heaps provided for low-level allocation strategies -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +pub use alloc as heap; // Primitive types using the heaps above diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs new file mode 100644 index 00000000000..5c51bb2b51b --- /dev/null +++ b/src/libcore/alloc.rs @@ -0,0 +1,1125 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use cmp; +use fmt; +use mem; +use usize; +use ptr::{self, NonNull}; + +extern { + /// An opaque, unsized type. Used for pointers to allocated memory. + /// + /// This type can only be used behind a pointer like `*mut Void` or `ptr::NonNull`. + /// Such pointers are similar to C’s `void*` type. + pub type Void; +} + +impl Void { + /// Similar to `std::ptr::null`, which requires `T: Sized`. + pub fn null() -> *const Self { + 0 as _ + } + + /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. + pub fn null_mut() -> *mut Self { + 0 as _ + } +} + +/// Represents the combination of a starting address and +/// a total capacity of the returned block. +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); + +fn size_align() -> (usize, usize) { + (mem::size_of::(), mem::align_of::()) +} + +/// Layout of a block of memory. +/// +/// An instance of `Layout` describes a particular layout of memory. +/// You build a `Layout` up as an input to give to an allocator. +/// +/// All layouts have an associated non-negative size and a +/// power-of-two alignment. +/// +/// (Note however that layouts are *not* required to have positive +/// size, even though many allocators require that all memory +/// requests have positive size. A caller to the `Alloc::alloc` +/// method must either ensure that conditions like this are met, or +/// use specific allocators with looser requirements.) +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Layout { + // size of the requested block of memory, measured in bytes. + size: usize, + + // alignment of the requested block of memory, measured in bytes. + // we ensure that this is always a power-of-two, because API's + // like `posix_memalign` require it and it is a reasonable + // constraint to impose on Layout constructors. + // + // (However, we do not analogously require `align >= sizeof(void*)`, + // even though that is *also* a requirement of `posix_memalign`.) + align: usize, +} + + +// FIXME: audit default implementations for overflow errors, +// (potentially switching to overflowing_add and +// overflowing_mul as necessary). + +impl Layout { + /// Constructs a `Layout` from a given `size` and `align`, + /// or returns `None` if either of the following conditions + /// are not met: + /// + /// * `align` must be a power of two, + /// + /// * `size`, when rounded up to the nearest multiple of `align`, + /// must not overflow (i.e. the rounded value must be less than + /// `usize::MAX`). + #[inline] + pub fn from_size_align(size: usize, align: usize) -> Option { + if !align.is_power_of_two() { + return None; + } + + // (power-of-two implies align != 0.) + + // Rounded up size is: + // size_rounded_up = (size + align - 1) & !(align - 1); + // + // We know from above that align != 0. If adding (align - 1) + // does not overflow, then rounding up will be fine. + // + // Conversely, &-masking with !(align - 1) will subtract off + // only low-order-bits. Thus if overflow occurs with the sum, + // the &-mask cannot subtract enough to undo that overflow. + // + // Above implies that checking for summation overflow is both + // necessary and sufficient. + if size > usize::MAX - (align - 1) { + return None; + } + + unsafe { + Some(Layout::from_size_align_unchecked(size, align)) + } + } + + /// Creates a layout, bypassing all checks. + /// + /// # Safety + /// + /// This function is unsafe as it does not verify that `align` is + /// a power-of-two nor `size` aligned to `align` fits within the + /// address space (i.e. the `Layout::from_size_align` preconditions). + #[inline] + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + Layout { size: size, align: align } + } + + /// The minimum size in bytes for a memory block of this layout. + #[inline] + pub fn size(&self) -> usize { self.size } + + /// The minimum byte alignment for a memory block of this layout. + #[inline] + pub fn align(&self) -> usize { self.align } + + /// Constructs a `Layout` suitable for holding a value of type `T`. + pub fn new() -> Self { + let (size, align) = size_align::(); + Layout::from_size_align(size, align).unwrap() + } + + /// Produces layout describing a record that could be used to + /// allocate backing structure for `T` (which could be a trait + /// or other unsized type like a slice). + pub fn for_value(t: &T) -> Self { + let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); + Layout::from_size_align(size, align).unwrap() + } + + /// Creates a layout describing the record that can hold a value + /// of the same layout as `self`, but that also is aligned to + /// alignment `align` (measured in bytes). + /// + /// If `self` already meets the prescribed alignment, then returns + /// `self`. + /// + /// Note that this method does not add any padding to the overall + /// size, regardless of whether the returned layout has a different + /// alignment. In other words, if `K` has size 16, `K.align_to(32)` + /// will *still* have size 16. + /// + /// # Panics + /// + /// Panics if the combination of `self.size` and the given `align` + /// violates the conditions listed in `from_size_align`. + #[inline] + pub fn align_to(&self, align: usize) -> Self { + Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() + } + + /// Returns the amount of padding we must insert after `self` + /// to ensure that the following address will satisfy `align` + /// (measured in bytes). + /// + /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` + /// returns 3, because that is the minimum number of bytes of + /// padding required to get a 4-aligned address (assuming that the + /// corresponding memory block starts at a 4-aligned address). + /// + /// The return value of this function has no meaning if `align` is + /// not a power-of-two. + /// + /// Note that the utility of the returned value requires `align` + /// to be less than or equal to the alignment of the starting + /// address for the whole allocated block of memory. One way to + /// satisfy this constraint is to ensure `align <= self.align`. + #[inline] + pub fn padding_needed_for(&self, align: usize) -> usize { + let len = self.size(); + + // Rounded up value is: + // len_rounded_up = (len + align - 1) & !(align - 1); + // and then we return the padding difference: `len_rounded_up - len`. + // + // We use modular arithmetic throughout: + // + // 1. align is guaranteed to be > 0, so align - 1 is always + // valid. + // + // 2. `len + align - 1` can overflow by at most `align - 1`, + // so the &-mask wth `!(align - 1)` will ensure that in the + // case of overflow, `len_rounded_up` will itself be 0. + // Thus the returned padding, when added to `len`, yields 0, + // which trivially satisfies the alignment `align`. + // + // (Of course, attempts to allocate blocks of memory whose + // size and padding overflow in the above manner should cause + // the allocator to yield an error anyway.) + + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + return len_rounded_up.wrapping_sub(len); + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with a suitable amount of padding between each to + /// ensure that each instance is given its requested size and + /// alignment. On success, returns `(k, offs)` where `k` is the + /// layout of the array and `offs` is the distance between the start + /// of each element in the array. + /// + /// On arithmetic overflow, returns `None`. + #[inline] + pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; + let alloc_size = padded_size.checked_mul(n)?; + + // We can assume that `self.align` is a power-of-two. + // Furthermore, `alloc_size` has already been rounded up + // to a multiple of `self.align`; therefore, the call to + // `Layout::from_size_align` below should never panic. + Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + } + + /// Creates a layout describing the record for `self` followed by + /// `next`, including any necessary padding to ensure that `next` + /// will be properly aligned. Note that the result layout will + /// satisfy the alignment properties of both `self` and `next`. + /// + /// Returns `Some((k, offset))`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// On arithmetic overflow, returns `None`. + pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + let new_align = cmp::max(self.align, next.align); + let realigned = Layout::from_size_align(self.size, new_align)?; + + let pad = realigned.padding_needed_for(next.align); + + let offset = self.size.checked_add(pad)?; + let new_size = offset.checked_add(next.size)?; + + let layout = Layout::from_size_align(new_size, new_align)?; + Some((layout, offset)) + } + + /// Creates a layout describing the record for `n` instances of + /// `self`, with no padding between each instance. + /// + /// Note that, unlike `repeat`, `repeat_packed` does not guarantee + /// that the repeated instances of `self` will be properly + /// aligned, even if a given instance of `self` is properly + /// aligned. In other words, if the layout returned by + /// `repeat_packed` is used to allocate an array, it is not + /// guaranteed that all elements in the array will be properly + /// aligned. + /// + /// On arithmetic overflow, returns `None`. + pub fn repeat_packed(&self, n: usize) -> Option { + let size = self.size().checked_mul(n)?; + Layout::from_size_align(size, self.align) + } + + /// Creates a layout describing the record for `self` followed by + /// `next` with no additional padding between the two. Since no + /// padding is inserted, the alignment of `next` is irrelevant, + /// and is not incorporated *at all* into the resulting layout. + /// + /// Returns `(k, offset)`, where `k` is layout of the concatenated + /// record and `offset` is the relative location, in bytes, of the + /// start of the `next` embedded within the concatenated record + /// (assuming that the record itself starts at offset 0). + /// + /// (The `offset` is always the same as `self.size()`; we use this + /// signature out of convenience in matching the signature of + /// `extend`.) + /// + /// On arithmetic overflow, returns `None`. + pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { + let new_size = self.size().checked_add(next.size())?; + let layout = Layout::from_size_align(new_size, self.align)?; + Some((layout, self.size())) + } + + /// Creates a layout describing the record for a `[T; n]`. + /// + /// On arithmetic overflow, returns `None`. + pub fn array(n: usize) -> Option { + Layout::new::() + .repeat(n) + .map(|(k, offs)| { + debug_assert!(offs == mem::size_of::()); + k + }) + } +} + +/// The `AllocErr` error specifies whether an allocation failure is +/// specifically due to resource exhaustion or if it is due to +/// something wrong when combining the given input arguments with this +/// allocator. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum AllocErr { + /// Error due to hitting some resource limit or otherwise running + /// out of memory. This condition strongly implies that *some* + /// series of deallocations would allow a subsequent reissuing of + /// the original allocation request to succeed. + Exhausted { request: Layout }, + + /// Error due to allocator being fundamentally incapable of + /// satisfying the original request. This condition implies that + /// such an allocation request will never succeed on the given + /// allocator, regardless of environment, memory pressure, or + /// other contextual conditions. + /// + /// For example, an allocator that does not support requests for + /// large memory blocks might return this error variant. + Unsupported { details: &'static str }, +} + +impl AllocErr { + #[inline] + pub fn invalid_input(details: &'static str) -> Self { + AllocErr::Unsupported { details: details } + } + #[inline] + pub fn is_memory_exhausted(&self) -> bool { + if let AllocErr::Exhausted { .. } = *self { true } else { false } + } + #[inline] + pub fn is_request_unsupported(&self) -> bool { + if let AllocErr::Unsupported { .. } = *self { true } else { false } + } + #[inline] + pub fn description(&self) -> &str { + match *self { + AllocErr::Exhausted { .. } => "allocator memory exhausted", + AllocErr::Unsupported { .. } => "unsupported allocator request", + } + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for AllocErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// The `CannotReallocInPlace` error is used when `grow_in_place` or +/// `shrink_in_place` were unable to reuse the given memory block for +/// a requested layout. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CannotReallocInPlace; + +impl CannotReallocInPlace { + pub fn description(&self) -> &str { + "cannot reallocate allocator's memory in place" + } +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for CannotReallocInPlace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr(AllocErr), +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + fn from(err: AllocErr) -> Self { + CollectionAllocErr::AllocErr(err) + } +} + +// FIXME: docs +pub unsafe trait GlobalAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut Void; + + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout); + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + let size = layout.size(); + let ptr = self.alloc(layout); + if !ptr.is_null() { + ptr::write_bytes(ptr as *mut u8, 0, size); + } + ptr + } + + unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + let new_ptr = self.alloc(new_layout); + if !new_ptr.is_null() { + ptr::copy_nonoverlapping( + ptr as *const u8, + new_ptr as *mut u8, + cmp::min(old_layout.size(), new_size), + ); + self.dealloc(ptr, old_layout); + } + new_ptr + } +} + +/// An implementation of `Alloc` can allocate, reallocate, and +/// deallocate arbitrary blocks of data described via `Layout`. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method (`alloc`, +/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or +/// reallocation method (`realloc`, `realloc_excess`, or +/// `realloc_array`), and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being +/// passed to a reallocation method (see above) that returns `Ok`. +/// +/// A note regarding zero-sized types and zero-sized layouts: many +/// methods in the `Alloc` trait state that allocation requests +/// must be non-zero size, or else undefined behavior can result. +/// +/// * However, some higher-level allocation methods (`alloc_one`, +/// `alloc_array`) are well-defined on zero-sized types and can +/// optionally support them: it is left up to the implementor +/// whether to return `Err`, or to return `Ok` with some pointer. +/// +/// * If an `Alloc` implementation chooses to return `Ok` in this +/// case (i.e. the pointer denotes a zero-sized inaccessible block) +/// then that returned pointer must be considered "currently +/// allocated". On such an allocator, *all* methods that take +/// currently-allocated pointers as inputs must accept these +/// zero-sized pointers, *without* causing undefined behavior. +/// +/// * In other words, if a zero-sized pointer can flow out of an +/// allocator, then that allocator must likewise accept that pointer +/// flowing back into its deallocation and reallocation methods. +/// +/// Some of the methods require that a layout *fit* a memory block. +/// What it means for a layout to "fit" a memory block means (or +/// equivalently, for a memory block to "fit" a layout) is that the +/// following two conditions must hold: +/// +/// 1. The block's starting address must be aligned to `layout.align()`. +/// +/// 2. The block's size must fall in the range `[use_min, use_max]`, where: +/// +/// * `use_min` is `self.usable_size(layout).0`, and +/// +/// * `use_max` is the capacity that was (or would have been) +/// returned when (if) the block was allocated via a call to +/// `alloc_excess` or `realloc_excess`. +/// +/// Note that: +/// +/// * the size of the layout most recently used to allocate the block +/// is guaranteed to be in the range `[use_min, use_max]`, and +/// +/// * a lower-bound on `use_max` can be safely approximated by a call to +/// `usable_size`. +/// +/// * if a layout `k` fits a memory block (denoted by `ptr`) +/// currently allocated via an allocator `a`, then it is legal to +/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. +/// +/// # Unsafety +/// +/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `Alloc` is dropped +/// itself. +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. Note that as of the time of this +/// writing allocators *not* intending to be global allocators can still panic +/// in their implementation without violating memory safety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. +/// +/// Note that this list may get tweaked over time as clarifications are made in +/// the future. Additionally global allocators may gain unique requirements for +/// how to safely implement one in the future as well. +pub unsafe trait Alloc { + + // (Note: existing allocators have unspecified but well-defined + // behavior in response to a zero size allocation request ; + // e.g. in C, `malloc` of 0 will either return a null pointer or a + // unique pointer, but will not have arbitrary undefined + // behavior. Rust should consider revising the alloc::heap crate + // to reflect this reality.) + + /// Returns a pointer meeting the size and alignment guarantees of + /// `layout`. + /// + /// If this method returns an `Ok(addr)`, then the `addr` returned + /// will be non-null address pointing to a block of storage + /// suitable for holding an instance of `layout`. + /// + /// The returned block of storage may or may not have its contents + /// initialized. (Extension subtraits might restrict this + /// behavior, e.g. to ensure initialization to particular sets of + /// bit patterns.) + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints. + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + + /// Deallocate the memory referenced by `ptr`. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must *fit* that block of memory, + /// + /// * In addition to fitting the block of memory `layout`, the + /// alignment of the `layout` must match the alignment used + /// to allocate that block of memory. + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + + /// Allocator-specific method for signaling an out-of-memory + /// condition. + /// + /// `oom` aborts the thread or process, optionally performing + /// cleanup or logging diagnostic information before panicking or + /// aborting. + /// + /// `oom` is meant to be used by clients unable to cope with an + /// unsatisfied allocation request (signaled by an error such as + /// `AllocErr::Exhausted`), and wish to abandon computation rather + /// than attempt to recover locally. Such clients should pass the + /// signaling error value back into `oom`, where the allocator + /// may incorporate that error value into its diagnostic report + /// before aborting. + /// + /// Implementations of the `oom` method are discouraged from + /// infinitely regressing in nested calls to `oom`. In + /// practice this means implementors should eschew allocating, + /// especially from `self` (directly or indirectly). + /// + /// Implementations of the allocation and reallocation methods + /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from + /// panicking (or aborting) in the event of memory exhaustion; + /// instead they should return an appropriate error from the + /// invoked method, and let the client decide whether to invoke + /// this `oom` method in response. + fn oom(&mut self, _: AllocErr) -> ! { + unsafe { ::intrinsics::abort() } + } + + // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == + // usable_size + + /// Returns bounds on the guaranteed usable size of a successful + /// allocation created with the specified `layout`. + /// + /// In particular, if one has a memory block allocated via a given + /// allocator `a` and layout `k` where `a.usable_size(k)` returns + /// `(l, u)`, then one can pass that block to `a.dealloc()` with a + /// layout in the size range [l, u]. + /// + /// (All implementors of `usable_size` must ensure that + /// `l <= k.size() <= u`) + /// + /// Both the lower- and upper-bounds (`l` and `u` respectively) + /// are provided, because an allocator based on size classes could + /// misbehave if one attempts to deallocate a block without + /// providing a correct value for its size (i.e., one within the + /// range `[l, u]`). + /// + /// Clients who wish to make use of excess capacity are encouraged + /// to use the `alloc_excess` and `realloc_excess` instead, as + /// this method is constrained to report conservative values that + /// serve as valid bounds for *all possible* allocation method + /// calls. + /// + /// However, for clients that do not wish to track the capacity + /// returned by `alloc_excess` locally, this method is likely to + /// produce useful results. + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + (layout.size(), layout.size()) + } + + // == METHODS FOR MEMORY REUSE == + // realloc. alloc_excess, realloc_excess + + /// Returns a pointer suitable for holding data described by + /// `new_layout`, meeting its size and alignment guarantees. To + /// accomplish this, this may extend or shrink the allocation + /// referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then ownership of the memory block + /// referenced by `ptr` has been transferred to this + /// allocator. The memory may or may not have been freed, and + /// should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). + /// + /// If this method returns `Err`, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. + /// + /// For best results, `new_layout` should not impose a different + /// alignment constraint than `layout`. (In other words, + /// `new_layout.align()` should equal `layout.align()`.) However, + /// behavior is well-defined (though underspecified) when this + /// constraint is violated; further discussion below. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` + /// argument need not fit it.) + /// + /// * `new_layout` must have size greater than zero. + /// + /// * the alignment of `new_layout` is non-zero. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns `Err` only if `new_layout` does not match the + /// alignment of `layout`, or does not meet the allocator's size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// (Note the previous sentence did not say "if and only if" -- in + /// particular, an implementation of this method *can* return `Ok` + /// if `new_layout.align() != old_layout.align()`; or it can + /// return `Err` in that scenario, depending on whether this + /// allocator can dynamically adjust the alignment constraint for + /// the block.) + /// + /// Implementations are encouraged to return `Err` on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + let new_size = new_layout.size(); + let old_size = layout.size(); + let aligns_match = layout.align == new_layout.align; + + if new_size >= old_size && aligns_match { + if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } else if new_size < old_size && aligns_match { + if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { + return Ok(ptr); + } + } + + // otherwise, fall back on alloc + copy + dealloc. + let result = self.alloc(new_layout); + if let Ok(new_ptr) = result { + ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + self.dealloc(ptr, layout); + } + result + } + + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let size = layout.size(); + let p = self.alloc(layout); + if let Ok(p) = p { + ptr::write_bytes(p, 0, size); + } + p + } + + /// Behaves like `alloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { + let usable_size = self.usable_size(&layout); + self.alloc(layout).map(|p| Excess(p, usable_size.1)) + } + + /// Behaves like `realloc`, but also returns the whole size of + /// the returned block. For some `layout` inputs, like arrays, this + /// may include extra storage usable for additional data. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `realloc` is. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `layout` does not meet allocator's size or alignment + /// constraints, just as in `realloc`. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result { + let usable_size = self.usable_size(&new_layout); + self.realloc(ptr, layout, new_layout) + .map(|p| Excess(p, usable_size.1)) + } + + /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and thus can + /// be used to carry data of that layout. (The allocator is allowed to + /// expend effort to accomplish this, such as extending the memory block to + /// include successor blocks, or virtual memory tricks.) + /// + /// Regardless of what this method returns, ownership of the + /// memory block referenced by `ptr` has not been transferred, and + /// the contents of the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be less than `layout.size()`, + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `grow_in_place` failures without aborting, or to fall back on + /// another reallocation method before resorting to an abort. + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size >= layout.size); + debug_assert!(new_layout.align == layout.align); + let (_l, u) = self.usable_size(&layout); + // _l <= layout.size() [guaranteed by usable_size()] + // layout.size() <= new_layout.size() [required by this method] + if new_layout.size <= u { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. + /// + /// If this returns `Ok`, then the allocator has asserted that the + /// memory block referenced by `ptr` now fits `new_layout`, and + /// thus can only be used to carry data of that smaller + /// layout. (The allocator is allowed to take advantage of this, + /// carving off portions of the block for reuse elsewhere.) The + /// truncated contents of the block within the smaller layout are + /// unaltered, and ownership of block has not been transferred. + /// + /// If this returns `Err`, then the memory block is considered to + /// still represent the original (larger) `layout`. None of the + /// block has been carved off for reuse elsewhere, ownership of + /// the memory block has not been transferred, and the contents of + /// the memory block are unaltered. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must *fit* the `ptr` (see above); note the + /// `new_layout` argument need not fit it, + /// + /// * `new_layout.size()` must not be greater than `layout.size()` + /// (and must be greater than zero), + /// + /// * `new_layout.align()` must equal `layout.align()`. + /// + /// # Errors + /// + /// Returns `Err(CannotReallocInPlace)` when the allocator is + /// unable to assert that the memory block referenced by `ptr` + /// could fit `layout`. + /// + /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// method; clients are expected either to be able to recover from + /// `shrink_in_place` failures without aborting, or to fall back + /// on another reallocation method before resorting to an abort. + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let _ = ptr; // this default implementation doesn't care about the actual address. + debug_assert!(new_layout.size <= layout.size); + debug_assert!(new_layout.align == layout.align); + let (l, _u) = self.usable_size(&layout); + // layout.size() <= _u [guaranteed by usable_size()] + // new_layout.size() <= layout.size() [required by this method] + if l <= new_layout.size { + return Ok(()); + } else { + return Err(CannotReallocInPlace); + } + } + + + // == COMMON USAGE PATTERNS == + // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array + + /// Allocates a block suitable for holding an instance of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `T` does not meet allocator's size or alignment constraints. + /// + /// For zero-sized `T`, may return either of `Ok` or `Err`, but + /// will *not* yield undefined behavior. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_one(&mut self) -> Result, AllocErr> + where Self: Sized + { + let k = Layout::new::(); + if k.size() > 0 { + unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + } else { + Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + } + } + + /// Deallocates a block suitable for holding an instance of `T`. + /// + /// The given block must have been produced by this allocator, + /// and must be suitable for storing a `T` (in terms of alignment + /// as well as minimum and maximum size); otherwise yields + /// undefined behavior. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `T` must *fit* that block of memory. + unsafe fn dealloc_one(&mut self, ptr: NonNull) + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + let k = Layout::new::(); + if k.size() > 0 { + self.dealloc(raw_ptr, k); + } + } + + /// Allocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` + /// must be considered "currently allocated" and must be + /// acceptable input to methods such as `realloc` or `dealloc`, + /// *even if* `T` is a zero-sized type. In other words, if your + /// `Alloc` implementation overrides this method in a manner + /// that can return a zero-sized `ptr`, then all reallocation and + /// deallocation methods need to be similarly overridden to accept + /// such values as input. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + fn alloc_array(&mut self, n: usize) -> Result, AllocErr> + where Self: Sized + { + match Layout::array::(n) { + Some(ref layout) if layout.size() > 0 => { + unsafe { + self.alloc(layout.clone()) + .map(|p| { + NonNull::new_unchecked(p as *mut T) + }) + } + } + _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + } + } + + /// Reallocates a block previously suitable for holding `n_old` + /// instances of `T`, returning a block suitable for holding + /// `n_new` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// The returned block is suitable for passing to the + /// `alloc`/`realloc` methods of this allocator. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * the layout of `[T; n_old]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or + /// `[T; n_new]` does not meet allocator's size or alignment + /// constraints. + /// + /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or + /// `Err`, but will *not* yield undefined behavior. + /// + /// Always returns `Err` on arithmetic overflow. + /// + /// Clients wishing to abort computation in response to an + /// reallocation error are encouraged to call the allocator's `oom` + /// method, rather than directly invoking `panic!` or similar. + unsafe fn realloc_array(&mut self, + ptr: NonNull, + n_old: usize, + n_new: usize) -> Result, AllocErr> + where Self: Sized + { + match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { + (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) + .map(|p| NonNull::new_unchecked(p as *mut T)) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for realloc_array")) + } + } + } + + /// Deallocates a block suitable for holding `n` instances of `T`. + /// + /// Captures a common usage pattern for allocators. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure both: + /// + /// * `ptr` must denote a block of memory currently allocated via this allocator + /// + /// * the layout of `[T; n]` must *fit* that block of memory. + /// + /// # Errors + /// + /// Returning `Err` indicates that either `[T; n]` or the given + /// memory block does not meet allocator's size or alignment + /// constraints. + /// + /// Always returns `Err` on arithmetic overflow. + unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> + where Self: Sized + { + let raw_ptr = ptr.as_ptr() as *mut u8; + match Layout::array::(n) { + Some(ref k) if k.size() > 0 => { + Ok(self.dealloc(raw_ptr, k.clone())) + } + _ => { + Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + } + } + } +} diff --git a/src/libcore/heap.rs b/src/libcore/heap.rs deleted file mode 100644 index 5c51bb2b51b..00000000000 --- a/src/libcore/heap.rs +++ /dev/null @@ -1,1125 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] - -use cmp; -use fmt; -use mem; -use usize; -use ptr::{self, NonNull}; - -extern { - /// An opaque, unsized type. Used for pointers to allocated memory. - /// - /// This type can only be used behind a pointer like `*mut Void` or `ptr::NonNull`. - /// Such pointers are similar to C’s `void*` type. - pub type Void; -} - -impl Void { - /// Similar to `std::ptr::null`, which requires `T: Sized`. - pub fn null() -> *const Self { - 0 as _ - } - - /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. - pub fn null_mut() -> *mut Self { - 0 as _ - } -} - -/// Represents the combination of a starting address and -/// a total capacity of the returned block. -#[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); - -fn size_align() -> (usize, usize) { - (mem::size_of::(), mem::align_of::()) -} - -/// Layout of a block of memory. -/// -/// An instance of `Layout` describes a particular layout of memory. -/// You build a `Layout` up as an input to give to an allocator. -/// -/// All layouts have an associated non-negative size and a -/// power-of-two alignment. -/// -/// (Note however that layouts are *not* required to have positive -/// size, even though many allocators require that all memory -/// requests have positive size. A caller to the `Alloc::alloc` -/// method must either ensure that conditions like this are met, or -/// use specific allocators with looser requirements.) -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Layout { - // size of the requested block of memory, measured in bytes. - size: usize, - - // alignment of the requested block of memory, measured in bytes. - // we ensure that this is always a power-of-two, because API's - // like `posix_memalign` require it and it is a reasonable - // constraint to impose on Layout constructors. - // - // (However, we do not analogously require `align >= sizeof(void*)`, - // even though that is *also* a requirement of `posix_memalign`.) - align: usize, -} - - -// FIXME: audit default implementations for overflow errors, -// (potentially switching to overflowing_add and -// overflowing_mul as necessary). - -impl Layout { - /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `None` if either of the following conditions - /// are not met: - /// - /// * `align` must be a power of two, - /// - /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow (i.e. the rounded value must be less than - /// `usize::MAX`). - #[inline] - pub fn from_size_align(size: usize, align: usize) -> Option { - if !align.is_power_of_two() { - return None; - } - - // (power-of-two implies align != 0.) - - // Rounded up size is: - // size_rounded_up = (size + align - 1) & !(align - 1); - // - // We know from above that align != 0. If adding (align - 1) - // does not overflow, then rounding up will be fine. - // - // Conversely, &-masking with !(align - 1) will subtract off - // only low-order-bits. Thus if overflow occurs with the sum, - // the &-mask cannot subtract enough to undo that overflow. - // - // Above implies that checking for summation overflow is both - // necessary and sufficient. - if size > usize::MAX - (align - 1) { - return None; - } - - unsafe { - Some(Layout::from_size_align_unchecked(size, align)) - } - } - - /// Creates a layout, bypassing all checks. - /// - /// # Safety - /// - /// This function is unsafe as it does not verify that `align` is - /// a power-of-two nor `size` aligned to `align` fits within the - /// address space (i.e. the `Layout::from_size_align` preconditions). - #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { - Layout { size: size, align: align } - } - - /// The minimum size in bytes for a memory block of this layout. - #[inline] - pub fn size(&self) -> usize { self.size } - - /// The minimum byte alignment for a memory block of this layout. - #[inline] - pub fn align(&self) -> usize { self.align } - - /// Constructs a `Layout` suitable for holding a value of type `T`. - pub fn new() -> Self { - let (size, align) = size_align::(); - Layout::from_size_align(size, align).unwrap() - } - - /// Produces layout describing a record that could be used to - /// allocate backing structure for `T` (which could be a trait - /// or other unsized type like a slice). - pub fn for_value(t: &T) -> Self { - let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); - Layout::from_size_align(size, align).unwrap() - } - - /// Creates a layout describing the record that can hold a value - /// of the same layout as `self`, but that also is aligned to - /// alignment `align` (measured in bytes). - /// - /// If `self` already meets the prescribed alignment, then returns - /// `self`. - /// - /// Note that this method does not add any padding to the overall - /// size, regardless of whether the returned layout has a different - /// alignment. In other words, if `K` has size 16, `K.align_to(32)` - /// will *still* have size 16. - /// - /// # Panics - /// - /// Panics if the combination of `self.size` and the given `align` - /// violates the conditions listed in `from_size_align`. - #[inline] - pub fn align_to(&self, align: usize) -> Self { - Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() - } - - /// Returns the amount of padding we must insert after `self` - /// to ensure that the following address will satisfy `align` - /// (measured in bytes). - /// - /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` - /// returns 3, because that is the minimum number of bytes of - /// padding required to get a 4-aligned address (assuming that the - /// corresponding memory block starts at a 4-aligned address). - /// - /// The return value of this function has no meaning if `align` is - /// not a power-of-two. - /// - /// Note that the utility of the returned value requires `align` - /// to be less than or equal to the alignment of the starting - /// address for the whole allocated block of memory. One way to - /// satisfy this constraint is to ensure `align <= self.align`. - #[inline] - pub fn padding_needed_for(&self, align: usize) -> usize { - let len = self.size(); - - // Rounded up value is: - // len_rounded_up = (len + align - 1) & !(align - 1); - // and then we return the padding difference: `len_rounded_up - len`. - // - // We use modular arithmetic throughout: - // - // 1. align is guaranteed to be > 0, so align - 1 is always - // valid. - // - // 2. `len + align - 1` can overflow by at most `align - 1`, - // so the &-mask wth `!(align - 1)` will ensure that in the - // case of overflow, `len_rounded_up` will itself be 0. - // Thus the returned padding, when added to `len`, yields 0, - // which trivially satisfies the alignment `align`. - // - // (Of course, attempts to allocate blocks of memory whose - // size and padding overflow in the above manner should cause - // the allocator to yield an error anyway.) - - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); - return len_rounded_up.wrapping_sub(len); - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with a suitable amount of padding between each to - /// ensure that each instance is given its requested size and - /// alignment. On success, returns `(k, offs)` where `k` is the - /// layout of the array and `offs` is the distance between the start - /// of each element in the array. - /// - /// On arithmetic overflow, returns `None`. - #[inline] - pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; - let alloc_size = padded_size.checked_mul(n)?; - - // We can assume that `self.align` is a power-of-two. - // Furthermore, `alloc_size` has already been rounded up - // to a multiple of `self.align`; therefore, the call to - // `Layout::from_size_align` below should never panic. - Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) - } - - /// Creates a layout describing the record for `self` followed by - /// `next`, including any necessary padding to ensure that `next` - /// will be properly aligned. Note that the result layout will - /// satisfy the alignment properties of both `self` and `next`. - /// - /// Returns `Some((k, offset))`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// On arithmetic overflow, returns `None`. - pub fn extend(&self, next: Self) -> Option<(Self, usize)> { - let new_align = cmp::max(self.align, next.align); - let realigned = Layout::from_size_align(self.size, new_align)?; - - let pad = realigned.padding_needed_for(next.align); - - let offset = self.size.checked_add(pad)?; - let new_size = offset.checked_add(next.size)?; - - let layout = Layout::from_size_align(new_size, new_align)?; - Some((layout, offset)) - } - - /// Creates a layout describing the record for `n` instances of - /// `self`, with no padding between each instance. - /// - /// Note that, unlike `repeat`, `repeat_packed` does not guarantee - /// that the repeated instances of `self` will be properly - /// aligned, even if a given instance of `self` is properly - /// aligned. In other words, if the layout returned by - /// `repeat_packed` is used to allocate an array, it is not - /// guaranteed that all elements in the array will be properly - /// aligned. - /// - /// On arithmetic overflow, returns `None`. - pub fn repeat_packed(&self, n: usize) -> Option { - let size = self.size().checked_mul(n)?; - Layout::from_size_align(size, self.align) - } - - /// Creates a layout describing the record for `self` followed by - /// `next` with no additional padding between the two. Since no - /// padding is inserted, the alignment of `next` is irrelevant, - /// and is not incorporated *at all* into the resulting layout. - /// - /// Returns `(k, offset)`, where `k` is layout of the concatenated - /// record and `offset` is the relative location, in bytes, of the - /// start of the `next` embedded within the concatenated record - /// (assuming that the record itself starts at offset 0). - /// - /// (The `offset` is always the same as `self.size()`; we use this - /// signature out of convenience in matching the signature of - /// `extend`.) - /// - /// On arithmetic overflow, returns `None`. - pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { - let new_size = self.size().checked_add(next.size())?; - let layout = Layout::from_size_align(new_size, self.align)?; - Some((layout, self.size())) - } - - /// Creates a layout describing the record for a `[T; n]`. - /// - /// On arithmetic overflow, returns `None`. - pub fn array(n: usize) -> Option { - Layout::new::() - .repeat(n) - .map(|(k, offs)| { - debug_assert!(offs == mem::size_of::()); - k - }) - } -} - -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to -/// something wrong when combining the given input arguments with this -/// allocator. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum AllocErr { - /// Error due to hitting some resource limit or otherwise running - /// out of memory. This condition strongly implies that *some* - /// series of deallocations would allow a subsequent reissuing of - /// the original allocation request to succeed. - Exhausted { request: Layout }, - - /// Error due to allocator being fundamentally incapable of - /// satisfying the original request. This condition implies that - /// such an allocation request will never succeed on the given - /// allocator, regardless of environment, memory pressure, or - /// other contextual conditions. - /// - /// For example, an allocator that does not support requests for - /// large memory blocks might return this error variant. - Unsupported { details: &'static str }, -} - -impl AllocErr { - #[inline] - pub fn invalid_input(details: &'static str) -> Self { - AllocErr::Unsupported { details: details } - } - #[inline] - pub fn is_memory_exhausted(&self) -> bool { - if let AllocErr::Exhausted { .. } = *self { true } else { false } - } - #[inline] - pub fn is_request_unsupported(&self) -> bool { - if let AllocErr::Unsupported { .. } = *self { true } else { false } - } - #[inline] - pub fn description(&self) -> &str { - match *self { - AllocErr::Exhausted { .. } => "allocator memory exhausted", - AllocErr::Unsupported { .. } => "unsupported allocator request", - } - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for AllocErr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// The `CannotReallocInPlace` error is used when `grow_in_place` or -/// `shrink_in_place` were unable to reuse the given memory block for -/// a requested layout. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct CannotReallocInPlace; - -impl CannotReallocInPlace { - pub fn description(&self) -> &str { - "cannot reallocate allocator's memory in place" - } -} - -// (we need this for downstream impl of trait Error) -impl fmt::Display for CannotReallocInPlace { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -/// Augments `AllocErr` with a CapacityOverflow variant. -#[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr(AllocErr), -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - fn from(err: AllocErr) -> Self { - CollectionAllocErr::AllocErr(err) - } -} - -// FIXME: docs -pub unsafe trait GlobalAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut Void; - - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout); - - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { - let size = layout.size(); - let ptr = self.alloc(layout); - if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, size); - } - ptr - } - - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); - let new_ptr = self.alloc(new_layout); - if !new_ptr.is_null() { - ptr::copy_nonoverlapping( - ptr as *const u8, - new_ptr as *mut u8, - cmp::min(old_layout.size(), new_size), - ); - self.dealloc(ptr, old_layout); - } - new_ptr - } -} - -/// An implementation of `Alloc` can allocate, reallocate, and -/// deallocate arbitrary blocks of data described via `Layout`. -/// -/// Some of the methods require that a memory block be *currently -/// allocated* via an allocator. This means that: -/// -/// * the starting address for that memory block was previously -/// returned by a previous call to an allocation method (`alloc`, -/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or -/// reallocation method (`realloc`, `realloc_excess`, or -/// `realloc_array`), and -/// -/// * the memory block has not been subsequently deallocated, where -/// blocks are deallocated either by being passed to a deallocation -/// method (`dealloc`, `dealloc_one`, `dealloc_array`) or by being -/// passed to a reallocation method (see above) that returns `Ok`. -/// -/// A note regarding zero-sized types and zero-sized layouts: many -/// methods in the `Alloc` trait state that allocation requests -/// must be non-zero size, or else undefined behavior can result. -/// -/// * However, some higher-level allocation methods (`alloc_one`, -/// `alloc_array`) are well-defined on zero-sized types and can -/// optionally support them: it is left up to the implementor -/// whether to return `Err`, or to return `Ok` with some pointer. -/// -/// * If an `Alloc` implementation chooses to return `Ok` in this -/// case (i.e. the pointer denotes a zero-sized inaccessible block) -/// then that returned pointer must be considered "currently -/// allocated". On such an allocator, *all* methods that take -/// currently-allocated pointers as inputs must accept these -/// zero-sized pointers, *without* causing undefined behavior. -/// -/// * In other words, if a zero-sized pointer can flow out of an -/// allocator, then that allocator must likewise accept that pointer -/// flowing back into its deallocation and reallocation methods. -/// -/// Some of the methods require that a layout *fit* a memory block. -/// What it means for a layout to "fit" a memory block means (or -/// equivalently, for a memory block to "fit" a layout) is that the -/// following two conditions must hold: -/// -/// 1. The block's starting address must be aligned to `layout.align()`. -/// -/// 2. The block's size must fall in the range `[use_min, use_max]`, where: -/// -/// * `use_min` is `self.usable_size(layout).0`, and -/// -/// * `use_max` is the capacity that was (or would have been) -/// returned when (if) the block was allocated via a call to -/// `alloc_excess` or `realloc_excess`. -/// -/// Note that: -/// -/// * the size of the layout most recently used to allocate the block -/// is guaranteed to be in the range `[use_min, use_max]`, and -/// -/// * a lower-bound on `use_max` can be safely approximated by a call to -/// `usable_size`. -/// -/// * if a layout `k` fits a memory block (denoted by `ptr`) -/// currently allocated via an allocator `a`, then it is legal to -/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`. -/// -/// # Unsafety -/// -/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and -/// implementors must ensure that they adhere to these contracts: -/// -/// * Pointers returned from allocation functions must point to valid memory and -/// retain their validity until at least the instance of `Alloc` is dropped -/// itself. -/// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. Note that as of the time of this -/// writing allocators *not* intending to be global allocators can still panic -/// in their implementation without violating memory safety. -/// -/// * `Layout` queries and calculations in general must be correct. Callers of -/// this trait are allowed to rely on the contracts defined on each method, -/// and implementors must ensure such contracts remain true. -/// -/// Note that this list may get tweaked over time as clarifications are made in -/// the future. Additionally global allocators may gain unique requirements for -/// how to safely implement one in the future as well. -pub unsafe trait Alloc { - - // (Note: existing allocators have unspecified but well-defined - // behavior in response to a zero size allocation request ; - // e.g. in C, `malloc` of 0 will either return a null pointer or a - // unique pointer, but will not have arbitrary undefined - // behavior. Rust should consider revising the alloc::heap crate - // to reflect this reality.) - - /// Returns a pointer meeting the size and alignment guarantees of - /// `layout`. - /// - /// If this method returns an `Ok(addr)`, then the `addr` returned - /// will be non-null address pointing to a block of storage - /// suitable for holding an instance of `layout`. - /// - /// The returned block of storage may or may not have its contents - /// initialized. (Extension subtraits might restrict this - /// behavior, e.g. to ensure initialization to particular sets of - /// bit patterns.) - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure that `layout` has non-zero size. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints. - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - - /// Deallocate the memory referenced by `ptr`. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must denote a block of memory currently allocated via - /// this allocator, - /// - /// * `layout` must *fit* that block of memory, - /// - /// * In addition to fitting the block of memory `layout`, the - /// alignment of the `layout` must match the alignment used - /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); - - /// Allocator-specific method for signaling an out-of-memory - /// condition. - /// - /// `oom` aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request (signaled by an error such as - /// `AllocErr::Exhausted`), and wish to abandon computation rather - /// than attempt to recover locally. Such clients should pass the - /// signaling error value back into `oom`, where the allocator - /// may incorporate that error value into its diagnostic report - /// before aborting. - /// - /// Implementations of the `oom` method are discouraged from - /// infinitely regressing in nested calls to `oom`. In - /// practice this means implementors should eschew allocating, - /// especially from `self` (directly or indirectly). - /// - /// Implementations of the allocation and reallocation methods - /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from - /// panicking (or aborting) in the event of memory exhaustion; - /// instead they should return an appropriate error from the - /// invoked method, and let the client decide whether to invoke - /// this `oom` method in response. - fn oom(&mut self, _: AllocErr) -> ! { - unsafe { ::intrinsics::abort() } - } - - // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == - // usable_size - - /// Returns bounds on the guaranteed usable size of a successful - /// allocation created with the specified `layout`. - /// - /// In particular, if one has a memory block allocated via a given - /// allocator `a` and layout `k` where `a.usable_size(k)` returns - /// `(l, u)`, then one can pass that block to `a.dealloc()` with a - /// layout in the size range [l, u]. - /// - /// (All implementors of `usable_size` must ensure that - /// `l <= k.size() <= u`) - /// - /// Both the lower- and upper-bounds (`l` and `u` respectively) - /// are provided, because an allocator based on size classes could - /// misbehave if one attempts to deallocate a block without - /// providing a correct value for its size (i.e., one within the - /// range `[l, u]`). - /// - /// Clients who wish to make use of excess capacity are encouraged - /// to use the `alloc_excess` and `realloc_excess` instead, as - /// this method is constrained to report conservative values that - /// serve as valid bounds for *all possible* allocation method - /// calls. - /// - /// However, for clients that do not wish to track the capacity - /// returned by `alloc_excess` locally, this method is likely to - /// produce useful results. - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - (layout.size(), layout.size()) - } - - // == METHODS FOR MEMORY REUSE == - // realloc. alloc_excess, realloc_excess - - /// Returns a pointer suitable for holding data described by - /// `new_layout`, meeting its size and alignment guarantees. To - /// accomplish this, this may extend or shrink the allocation - /// referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then ownership of the memory block - /// referenced by `ptr` has been transferred to this - /// allocator. The memory may or may not have been freed, and - /// should be considered unusable (unless of course it was - /// transferred back to the caller again via the return value of - /// this method). - /// - /// If this method returns `Err`, then ownership of the memory - /// block has not been transferred to this allocator, and the - /// contents of the memory block are unaltered. - /// - /// For best results, `new_layout` should not impose a different - /// alignment constraint than `layout`. (In other words, - /// `new_layout.align()` should equal `layout.align()`.) However, - /// behavior is well-defined (though underspecified) when this - /// constraint is violated; further discussion below. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` - /// argument need not fit it.) - /// - /// * `new_layout` must have size greater than zero. - /// - /// * the alignment of `new_layout` is non-zero. - /// - /// (Extension subtraits might provide more specific bounds on - /// behavior, e.g. guarantee a sentinel address or a null pointer - /// in response to a zero-size allocation request.) - /// - /// # Errors - /// - /// Returns `Err` only if `new_layout` does not match the - /// alignment of `layout`, or does not meet the allocator's size - /// and alignment constraints of the allocator, or if reallocation - /// otherwise fails. - /// - /// (Note the previous sentence did not say "if and only if" -- in - /// particular, an implementation of this method *can* return `Ok` - /// if `new_layout.align() != old_layout.align()`; or it can - /// return `Err` in that scenario, depending on whether this - /// allocator can dynamically adjust the alignment constraint for - /// the block.) - /// - /// Implementations are encouraged to return `Err` on memory - /// exhaustion rather than panicking or aborting, but this is not - /// a strict requirement. (Specifically: it is *legal* to - /// implement this trait atop an underlying native allocation - /// library that aborts on memory exhaustion.) - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let new_size = new_layout.size(); - let old_size = layout.size(); - let aligns_match = layout.align == new_layout.align; - - if new_size >= old_size && aligns_match { - if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } else if new_size < old_size && aligns_match { - if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { - return Ok(ptr); - } - } - - // otherwise, fall back on alloc + copy + dealloc. - let result = self.alloc(new_layout); - if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); - self.dealloc(ptr, layout); - } - result - } - - /// Behaves like `alloc`, but also ensures that the contents - /// are set to zero before being returned. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let size = layout.size(); - let p = self.alloc(layout); - if let Ok(p) = p { - ptr::write_bytes(p, 0, size); - } - p - } - - /// Behaves like `alloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `alloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `alloc`. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let usable_size = self.usable_size(&layout); - self.alloc(layout).map(|p| Excess(p, usable_size.1)) - } - - /// Behaves like `realloc`, but also returns the whole size of - /// the returned block. For some `layout` inputs, like arrays, this - /// may include extra storage usable for additional data. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `realloc` is. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `layout` does not meet allocator's size or alignment - /// constraints, just as in `realloc`. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let usable_size = self.usable_size(&new_layout); - self.realloc(ptr, layout, new_layout) - .map(|p| Excess(p, usable_size.1)) - } - - /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and thus can - /// be used to carry data of that layout. (The allocator is allowed to - /// expend effort to accomplish this, such as extending the memory block to - /// include successor blocks, or virtual memory tricks.) - /// - /// Regardless of what this method returns, ownership of the - /// memory block referenced by `ptr` has not been transferred, and - /// the contents of the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be less than `layout.size()`, - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `grow_in_place` failures without aborting, or to fall back on - /// another reallocation method before resorting to an abort. - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size >= layout.size); - debug_assert!(new_layout.align == layout.align); - let (_l, u) = self.usable_size(&layout); - // _l <= layout.size() [guaranteed by usable_size()] - // layout.size() <= new_layout.size() [required by this method] - if new_layout.size <= u { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and - /// thus can only be used to carry data of that smaller - /// layout. (The allocator is allowed to take advantage of this, - /// carving off portions of the block for reuse elsewhere.) The - /// truncated contents of the block within the smaller layout are - /// unaltered, and ownership of block has not been transferred. - /// - /// If this returns `Err`, then the memory block is considered to - /// still represent the original (larger) `layout`. None of the - /// block has been carved off for reuse elsewhere, ownership of - /// the memory block has not been transferred, and the contents of - /// the memory block are unaltered. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, - /// - /// * `new_layout.size()` must not be greater than `layout.size()` - /// (and must be greater than zero), - /// - /// * `new_layout.align()` must equal `layout.align()`. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from - /// `shrink_in_place` failures without aborting, or to fall back - /// on another reallocation method before resorting to an abort. - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size <= layout.size); - debug_assert!(new_layout.align == layout.align); - let (l, _u) = self.usable_size(&layout); - // layout.size() <= _u [guaranteed by usable_size()] - // new_layout.size() <= layout.size() [required by this method] - if l <= new_layout.size { - return Ok(()); - } else { - return Err(CannotReallocInPlace); - } - } - - - // == COMMON USAGE PATTERNS == - // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array - - /// Allocates a block suitable for holding an instance of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `T` does not meet allocator's size or alignment constraints. - /// - /// For zero-sized `T`, may return either of `Ok` or `Err`, but - /// will *not* yield undefined behavior. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_one(&mut self) -> Result, AllocErr> - where Self: Sized - { - let k = Layout::new::(); - if k.size() > 0 { - unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } - } else { - Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) - } - } - - /// Deallocates a block suitable for holding an instance of `T`. - /// - /// The given block must have been produced by this allocator, - /// and must be suitable for storing a `T` (in terms of alignment - /// as well as minimum and maximum size); otherwise yields - /// undefined behavior. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `T` must *fit* that block of memory. - unsafe fn dealloc_one(&mut self, ptr: NonNull) - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - let k = Layout::new::(); - if k.size() > 0 { - self.dealloc(raw_ptr, k); - } - } - - /// Allocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `Alloc` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - fn alloc_array(&mut self, n: usize) -> Result, AllocErr> - where Self: Sized - { - match Layout::array::(n) { - Some(ref layout) if layout.size() > 0 => { - unsafe { - self.alloc(layout.clone()) - .map(|p| { - NonNull::new_unchecked(p as *mut T) - }) - } - } - _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), - } - } - - /// Reallocates a block previously suitable for holding `n_old` - /// instances of `T`, returning a block suitable for holding - /// `n_new` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `alloc`/`realloc` methods of this allocator. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: - /// - /// * `ptr` must be currently allocated via this allocator, - /// - /// * the layout of `[T; n_old]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n_new]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn realloc_array(&mut self, - ptr: NonNull, - n_old: usize, - n_new: usize) -> Result, AllocErr> - where Self: Sized - { - match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { - self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) - .map(|p| NonNull::new_unchecked(p as *mut T)) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for realloc_array")) - } - } - } - - /// Deallocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `[T; n]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either `[T; n]` or the given - /// memory block does not meet allocator's size or alignment - /// constraints. - /// - /// Always returns `Err` on arithmetic overflow. - unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> - where Self: Sized - { - let raw_ptr = ptr.as_ptr() as *mut u8; - match Layout::array::(n) { - Some(ref k) if k.size() > 0 => { - Ok(self.dealloc(raw_ptr, k.clone())) - } - _ => { - Err(AllocErr::invalid_input("invalid layout for dealloc_array")) - } - } - } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 722a9de215c..56d4e65d3ac 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -185,7 +185,11 @@ pub mod unicode; /* Heap memory allocator trait */ #[allow(missing_docs)] -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +pub use alloc as heap; // note: does not need to be public mod iter_private; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs new file mode 100644 index 00000000000..b42a1052c49 --- /dev/null +++ b/src/libstd/alloc.rs @@ -0,0 +1,176 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! dox + +#![unstable(issue = "32838", feature = "allocator_api")] + +pub use alloc_crate::heap::Heap; +pub use alloc_system::System; +#[doc(inline)] pub use core::heap::*; + +#[cfg(not(test))] +#[doc(hidden)] +#[allow(unused_attributes)] +pub mod __default_lib_allocator { + use super::{System, Layout, Alloc, AllocErr}; + use ptr; + + // for symbol names src/librustc/middle/allocator.rs + // for signatures src/librustc_allocator/lib.rs + + // linkage directives are provided as part of the current compiler allocator + // ABI + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc(layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { + System.oom((*(err as *const AllocErr)).clone()) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, + size: usize, + align: usize) { + System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_usable_size(layout: *const u8, + min: *mut usize, + max: *mut usize) { + let pair = System.usable_size(&*(layout as *const Layout)); + *min = pair.0; + *max = pair.1; + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.realloc(ptr, old_layout, new_layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_zeroed(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc_zeroed(layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_excess(size: usize, + align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc_excess(layout) { + Ok(p) => { + *excess = p.1; + p.0 + } + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.realloc_excess(ptr, old_layout, new_layout) { + Ok(p) => { + *excess = p.1; + p.0 + } + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.grow_in_place(ptr, old_layout, new_layout) { + Ok(()) => 1, + Err(_) => 0, + } + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.shrink_in_place(ptr, old_layout, new_layout) { + Ok(()) => 1, + Err(_) => 0, + } + } +} diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs deleted file mode 100644 index b42a1052c49..00000000000 --- a/src/libstd/heap.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! dox - -#![unstable(issue = "32838", feature = "allocator_api")] - -pub use alloc_crate::heap::Heap; -pub use alloc_system::System; -#[doc(inline)] pub use core::heap::*; - -#[cfg(not(test))] -#[doc(hidden)] -#[allow(unused_attributes)] -pub mod __default_lib_allocator { - use super::{System, Layout, Alloc, AllocErr}; - use ptr; - - // for symbol names src/librustc/middle/allocator.rs - // for signatures src/librustc_allocator/lib.rs - - // linkage directives are provided as part of the current compiler allocator - // ABI - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { - System.oom((*(err as *const AllocErr)).clone()) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, - size: usize, - align: usize) { - System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize) { - let pair = System.usable_size(&*(layout as *const Layout)); - *min = pair.0; - *max = pair.1; - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc(ptr, old_layout, new_layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_zeroed(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_zeroed(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_excess(layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc_excess(ptr, old_layout, new_layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.grow_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.shrink_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } -} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ef4205e7a62..3a99e845a16 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -477,7 +477,11 @@ pub mod path; pub mod process; pub mod sync; pub mod time; -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +pub use alloc as heap; // Platform-abstraction modules #[macro_use] -- cgit 1.4.1-3-g733a5 From 743c29bdc5b0a75c648e1317aa5d1d816007f176 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 21:05:10 +0200 Subject: Actually deprecate heap modules. --- src/liballoc/alloc.rs | 2 +- src/liballoc/lib.rs | 10 ++++++++-- src/libcore/lib.rs | 5 ++++- src/libstd/alloc.rs | 6 +++--- src/libstd/lib.rs | 5 ++++- 5 files changed, 20 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 000c0123d9f..2477166966e 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -20,7 +20,7 @@ use core::mem::{self, ManuallyDrop}; use core::usize; #[doc(inline)] -pub use core::heap::*; +pub use core::alloc::*; #[doc(hidden)] pub mod __core { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 617bc5c52b3..066698a71df 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -141,7 +141,10 @@ mod macros; #[rustc_deprecated(since = "1.27.0", reason = "use the heap module in core, alloc, or std instead")] #[unstable(feature = "allocator_api", issue = "32838")] -pub use core::heap as allocator; +/// Use the `alloc` module instead. +pub mod allocator { + pub use alloc::*; +} // Heaps provided for low-level allocation strategies @@ -149,7 +152,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -pub use alloc as heap; +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // Primitive types using the heaps above diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 56d4e65d3ac..5ebd9e4334c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -189,7 +189,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -pub use alloc as heap; +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // note: does not need to be public mod iter_private; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index b42a1052c49..77be3e52d76 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -12,9 +12,9 @@ #![unstable(issue = "32838", feature = "allocator_api")] -pub use alloc_crate::heap::Heap; -pub use alloc_system::System; -#[doc(inline)] pub use core::heap::*; +#[doc(inline)] pub use alloc_crate::alloc::Heap; +#[doc(inline)] pub use alloc_system::System; +#[doc(inline)] pub use core::alloc::*; #[cfg(not(test))] #[doc(hidden)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3a99e845a16..25ba75fd35e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -481,7 +481,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -pub use alloc as heap; +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // Platform-abstraction modules #[macro_use] -- cgit 1.4.1-3-g733a5 From e521b8b472dfe058f6d0f62f2e1ab5f291c220ee Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 21:15:06 +0200 Subject: Actually deprecate the Heap type --- src/liballoc/alloc.rs | 8 ++++++-- src/liballoc/arc.rs | 13 ++++++------- src/liballoc/btree/node.rs | 13 ++++++------- src/liballoc/raw_vec.rs | 23 +++++++++++------------ src/liballoc/rc.rs | 13 ++++++------- src/liballoc/tests/heap.rs | 4 ++-- src/libstd/alloc.rs | 3 ++- src/libstd/collections/hash/map.rs | 4 ++-- src/libstd/collections/hash/table.rs | 12 ++++++------ 9 files changed, 47 insertions(+), 46 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 1bd95cfd08c..12ee7701903 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -81,8 +81,12 @@ pub struct Global; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] -pub use self::Global as Heap; +pub type Heap = Global; +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] +#[allow(non_upper_case_globals)] +pub const Heap: Global = Global; unsafe impl Alloc for Global { #[inline] @@ -268,7 +272,7 @@ mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use heap::{Global, Alloc, Layout}; + use alloc::{Global, Alloc, Layout}; #[test] fn allocate_zeroed() { diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index ccf2e2768d1..d63ed24aa4f 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -21,7 +21,6 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; use core::borrow; use core::fmt; use core::cmp::Ordering; -use core::heap::{Alloc, Layout}; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val, uninitialized}; use core::ops::Deref; @@ -32,7 +31,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use heap::{Heap, box_free}; +use alloc::{Global, Alloc, Layout, box_free}; use boxed::Box; use string::String; use vec::Vec; @@ -521,7 +520,7 @@ impl Arc { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) } } @@ -555,8 +554,8 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); - let mem = Heap.alloc(layout) - .unwrap_or_else(|e| Heap.oom(e)); + let mem = Global.alloc(layout) + .unwrap_or_else(|e| Global.oom(e)); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem) as *mut ArcInner; @@ -640,7 +639,7 @@ impl ArcFromSlice for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Heap.dealloc(self.mem, self.layout.clone()); + Global.dealloc(self.mem, self.layout.clone()); } } } @@ -1161,7 +1160,7 @@ impl Drop for Weak { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 49109d522e9..8e23228bd28 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -41,14 +41,13 @@ // - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges. // This implies that even an empty internal node has at least one edge. -use core::heap::{Alloc, Layout}; use core::marker::PhantomData; use core::mem; use core::ptr::{self, Unique, NonNull}; use core::slice; +use alloc::{Global, Alloc, Layout}; use boxed::Box; -use heap::Heap; const B: usize = 6; pub const MIN_LEN: usize = B - 1; @@ -250,7 +249,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Heap.dealloc(top, Layout::new::>()); + Global.dealloc(top, Layout::new::>()); } } } @@ -436,7 +435,7 @@ impl NodeRef { > { let ptr = self.as_leaf() as *const LeafNode as *const u8 as *mut u8; let ret = self.ascend().ok(); - Heap.dealloc(ptr, Layout::new::>()); + Global.dealloc(ptr, Layout::new::>()); ret } } @@ -457,7 +456,7 @@ impl NodeRef { > { let ptr = self.as_internal() as *const InternalNode as *const u8 as *mut u8; let ret = self.ascend().ok(); - Heap.dealloc(ptr, Layout::new::>()); + Global.dealloc(ptr, Layout::new::>()); ret } } @@ -1239,12 +1238,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: ).correct_parent_link(); } - Heap.dealloc( + Global.dealloc( right_node.node.as_ptr() as *mut u8, Layout::new::>(), ); } else { - Heap.dealloc( + Global.dealloc( right_node.node.as_ptr() as *mut u8, Layout::new::>(), ); diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 3edce8aebdf..51f39dc6cc7 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use alloc::{Alloc, Layout, Global}; use core::cmp; -use core::heap::{Alloc, Layout}; use core::mem; use core::ops::Drop; use core::ptr::{self, Unique}; use core::slice; -use heap::Heap; use super::boxed::Box; use super::allocator::CollectionAllocErr; use super::allocator::CollectionAllocErr::*; @@ -47,7 +46,7 @@ use super::allocator::CollectionAllocErr::*; /// field. This allows zero-sized types to not be special-cased by consumers of /// this type. #[allow(missing_debug_implementations)] -pub struct RawVec { +pub struct RawVec { ptr: Unique, cap: usize, a: A, @@ -114,14 +113,14 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Creates the biggest possible RawVec (on the system heap) /// without allocating. If T has positive size, then this makes a /// RawVec with capacity 0. If T has 0 size, then it makes a /// RawVec with capacity `usize::MAX`. Useful for implementing /// delayed allocation. pub fn new() -> Self { - Self::new_in(Heap) + Self::new_in(Global) } /// Creates a RawVec (on the system heap) with exactly the @@ -141,13 +140,13 @@ impl RawVec { /// Aborts on OOM #[inline] pub fn with_capacity(cap: usize) -> Self { - RawVec::allocate_in(cap, false, Heap) + RawVec::allocate_in(cap, false, Global) } /// Like `with_capacity` but guarantees the buffer is zeroed. #[inline] pub fn with_capacity_zeroed(cap: usize) -> Self { - RawVec::allocate_in(cap, true, Heap) + RawVec::allocate_in(cap, true, Global) } } @@ -168,7 +167,7 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Reconstitutes a RawVec from a pointer, capacity. /// /// # Undefined Behavior @@ -180,7 +179,7 @@ impl RawVec { RawVec { ptr: Unique::new_unchecked(ptr), cap, - a: Heap, + a: Global, } } @@ -678,7 +677,7 @@ impl RawVec { } } -impl RawVec { +impl RawVec { /// Converts the entire buffer into `Box<[T]>`. /// /// While it is not *strictly* Undefined Behavior to call @@ -763,13 +762,13 @@ mod tests { if size > self.fuel { return Err(AllocErr::Unsupported { details: "fuel exhausted" }); } - match Heap.alloc(layout) { + match Global.alloc(layout) { ok @ Ok(_) => { self.fuel -= size; ok } err @ Err(_) => err, } } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - Heap.dealloc(ptr, layout) + Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 8bdc57f96a6..c134b181158 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -250,7 +250,6 @@ use core::cell::Cell; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; -use core::heap::{Alloc, Layout}; use core::intrinsics::abort; use core::marker; use core::marker::{Unsize, PhantomData}; @@ -260,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use heap::{Heap, box_free}; +use alloc::{Global, Alloc, Layout, box_free}; use string::String; use vec::Vec; @@ -668,8 +667,8 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); - let mem = Heap.alloc(layout) - .unwrap_or_else(|e| Heap.oom(e)); + let mem = Global.alloc(layout) + .unwrap_or_else(|e| Global.oom(e)); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem) as *mut RcBox; @@ -752,7 +751,7 @@ impl RcFromSlice for Rc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Heap.dealloc(self.mem, self.layout.clone()); + Global.dealloc(self.mem, self.layout.clone()); } } } @@ -847,7 +846,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); } } } @@ -1273,7 +1272,7 @@ impl Drop for Weak { // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); } } } diff --git a/src/liballoc/tests/heap.rs b/src/liballoc/tests/heap.rs index d3ce12056bb..328131e2fef 100644 --- a/src/liballoc/tests/heap.rs +++ b/src/liballoc/tests/heap.rs @@ -9,7 +9,7 @@ // except according to those terms. use alloc_system::System; -use std::heap::{Heap, Alloc, Layout}; +use std::alloc::{Global, Alloc, Layout}; /// https://github.com/rust-lang/rust/issues/45955 /// @@ -22,7 +22,7 @@ fn alloc_system_overaligned_request() { #[test] fn std_heap_overaligned_request() { - check_overalign_requests(Heap) + check_overalign_requests(Global) } fn check_overalign_requests(mut allocator: T) { diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 77be3e52d76..eb0c960732d 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -12,7 +12,8 @@ #![unstable(issue = "32838", feature = "allocator_api")] -#[doc(inline)] pub use alloc_crate::alloc::Heap; +#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; +#[doc(inline)] pub use alloc_crate::alloc::Global; #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 73a5df8dc28..c4ef9e62577 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,13 +11,13 @@ use self::Entry::*; use self::VacantEntryState::*; +use alloc::{Global, Alloc, CollectionAllocErr}; use cell::Cell; use borrow::Borrow; use cmp::max; use fmt::{self, Debug}; #[allow(deprecated)] use hash::{Hash, Hasher, BuildHasher, SipHasher13}; -use heap::{Heap, Alloc, CollectionAllocErr}; use iter::{FromIterator, FusedIterator}; use mem::{self, replace}; use ops::{Deref, Index}; @@ -784,7 +784,7 @@ impl HashMap pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), Ok(()) => { /* yay */ } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 878cd82a258..10bab5df8b5 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use alloc::{Global, Alloc, Layout, CollectionAllocErr}; use cmp; use hash::{BuildHasher, Hash, Hasher}; -use heap::{Heap, Alloc, Layout, CollectionAllocErr}; use marker; use mem::{align_of, size_of, needs_drop}; use mem; @@ -754,7 +754,7 @@ impl RawTable { return Err(CollectionAllocErr::CapacityOverflow); } - let buffer = Heap.alloc(Layout::from_size_align(size, alignment) + let buffer = Global.alloc(Layout::from_size_align(size, alignment) .ok_or(CollectionAllocErr::CapacityOverflow)?)?; let hashes = buffer as *mut HashUint; @@ -772,7 +772,7 @@ impl RawTable { unsafe fn new_uninitialized(capacity: usize) -> RawTable { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), Ok(table) => { table } } } @@ -811,7 +811,7 @@ impl RawTable { pub fn new(capacity: usize) -> RawTable { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), Ok(table) => { table } } } @@ -1185,8 +1185,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { debug_assert!(!oflo, "should be impossible"); unsafe { - Heap.dealloc(self.hashes.ptr() as *mut u8, - Layout::from_size_align(size, align).unwrap()); + Global.dealloc(self.hashes.ptr() as *mut u8, + Layout::from_size_align(size, align).unwrap()); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } -- cgit 1.4.1-3-g733a5 From ba7081a033de4981ccad1e1525c8b5191ce02208 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 15:41:09 +0200 Subject: Make AllocErr a zero-size unit struct --- src/liballoc/alloc.rs | 32 ++++++++++++------------ src/liballoc/raw_vec.rs | 2 +- src/liballoc_jemalloc/lib.rs | 25 +++---------------- src/liballoc_system/lib.rs | 24 +++++++----------- src/libcore/alloc.rs | 58 ++++++-------------------------------------- src/libstd/alloc.rs | 43 ++++++++++---------------------- src/libstd/error.rs | 2 +- 7 files changed, 51 insertions(+), 135 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 00a8b2c0e25..b975ff6be58 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -16,7 +16,7 @@ issue = "32838")] use core::intrinsics::{min_align_of_val, size_of_val}; -use core::mem::{self, ManuallyDrop}; +use core::mem; use core::usize; #[doc(inline)] @@ -86,12 +86,12 @@ pub const Heap: Global = Global; unsafe impl Alloc for Global { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let ptr = __rust_alloc(layout.size(), layout.align(), - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(ptr) } @@ -129,15 +129,15 @@ unsafe impl Alloc for Global { new_layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let ptr = __rust_realloc(ptr, layout.size(), layout.align(), new_layout.size(), new_layout.align(), - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { mem::forget(err); Ok(ptr) @@ -146,12 +146,12 @@ unsafe impl Alloc for Global { #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(ptr) } @@ -159,14 +159,14 @@ unsafe impl Alloc for Global { #[inline] unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let mut size = 0; let ptr = __rust_alloc_excess(layout.size(), layout.align(), &mut size, - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(Excess(ptr, size)) } @@ -177,7 +177,7 @@ unsafe impl Alloc for Global { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - let mut err = ManuallyDrop::new(mem::uninitialized::()); + let mut err = AllocErr; let mut size = 0; let ptr = __rust_realloc_excess(ptr, layout.size(), @@ -185,9 +185,9 @@ unsafe impl Alloc for Global { new_layout.size(), new_layout.align(), &mut size, - &mut *err as *mut AllocErr as *mut u8); + &mut err as *mut AllocErr as *mut u8); if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) + Err(AllocErr) } else { Ok(Excess(ptr, size)) } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 51f39dc6cc7..caedb971ddc 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -760,7 +760,7 @@ mod tests { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { let size = layout.size(); if size > self.fuel { - return Err(AllocErr::Unsupported { details: "fuel exhausted" }); + return Err(AllocErr); } match Global.alloc(layout) { ok @ Ok(_) => { self.fuel -= size; ok } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 616181d99bc..59a7e87e1ec 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -30,8 +30,6 @@ extern crate libc; pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { - use core::ptr; - use core::alloc::{Alloc, AllocErr, Layout}; use alloc_system::System; use libc::{c_int, c_void, size_t}; @@ -106,14 +104,9 @@ mod contents { #[rustc_std_internal_symbol] pub unsafe extern fn __rde_alloc(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let flags = align_to_flags(align, size); let ptr = mallocx(size as size_t, flags) as *mut u8; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(size, align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } @@ -155,20 +148,13 @@ mod contents { old_align: usize, new_size: usize, new_align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { if new_align != old_align { - ptr::write(err as *mut AllocErr, - AllocErr::Unsupported { details: "can't change alignments" }); return 0 as *mut u8 } let flags = align_to_flags(new_align, new_size); let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(new_size, new_align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } @@ -176,18 +162,13 @@ mod contents { #[rustc_std_internal_symbol] pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let ptr = if align <= MIN_ALIGN && align <= size { calloc(size as size_t, 1) as *mut u8 } else { let flags = align_to_flags(align, size) | MALLOCX_ZERO; mallocx(size as size_t, flags) as *mut u8 }; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(size, align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 6f928287ef2..5dca05cf085 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -133,9 +133,7 @@ mod platform { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - return Err(AllocErr::Unsupported { - details: "requested alignment too large" - }) + return Err(AllocErr) } } aligned_malloc(&layout) @@ -143,7 +141,7 @@ mod platform { if !ptr.is_null() { Ok(ptr) } else { - Err(AllocErr::Exhausted { request: layout }) + Err(AllocErr) } } @@ -156,7 +154,7 @@ mod platform { if !ptr.is_null() { Ok(ptr) } else { - Err(AllocErr::Exhausted { request: layout }) + Err(AllocErr) } } else { let ret = self.alloc(layout.clone()); @@ -178,9 +176,7 @@ mod platform { old_layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { if old_layout.align() != new_layout.align() { - return Err(AllocErr::Unsupported { - details: "cannot change alignment on `realloc`", - }) + return Err(AllocErr) } if new_layout.align() <= MIN_ALIGN && new_layout.align() <= new_layout.size(){ @@ -188,7 +184,7 @@ mod platform { if !ptr.is_null() { Ok(ptr as *mut u8) } else { - Err(AllocErr::Exhausted { request: new_layout }) + Err(AllocErr) } } else { let res = self.alloc(new_layout.clone()); @@ -342,7 +338,7 @@ mod platform { } }; if ptr.is_null() { - Err(AllocErr::Exhausted { request: layout }) + Err(AllocErr) } else { Ok(ptr as *mut u8) } @@ -382,9 +378,7 @@ mod platform { old_layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { if old_layout.align() != new_layout.align() { - return Err(AllocErr::Unsupported { - details: "cannot change alignment on `realloc`", - }) + return Err(AllocErr) } if new_layout.align() <= MIN_ALIGN { @@ -395,7 +389,7 @@ mod platform { if !ptr.is_null() { Ok(ptr as *mut u8) } else { - Err(AllocErr::Exhausted { request: new_layout }) + Err(AllocErr) } } else { let res = self.alloc(new_layout.clone()); @@ -505,7 +499,7 @@ mod platform { if !ptr.is_null() { Ok(ptr) } else { - Err(AllocErr::Unsupported { details: "" }) + Err(AllocErr) } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 5c51bb2b51b..b6626ff9f26 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -320,50 +320,12 @@ impl Layout { /// something wrong when combining the given input arguments with this /// allocator. #[derive(Clone, PartialEq, Eq, Debug)] -pub enum AllocErr { - /// Error due to hitting some resource limit or otherwise running - /// out of memory. This condition strongly implies that *some* - /// series of deallocations would allow a subsequent reissuing of - /// the original allocation request to succeed. - Exhausted { request: Layout }, - - /// Error due to allocator being fundamentally incapable of - /// satisfying the original request. This condition implies that - /// such an allocation request will never succeed on the given - /// allocator, regardless of environment, memory pressure, or - /// other contextual conditions. - /// - /// For example, an allocator that does not support requests for - /// large memory blocks might return this error variant. - Unsupported { details: &'static str }, -} - -impl AllocErr { - #[inline] - pub fn invalid_input(details: &'static str) -> Self { - AllocErr::Unsupported { details: details } - } - #[inline] - pub fn is_memory_exhausted(&self) -> bool { - if let AllocErr::Exhausted { .. } = *self { true } else { false } - } - #[inline] - pub fn is_request_unsupported(&self) -> bool { - if let AllocErr::Unsupported { .. } = *self { true } else { false } - } - #[inline] - pub fn description(&self) -> &str { - match *self { - AllocErr::Exhausted { .. } => "allocator memory exhausted", - AllocErr::Unsupported { .. } => "unsupported allocator request", - } - } -} +pub struct AllocErr; // (we need this for downstream impl of trait Error) impl fmt::Display for AllocErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) + f.write_str("memory allocation failed") } } @@ -592,12 +554,8 @@ pub unsafe trait Alloc { /// aborting. /// /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request (signaled by an error such as - /// `AllocErr::Exhausted`), and wish to abandon computation rather - /// than attempt to recover locally. Such clients should pass the - /// signaling error value back into `oom`, where the allocator - /// may incorporate that error value into its diagnostic report - /// before aborting. + /// unsatisfied allocation request, and wish to abandon + /// computation rather than attempt to recover locally. /// /// Implementations of the `oom` method are discouraged from /// infinitely regressing in nested calls to `oom`. In @@ -963,7 +921,7 @@ pub unsafe trait Alloc { if k.size() > 0 { unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } } else { - Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + Err(AllocErr) } } @@ -1036,7 +994,7 @@ pub unsafe trait Alloc { }) } } - _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + _ => Err(AllocErr), } } @@ -1084,7 +1042,7 @@ pub unsafe trait Alloc { .map(|p| NonNull::new_unchecked(p as *mut T)) } _ => { - Err(AllocErr::invalid_input("invalid layout for realloc_array")) + Err(AllocErr) } } } @@ -1118,7 +1076,7 @@ pub unsafe trait Alloc { Ok(self.dealloc(raw_ptr, k.clone())) } _ => { - Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + Err(AllocErr) } } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index eb0c960732d..533ad3ad473 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -21,9 +21,7 @@ #[doc(hidden)] #[allow(unused_attributes)] pub mod __default_lib_allocator { - use super::{System, Layout, Alloc, AllocErr}; - use ptr; - + use super::{System, Layout, Alloc, AllocErr, CannotReallocInPlace}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -34,14 +32,11 @@ pub mod __default_lib_allocator { #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); match System.alloc(layout) { Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -76,15 +71,12 @@ pub mod __default_lib_allocator { old_align: usize, new_size: usize, new_align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, old_align); let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.realloc(ptr, old_layout, new_layout) { Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -92,14 +84,11 @@ pub mod __default_lib_allocator { #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); match System.alloc_zeroed(layout) { Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -108,17 +97,14 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_alloc_excess(size: usize, align: usize, excess: *mut usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); match System.alloc_excess(layout) { Ok(p) => { *excess = p.1; p.0 } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -130,7 +116,7 @@ pub mod __default_lib_allocator { new_size: usize, new_align: usize, excess: *mut usize, - err: *mut u8) -> *mut u8 { + _err: *mut u8) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, old_align); let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.realloc_excess(ptr, old_layout, new_layout) { @@ -138,10 +124,7 @@ pub mod __default_lib_allocator { *excess = p.1; p.0 } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } + Err(AllocErr) => 0 as *mut u8, } } @@ -156,7 +139,7 @@ pub mod __default_lib_allocator { let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.grow_in_place(ptr, old_layout, new_layout) { Ok(()) => 1, - Err(_) => 0, + Err(CannotReallocInPlace) => 0, } } @@ -171,7 +154,7 @@ pub mod __default_lib_allocator { let new_layout = Layout::from_size_align_unchecked(new_size, new_align); match System.shrink_in_place(ptr, old_layout, new_layout) { Ok(()) => 1, - Err(_) => 0, + Err(CannotReallocInPlace) => 0, } } } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 4edb897350e..ec55a3c021a 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -243,7 +243,7 @@ impl Error for ! { issue = "32838")] impl Error for AllocErr { fn description(&self) -> &str { - AllocErr::description(self) + "memory allocation failed" } } -- cgit 1.4.1-3-g733a5 From 86753ce1cc520bfe50ae89f09ec47f313ce900eb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 17:12:57 +0200 Subject: Use the GlobalAlloc trait for #[global_allocator] --- src/Cargo.lock | 1 - .../src/language-features/global-allocator.md | 8 +- src/liballoc/alloc.rs | 188 +++----------- src/liballoc_jemalloc/Cargo.toml | 1 - src/liballoc_jemalloc/lib.rs | 110 +------- src/librustc_allocator/expand.rs | 283 +++------------------ src/librustc_allocator/lib.rs | 39 +-- src/librustc_trans/allocator.rs | 28 +- src/libstd/alloc.rs | 153 ++++------- src/llvm | 2 +- src/rustllvm/llvm-rebuild-trigger | 2 +- .../compile-fail/allocator/not-an-allocator.rs | 14 +- src/test/run-make-fulldeps/std-core-cycle/bar.rs | 8 +- src/test/run-pass/allocator/auxiliary/custom.rs | 8 +- src/test/run-pass/allocator/custom.rs | 12 +- src/test/run-pass/allocator/xcrate-use.rs | 6 +- src/test/run-pass/allocator/xcrate-use2.rs | 12 +- 17 files changed, 168 insertions(+), 707 deletions(-) (limited to 'src/libstd') diff --git a/src/Cargo.lock b/src/Cargo.lock index e5297d1482e..2e969f4ec2b 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -19,7 +19,6 @@ dependencies = [ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ - "alloc_system 0.0.0", "build_helper 0.1.0", "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index b3e6925b666..6ce12ba684d 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -29,16 +29,16 @@ looks like: ```rust #![feature(global_allocator, allocator_api, heap_api)] -use std::heap::{Alloc, System, Layout, AllocErr}; +use std::alloc::{GlobalAlloc, System, Layout, Void}; struct MyAllocator; -unsafe impl<'a> Alloc for &'a MyAllocator { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl GlobalAlloc for MyAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut Void { System.alloc(layout) } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { System.dealloc(ptr, layout) } } diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index b975ff6be58..73bc78eb8a2 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -16,26 +16,19 @@ issue = "32838")] use core::intrinsics::{min_align_of_val, size_of_val}; -use core::mem; use core::usize; #[doc(inline)] pub use core::alloc::*; +#[cfg(stage0)] extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom(err: *const u8) -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] - fn __rust_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize); - #[rustc_allocator_nounwind] fn __rust_realloc(ptr: *mut u8, old_size: usize, old_align: usize, @@ -44,31 +37,22 @@ extern "Rust" { err: *mut u8) -> *mut u8; #[rustc_allocator_nounwind] fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; +} + +#[cfg(not(stage0))] +extern "Rust" { + #[allocator] #[rustc_allocator_nounwind] - fn __rust_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; + fn __rust_alloc(size: usize, align: usize) -> *mut u8; #[rustc_allocator_nounwind] - fn __rust_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] - fn __rust_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; + fn __rust_realloc(ptr: *mut u8, + old_size: usize, + align: usize, + new_size: usize) -> *mut u8; #[rustc_allocator_nounwind] - fn __rust_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; + fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; } #[derive(Copy, Clone, Default, Debug)] @@ -86,22 +70,15 @@ pub const Heap: Global = Global; unsafe impl Alloc for Global { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = AllocErr; - let ptr = __rust_alloc(layout.size(), - layout.align(), - &mut err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(AllocErr) - } else { - Ok(ptr) - } - } + #[cfg(not(stage0))] + let ptr = __rust_alloc(layout.size(), layout.align()); + #[cfg(stage0)] + let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0); - #[inline] - #[cold] - fn oom(&mut self, err: AllocErr) -> ! { - unsafe { - __rust_oom(&err as *const AllocErr as *const u8) + if !ptr.is_null() { + Ok(ptr) + } else { + Err(AllocErr) } } @@ -110,18 +87,6 @@ unsafe impl Alloc for Global { __rust_dealloc(ptr, layout.size(), layout.align()) } - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - let mut min = 0; - let mut max = 0; - unsafe { - __rust_usable_size(layout as *const Layout as *const u8, - &mut min, - &mut max); - } - (min, max) - } - #[inline] unsafe fn realloc(&mut self, ptr: *mut u8, @@ -129,107 +94,34 @@ unsafe impl Alloc for Global { new_layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = AllocErr; - let ptr = __rust_realloc(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(AllocErr) + if layout.align() == new_layout.align() { + #[cfg(not(stage0))] + let ptr = __rust_realloc(ptr, layout.size(), layout.align(), new_layout.size()); + #[cfg(stage0)] + let ptr = __rust_realloc(ptr, layout.size(), layout.align(), + new_layout.size(), new_layout.align(), &mut 0); + + if !ptr.is_null() { + Ok(ptr) + } else { + Err(AllocErr) + } } else { - mem::forget(err); - Ok(ptr) + Err(AllocErr) } } #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = AllocErr; - let ptr = __rust_alloc_zeroed(layout.size(), - layout.align(), - &mut err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(AllocErr) - } else { - Ok(ptr) - } - } + #[cfg(not(stage0))] + let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); + #[cfg(stage0)] + let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); - #[inline] - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - let mut err = AllocErr; - let mut size = 0; - let ptr = __rust_alloc_excess(layout.size(), - layout.align(), - &mut size, - &mut err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(AllocErr) + if !ptr.is_null() { + Ok(ptr) } else { - Ok(Excess(ptr, size)) - } - } - - #[inline] - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let mut err = AllocErr; - let mut size = 0; - let ptr = __rust_realloc_excess(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut size, - &mut err as *mut AllocErr as *mut u8); - if ptr.is_null() { Err(AllocErr) - } else { - Ok(Excess(ptr, size)) - } - } - - #[inline] - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) - -> Result<(), CannotReallocInPlace> - { - debug_assert!(new_layout.size() >= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_grow_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) - } - } - - #[inline] - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - debug_assert!(new_layout.size() <= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_shrink_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) } } } diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 02435170374..7986d5dd2eb 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -12,7 +12,6 @@ test = false doc = false [dependencies] -alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 59a7e87e1ec..661d7ab78da 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,7 +14,6 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] #![feature(staged_api)] @@ -23,15 +22,12 @@ #![cfg_attr(not(dummy_jemalloc), feature(allocator_api))] #![rustc_alloc_kind = "exe"] -extern crate alloc_system; extern crate libc; #[cfg(not(dummy_jemalloc))] pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { - use core::alloc::{Alloc, AllocErr, Layout}; - use alloc_system::System; use libc::{c_int, c_void, size_t}; // Note that the symbols here are prefixed by default on macOS and Windows (we @@ -50,18 +46,10 @@ mod contents { target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_rallocx")] fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows", target_env = "musl"), - link_name = "je_xallocx")] - fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_sdallocx")] fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows", target_env = "musl"), - link_name = "je_nallocx")] - fn nallocx(size: size_t, flags: c_int) -> size_t; } const MALLOCX_ZERO: c_int = 0x40; @@ -102,20 +90,12 @@ mod contents { #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_alloc(size: usize, - align: usize, - _err: *mut u8) -> *mut u8 { + pub unsafe extern fn __rde_alloc(size: usize, align: usize) -> *mut u8 { let flags = align_to_flags(align, size); let ptr = mallocx(size as size_t, flags) as *mut u8; ptr } - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_oom(err: *const u8) -> ! { - System.oom((*(err as *const AllocErr)).clone()) - } - #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_dealloc(ptr: *mut u8, @@ -125,44 +105,20 @@ mod contents { sdallocx(ptr as *mut c_void, size, flags); } - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize) { - let layout = &*(layout as *const Layout); - let flags = align_to_flags(layout.align(), layout.size()); - let size = nallocx(layout.size(), flags) as usize; - *min = layout.size(); - if size > 0 { - *max = size; - } else { - *max = layout.size(); - } - } - #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_realloc(ptr: *mut u8, _old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - _err: *mut u8) -> *mut u8 { - if new_align != old_align { - return 0 as *mut u8 - } - - let flags = align_to_flags(new_align, new_size); + align: usize, + new_size: usize) -> *mut u8 { + let flags = align_to_flags(align, new_size); let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8; ptr } #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_alloc_zeroed(size: usize, - align: usize, - _err: *mut u8) -> *mut u8 { + pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize) -> *mut u8 { let ptr = if align <= MIN_ALIGN && align <= size { calloc(size as size_t, 1) as *mut u8 } else { @@ -171,60 +127,4 @@ mod contents { }; ptr } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let p = __rde_alloc(size, align, err); - if !p.is_null() { - let flags = align_to_flags(align, size); - *excess = nallocx(size, flags) as usize; - } - return p - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err); - if !p.is_null() { - let flags = align_to_flags(new_align, new_size); - *excess = nallocx(new_size, flags) as usize; - } - p - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8, - _old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - if old_align == new_align { - let flags = align_to_flags(new_align, new_size); - (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8 - } else { - 0 - } - } } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index ee38cca7828..ce41fe1f3bc 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -11,7 +11,7 @@ use rustc::middle::allocator::AllocatorKind; use rustc_errors; use syntax::abi::Abi; -use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind}; +use syntax::ast::{Crate, Attribute, LitKind, StrStyle}; use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg}; use syntax::ast::{self, Ident, Item, ItemKind, TyKind, VisibilityKind, Expr}; use syntax::attr; @@ -88,7 +88,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { span, kind: AllocatorKind::Global, global: item.ident, - alloc: Ident::from_str("alloc"), + core: Ident::from_str("core"), cx: ExtCtxt::new(self.sess, ecfg, self.resolver), }; let super_path = f.cx.path(f.span, vec![ @@ -96,7 +96,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { f.global, ]); let mut items = vec![ - f.cx.item_extern_crate(f.span, f.alloc), + f.cx.item_extern_crate(f.span, f.core), f.cx.item_use_simple( f.span, respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), @@ -126,7 +126,7 @@ struct AllocFnFactory<'a> { span: Span, kind: AllocatorKind, global: Ident, - alloc: Ident, + core: Ident, cx: ExtCtxt<'a>, } @@ -143,8 +143,7 @@ impl<'a> AllocFnFactory<'a> { self.arg_ty(ty, &mut abi_args, mk) }).collect(); let result = self.call_allocator(method.name, args); - let (output_ty, output_expr) = - self.ret_ty(&method.output, &mut abi_args, mk, result); + let (output_ty, output_expr) = self.ret_ty(&method.output, result); let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), Unsafety::Unsafe, dummy_spanned(Constness::NotConst), @@ -159,16 +158,15 @@ impl<'a> AllocFnFactory<'a> { fn call_allocator(&self, method: &str, mut args: Vec>) -> P { let method = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("Alloc"), + self.core, + Ident::from_str("alloc"), + Ident::from_str("GlobalAlloc"), Ident::from_str(method), ]); let method = self.cx.expr_path(method); let allocator = self.cx.path_ident(self.span, self.global); let allocator = self.cx.expr_path(allocator); let allocator = self.cx.expr_addr_of(self.span, allocator); - let allocator = self.cx.expr_mut_addr_of(self.span, allocator); args.insert(0, allocator); self.cx.expr_call(self.span, method, args) @@ -205,8 +203,8 @@ impl<'a> AllocFnFactory<'a> { args.push(self.cx.arg(self.span, align, ty_usize)); let layout_new = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), + self.core, + Ident::from_str("alloc"), Ident::from_str("Layout"), Ident::from_str("from_size_align_unchecked"), ]); @@ -219,286 +217,67 @@ impl<'a> AllocFnFactory<'a> { layout } - AllocatorTy::LayoutRef => { - let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); - - // Convert our `arg: *const u8` via: - // - // &*(arg as *const Layout) - let expr = self.cx.expr_ident(self.span, ident); - let expr = self.cx.expr_cast(self.span, expr, self.layout_ptr()); - let expr = self.cx.expr_deref(self.span, expr); - self.cx.expr_addr_of(self.span, expr) - } - - AllocatorTy::AllocErr => { - // We're creating: - // - // (*(arg as *const AllocErr)).clone() + AllocatorTy::Ptr => { let ident = ident(); args.push(self.cx.arg(self.span, ident, self.ptr_u8())); - let expr = self.cx.expr_ident(self.span, ident); - let expr = self.cx.expr_cast(self.span, expr, self.alloc_err_ptr()); - let expr = self.cx.expr_deref(self.span, expr); - self.cx.expr_method_call( - self.span, - expr, - Ident::from_str("clone"), - Vec::new() - ) + let arg = self.cx.expr_ident(self.span, ident); + self.cx.expr_cast(self.span, arg, self.ptr_void()) } - AllocatorTy::Ptr => { + AllocatorTy::Usize => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + args.push(self.cx.arg(self.span, ident, self.usize())); self.cx.expr_ident(self.span, ident) } AllocatorTy::ResultPtr | - AllocatorTy::ResultExcess | - AllocatorTy::ResultUnit | - AllocatorTy::Bang | - AllocatorTy::UsizePair | AllocatorTy::Unit => { panic!("can't convert AllocatorTy to an argument") } } } - fn ret_ty(&self, - ty: &AllocatorTy, - args: &mut Vec, - ident: &mut FnMut() -> Ident, - expr: P) -> (P, P) - { + fn ret_ty(&self, ty: &AllocatorTy, expr: P) -> (P, P) { match *ty { - AllocatorTy::UsizePair => { - // We're creating: - // - // let arg = #expr; - // *min = arg.0; - // *max = arg.1; - - let min = ident(); - let max = ident(); - - args.push(self.cx.arg(self.span, min, self.ptr_usize())); - args.push(self.cx.arg(self.span, max, self.ptr_usize())); - - let ident = ident(); - let stmt = self.cx.stmt_let(self.span, false, ident, expr); - let min = self.cx.expr_ident(self.span, min); - let max = self.cx.expr_ident(self.span, max); - let layout = self.cx.expr_ident(self.span, ident); - let assign_min = self.cx.expr(self.span, ExprKind::Assign( - self.cx.expr_deref(self.span, min), - self.cx.expr_tup_field_access(self.span, layout.clone(), 0), - )); - let assign_min = self.cx.stmt_semi(assign_min); - let assign_max = self.cx.expr(self.span, ExprKind::Assign( - self.cx.expr_deref(self.span, max), - self.cx.expr_tup_field_access(self.span, layout.clone(), 1), - )); - let assign_max = self.cx.stmt_semi(assign_max); - - let stmts = vec![stmt, assign_min, assign_max]; - let block = self.cx.block(self.span, stmts); - let ty_unit = self.cx.ty(self.span, TyKind::Tup(Vec::new())); - (ty_unit, self.cx.expr_block(block)) - } - - AllocatorTy::ResultExcess => { - // We're creating: - // - // match #expr { - // Ok(ptr) => { - // *excess = ptr.1; - // ptr.0 - // } - // Err(e) => { - // ptr::write(err_ptr, e); - // 0 as *mut u8 - // } - // } - - let excess_ptr = ident(); - args.push(self.cx.arg(self.span, excess_ptr, self.ptr_usize())); - let excess_ptr = self.cx.expr_ident(self.span, excess_ptr); - - let err_ptr = ident(); - args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8())); - let err_ptr = self.cx.expr_ident(self.span, err_ptr); - let err_ptr = self.cx.expr_cast(self.span, - err_ptr, - self.alloc_err_ptr()); - - let name = ident(); - let ok_expr = { - let ptr = self.cx.expr_ident(self.span, name); - let write = self.cx.expr(self.span, ExprKind::Assign( - self.cx.expr_deref(self.span, excess_ptr), - self.cx.expr_tup_field_access(self.span, ptr.clone(), 1), - )); - let write = self.cx.stmt_semi(write); - let ret = self.cx.expr_tup_field_access(self.span, - ptr.clone(), - 0); - let ret = self.cx.stmt_expr(ret); - let block = self.cx.block(self.span, vec![write, ret]); - self.cx.expr_block(block) - }; - let pat = self.cx.pat_ident(self.span, name); - let ok = self.cx.path_ident(self.span, Ident::from_str("Ok")); - let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]); - let ok = self.cx.arm(self.span, vec![ok], ok_expr); - - let name = ident(); - let err_expr = { - let err = self.cx.expr_ident(self.span, name); - let write = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("__core"), - Ident::from_str("ptr"), - Ident::from_str("write"), - ]); - let write = self.cx.expr_path(write); - let write = self.cx.expr_call(self.span, write, - vec![err_ptr, err]); - let write = self.cx.stmt_semi(write); - let null = self.cx.expr_usize(self.span, 0); - let null = self.cx.expr_cast(self.span, null, self.ptr_u8()); - let null = self.cx.stmt_expr(null); - let block = self.cx.block(self.span, vec![write, null]); - self.cx.expr_block(block) - }; - let pat = self.cx.pat_ident(self.span, name); - let err = self.cx.path_ident(self.span, Ident::from_str("Err")); - let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]); - let err = self.cx.arm(self.span, vec![err], err_expr); - - let expr = self.cx.expr_match(self.span, expr, vec![ok, err]); - (self.ptr_u8(), expr) - } - AllocatorTy::ResultPtr => { // We're creating: // - // match #expr { - // Ok(ptr) => ptr, - // Err(e) => { - // ptr::write(err_ptr, e); - // 0 as *mut u8 - // } - // } - - let err_ptr = ident(); - args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8())); - let err_ptr = self.cx.expr_ident(self.span, err_ptr); - let err_ptr = self.cx.expr_cast(self.span, - err_ptr, - self.alloc_err_ptr()); + // #expr as *mut u8 - let name = ident(); - let ok_expr = self.cx.expr_ident(self.span, name); - let pat = self.cx.pat_ident(self.span, name); - let ok = self.cx.path_ident(self.span, Ident::from_str("Ok")); - let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]); - let ok = self.cx.arm(self.span, vec![ok], ok_expr); - - let name = ident(); - let err_expr = { - let err = self.cx.expr_ident(self.span, name); - let write = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("__core"), - Ident::from_str("ptr"), - Ident::from_str("write"), - ]); - let write = self.cx.expr_path(write); - let write = self.cx.expr_call(self.span, write, - vec![err_ptr, err]); - let write = self.cx.stmt_semi(write); - let null = self.cx.expr_usize(self.span, 0); - let null = self.cx.expr_cast(self.span, null, self.ptr_u8()); - let null = self.cx.stmt_expr(null); - let block = self.cx.block(self.span, vec![write, null]); - self.cx.expr_block(block) - }; - let pat = self.cx.pat_ident(self.span, name); - let err = self.cx.path_ident(self.span, Ident::from_str("Err")); - let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]); - let err = self.cx.arm(self.span, vec![err], err_expr); - - let expr = self.cx.expr_match(self.span, expr, vec![ok, err]); + let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8()); (self.ptr_u8(), expr) } - AllocatorTy::ResultUnit => { - // We're creating: - // - // #expr.is_ok() as u8 - - let cast = self.cx.expr_method_call( - self.span, - expr, - Ident::from_str("is_ok"), - Vec::new() - ); - let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); - let u8 = self.cx.ty_path(u8); - let cast = self.cx.expr_cast(self.span, cast, u8.clone()); - (u8, cast) - } - - AllocatorTy::Bang => { - (self.cx.ty(self.span, TyKind::Never), expr) - } - AllocatorTy::Unit => { (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr) } - AllocatorTy::AllocErr | AllocatorTy::Layout | - AllocatorTy::LayoutRef | + AllocatorTy::Usize | AllocatorTy::Ptr => { panic!("can't convert AllocatorTy to an output") } } } + fn usize(&self) -> P { + let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + self.cx.ty_path(usize) + } + fn ptr_u8(&self) -> P { let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } - fn ptr_usize(&self) -> P { - let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); - let ty_usize = self.cx.ty_path(usize); - self.cx.ty_ptr(self.span, ty_usize, Mutability::Mutable) - } - - fn layout_ptr(&self) -> P { - let layout = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("Layout"), - ]); - let layout = self.cx.ty_path(layout); - self.cx.ty_ptr(self.span, layout, Mutability::Mutable) - } - - fn alloc_err_ptr(&self) -> P { - let err = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("AllocErr"), + fn ptr_void(&self) -> P { + let void = self.cx.path(self.span, vec![ + self.core, + Ident::from_str("alloc"), + Ident::from_str("Void"), ]); - let err = self.cx.ty_path(err); - self.cx.ty_ptr(self.span, err, Mutability::Mutable) + let ty_void = self.cx.ty_path(void); + self.cx.ty_ptr(self.span, ty_void, Mutability::Mutable) } } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 0c7a9a91711..969086815de 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -23,24 +23,14 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, - AllocatorMethod { - name: "oom", - inputs: &[AllocatorTy::AllocErr], - output: AllocatorTy::Bang, - }, AllocatorMethod { name: "dealloc", inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], output: AllocatorTy::Unit, }, - AllocatorMethod { - name: "usable_size", - inputs: &[AllocatorTy::LayoutRef], - output: AllocatorTy::UsizePair, - }, AllocatorMethod { name: "realloc", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize], output: AllocatorTy::ResultPtr, }, AllocatorMethod { @@ -48,26 +38,6 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, - AllocatorMethod { - name: "alloc_excess", - inputs: &[AllocatorTy::Layout], - output: AllocatorTy::ResultExcess, - }, - AllocatorMethod { - name: "realloc_excess", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], - output: AllocatorTy::ResultExcess, - }, - AllocatorMethod { - name: "grow_in_place", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], - output: AllocatorTy::ResultUnit, - }, - AllocatorMethod { - name: "shrink_in_place", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], - output: AllocatorTy::ResultUnit, - }, ]; pub struct AllocatorMethod { @@ -77,14 +47,9 @@ pub struct AllocatorMethod { } pub enum AllocatorTy { - AllocErr, - Bang, Layout, - LayoutRef, Ptr, - ResultExcess, ResultPtr, - ResultUnit, Unit, - UsizePair, + Usize, } diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs index e1c145b122d..ffebb959ebf 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_trans/allocator.rs @@ -30,7 +30,6 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) }; let i8 = llvm::LLVMInt8TypeInContext(llcx); let i8p = llvm::LLVMPointerType(i8, 0); - let usizep = llvm::LLVMPointerType(usize, 0); let void = llvm::LLVMVoidTypeInContext(llcx); for method in ALLOCATOR_METHODS { @@ -41,40 +40,19 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) args.push(usize); // size args.push(usize); // align } - AllocatorTy::LayoutRef => args.push(i8p), AllocatorTy::Ptr => args.push(i8p), - AllocatorTy::AllocErr => args.push(i8p), + AllocatorTy::Usize => args.push(usize), - AllocatorTy::Bang | - AllocatorTy::ResultExcess | AllocatorTy::ResultPtr | - AllocatorTy::ResultUnit | - AllocatorTy::UsizePair | AllocatorTy::Unit => panic!("invalid allocator arg"), } } let output = match method.output { - AllocatorTy::UsizePair => { - args.push(usizep); // min - args.push(usizep); // max - None - } - AllocatorTy::Bang => None, - AllocatorTy::ResultExcess => { - args.push(i8p); // excess_ptr - args.push(i8p); // err_ptr - Some(i8p) - } - AllocatorTy::ResultPtr => { - args.push(i8p); // err_ptr - Some(i8p) - } - AllocatorTy::ResultUnit => Some(i8), + AllocatorTy::ResultPtr => Some(i8p), AllocatorTy::Unit => None, - AllocatorTy::AllocErr | AllocatorTy::Layout | - AllocatorTy::LayoutRef | + AllocatorTy::Usize | AllocatorTy::Ptr => panic!("invalid allocator output"), }; let ty = llvm::LLVMFunctionType(output.unwrap_or(void), diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 533ad3ad473..335dc7e0412 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -21,7 +21,7 @@ #[doc(hidden)] #[allow(unused_attributes)] pub mod __default_lib_allocator { - use super::{System, Layout, Alloc, AllocErr, CannotReallocInPlace}; + use super::{System, Layout, GlobalAlloc, Void}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -30,20 +30,9 @@ pub mod __default_lib_allocator { #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc(size: usize, - align: usize, - _err: *mut u8) -> *mut u8 { + pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc(layout) { - Ok(p) => p, - Err(AllocErr) => 0 as *mut u8, - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { - System.oom((*(err as *const AllocErr)).clone()) + System.alloc(layout) as *mut u8 } #[no_mangle] @@ -51,110 +40,76 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { - System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize) { - let pair = System.usable_size(&*(layout as *const Layout)); - *min = pair.0; - *max = pair.1; + System.dealloc(ptr as *mut Void, Layout::from_size_align_unchecked(size, align)) } #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_realloc(ptr: *mut u8, old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - _err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc(ptr, old_layout, new_layout) { - Ok(p) => p, - Err(AllocErr) => 0 as *mut u8, - } + align: usize, + new_size: usize) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, align); + System.realloc(ptr as *mut Void, old_layout, new_size) as *mut u8 } #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_zeroed(size: usize, - align: usize, - _err: *mut u8) -> *mut u8 { + pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_zeroed(layout) { - Ok(p) => p, - Err(AllocErr) => 0 as *mut u8, - } + System.alloc_zeroed(layout) as *mut u8 } - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - _err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_excess(layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(AllocErr) => 0 as *mut u8, + #[cfg(stage0)] + pub mod stage0 { + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_usable_size(_layout: *const u8, + _min: *mut usize, + _max: *mut usize) { + unimplemented!() } - } - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - _err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc_excess(ptr, old_layout, new_layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(AllocErr) => 0 as *mut u8, + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_excess(_size: usize, + _align: usize, + _excess: *mut usize, + _err: *mut u8) -> *mut u8 { + unimplemented!() } - } - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.grow_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(CannotReallocInPlace) => 0, + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize, + _excess: *mut usize, + _err: *mut u8) -> *mut u8 { + unimplemented!() } - } - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.shrink_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(CannotReallocInPlace) => 0, + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize) -> u8 { + unimplemented!() } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize) -> u8 { + unimplemented!() + } + } } diff --git a/src/llvm b/src/llvm index 6ceaaa4b017..7243155b1c3 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 6ceaaa4b0176a200e4bbd347d6a991ab6c776ede +Subproject commit 7243155b1c3da0a980c868a87adebf00e0b33989 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index c4c0f1ab6e6..c3fc3e5452c 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2018-03-10 +2018-04-05 diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs index e4301435063..140cad22f34 100644 --- a/src/test/compile-fail/allocator/not-an-allocator.rs +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -12,15 +12,9 @@ #[global_allocator] static A: usize = 0; -//~^ the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: +//~^ the trait bound `usize: +//~| the trait bound `usize: +//~| the trait bound `usize: +//~| the trait bound `usize: fn main() {} diff --git a/src/test/run-make-fulldeps/std-core-cycle/bar.rs b/src/test/run-make-fulldeps/std-core-cycle/bar.rs index 6def5b6f5e1..20b87028fd1 100644 --- a/src/test/run-make-fulldeps/std-core-cycle/bar.rs +++ b/src/test/run-make-fulldeps/std-core-cycle/bar.rs @@ -11,16 +11,16 @@ #![feature(allocator_api)] #![crate_type = "rlib"] -use std::heap::*; +use std::alloc::*; pub struct A; -unsafe impl<'a> Alloc for &'a A { - unsafe fn alloc(&mut self, _: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl GlobalAlloc for A { + unsafe fn alloc(&self, _: Layout) -> *mut Void { loop {} } - unsafe fn dealloc(&mut self, _ptr: *mut u8, _: Layout) { + unsafe fn dealloc(&self, _ptr: *mut Void, _: Layout) { loop {} } } diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs index 8f4fbcd5ab1..95096efc7ef 100644 --- a/src/test/run-pass/allocator/auxiliary/custom.rs +++ b/src/test/run-pass/allocator/auxiliary/custom.rs @@ -13,18 +13,18 @@ #![feature(heap_api, allocator_api)] #![crate_type = "rlib"] -use std::heap::{Alloc, System, AllocErr, Layout}; +use std::heap::{GlobalAlloc, System, Layout, Void}; use std::sync::atomic::{AtomicUsize, Ordering}; pub struct A(pub AtomicUsize); -unsafe impl<'a> Alloc for &'a A { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl GlobalAlloc for A { + unsafe fn alloc(&self, layout: Layout) -> *mut Void { self.0.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { self.0.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index 22081678fb9..f7b2fd73c87 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -15,20 +15,20 @@ extern crate helper; -use std::heap::{Heap, Alloc, System, Layout, AllocErr}; +use std::alloc::{self, Global, Alloc, System, Layout, Void}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; static HITS: AtomicUsize = ATOMIC_USIZE_INIT; struct A; -unsafe impl<'a> Alloc for &'a A { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl alloc::GlobalAlloc for A { + unsafe fn alloc(&self, layout: Layout) -> *mut Void { HITS.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } @@ -45,10 +45,10 @@ fn main() { unsafe { let layout = Layout::from_size_align(4, 2).unwrap(); - let ptr = Heap.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()).unwrap(); helper::work_with(&ptr); assert_eq!(HITS.load(Ordering::SeqCst), n + 1); - Heap.dealloc(ptr, layout.clone()); + Global.dealloc(ptr, layout.clone()); assert_eq!(HITS.load(Ordering::SeqCst), n + 2); let s = String::with_capacity(10); diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs index 04d2ef466e7..78d604a7108 100644 --- a/src/test/run-pass/allocator/xcrate-use.rs +++ b/src/test/run-pass/allocator/xcrate-use.rs @@ -17,7 +17,7 @@ extern crate custom; extern crate helper; -use std::heap::{Heap, Alloc, System, Layout}; +use std::alloc::{Global, Alloc, System, Layout}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; #[global_allocator] @@ -28,10 +28,10 @@ fn main() { let n = GLOBAL.0.load(Ordering::SeqCst); let layout = Layout::from_size_align(4, 2).unwrap(); - let ptr = Heap.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()).unwrap(); helper::work_with(&ptr); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); - Heap.dealloc(ptr, layout.clone()); + Global.dealloc(ptr, layout.clone()); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); let ptr = System.alloc(layout.clone()).unwrap(); diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs index 155fb5d6c5d..52eb963efdb 100644 --- a/src/test/run-pass/allocator/xcrate-use2.rs +++ b/src/test/run-pass/allocator/xcrate-use2.rs @@ -19,7 +19,7 @@ extern crate custom; extern crate custom_as_global; extern crate helper; -use std::heap::{Heap, Alloc, System, Layout}; +use std::alloc::{Global, Alloc, GlobalAlloc, System, Layout}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT); @@ -30,25 +30,25 @@ fn main() { let layout = Layout::from_size_align(4, 2).unwrap(); // Global allocator routes to the `custom_as_global` global - let ptr = Heap.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()).unwrap(); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 1); - Heap.dealloc(ptr, layout.clone()); + Global.dealloc(ptr, layout.clone()); assert_eq!(custom_as_global::get(), n + 2); // Usage of the system allocator avoids all globals - let ptr = System.alloc(layout.clone()).unwrap(); + let ptr = System.alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 2); System.dealloc(ptr, layout.clone()); assert_eq!(custom_as_global::get(), n + 2); // Usage of our personal allocator doesn't affect other instances - let ptr = (&GLOBAL).alloc(layout.clone()).unwrap(); + let ptr = GLOBAL.alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 2); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1); - (&GLOBAL).dealloc(ptr, layout); + GLOBAL.dealloc(ptr, layout); assert_eq!(custom_as_global::get(), n + 2); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2); } -- cgit 1.4.1-3-g733a5 From 157ff8cd0562eefdd7aa296395c38a7bc259a4b9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 16:00:04 +0200 Subject: Remove the now-unit-struct AllocErr parameter of oom() --- src/liballoc/alloc.rs | 6 +++--- src/liballoc/arc.rs | 2 +- src/liballoc/heap.rs | 4 ++-- src/liballoc/raw_vec.rs | 12 ++++++------ src/liballoc/rc.rs | 2 +- src/liballoc_system/lib.rs | 12 ++++++------ src/libcore/alloc.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- src/libstd/collections/hash/table.rs | 4 ++-- src/test/run-pass/allocator-alloc-one.rs | 4 ++-- src/test/run-pass/realloc-16687.rs | 4 ++-- src/test/run-pass/regions-mock-trans.rs | 2 +- 12 files changed, 28 insertions(+), 28 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 73bc78eb8a2..a7b5864016c 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -136,8 +136,8 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { align as *mut u8 } else { let layout = Layout::from_size_align_unchecked(size, align); - Global.alloc(layout).unwrap_or_else(|err| { - Global.oom(err) + Global.alloc(layout).unwrap_or_else(|_| { + Global.oom() }) } } @@ -166,7 +166,7 @@ mod tests { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|e| Global.oom(e)); + .unwrap_or_else(|_| Global.oom()); let end = ptr.offset(layout.size() as isize); let mut i = ptr; diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index d63ed24aa4f..f0a325530ba 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -555,7 +555,7 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|e| Global.oom(e)); + .unwrap_or_else(|_| Global.oom()); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem) as *mut ArcInner; diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index a44ff04bd1b..765fb8458d1 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -52,8 +52,8 @@ unsafe impl Alloc for T where T: CoreAlloc { CoreAlloc::dealloc(self, ptr, layout) } - fn oom(&mut self, err: AllocErr) -> ! { - CoreAlloc::oom(self, err) + fn oom(&mut self, _: AllocErr) -> ! { + CoreAlloc::oom(self) } fn usable_size(&self, layout: &Layout) -> (usize, usize) { diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index caedb971ddc..25d759764a5 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -100,7 +100,7 @@ impl RawVec { }; match result { Ok(ptr) => ptr, - Err(err) => a.oom(err), + Err(_) => a.oom(), } }; @@ -316,7 +316,7 @@ impl RawVec { new_layout); match ptr_res { Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)), - Err(e) => self.a.oom(e), + Err(_) => self.a.oom(), } } None => { @@ -325,7 +325,7 @@ impl RawVec { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(e) => self.a.oom(e), + Err(_) => self.a.oom(), } } }; @@ -444,7 +444,7 @@ impl RawVec { pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(e)) => self.a.oom(e), + Err(AllocErr(_)) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -554,7 +554,7 @@ impl RawVec { pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(e)) => self.a.oom(e), + Err(AllocErr(_)) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -669,7 +669,7 @@ impl RawVec { old_layout, new_layout) { Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T), - Err(err) => self.a.oom(err), + Err(_) => self.a.oom(), } } self.cap = amount; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c134b181158..3c0b11bfe74 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -668,7 +668,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|e| Global.oom(e)); + .unwrap_or_else(|_| Global.oom()); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem) as *mut RcBox; diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 0480be8d913..5e6b3b5ca11 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -73,8 +73,8 @@ unsafe impl Alloc for System { Alloc::realloc(&mut &*self, ptr, old_layout, new_layout) } - fn oom(&mut self, err: AllocErr) -> ! { - Alloc::oom(&mut &*self, err) + fn oom(&mut self) -> ! { + Alloc::oom(&mut &*self) } #[inline] @@ -242,7 +242,7 @@ mod platform { unsafe impl<'a> Alloc for &'a System { alloc_methods_based_on_global_alloc!(); - fn oom(&mut self, err: AllocErr) -> ! { + fn oom(&mut self) -> ! { use core::fmt::{self, Write}; // Print a message to stderr before aborting to assist with @@ -250,7 +250,7 @@ mod platform { // memory since we are in an OOM situation. Any errors are ignored // while printing since there's nothing we can do about them and we // are about to exit anyways. - drop(writeln!(Stderr, "fatal runtime error: {}", err)); + drop(writeln!(Stderr, "fatal runtime error: {}", AllocErr)); unsafe { ::core::intrinsics::abort(); } @@ -459,11 +459,11 @@ mod platform { } } - fn oom(&mut self, err: AllocErr) -> ! { + fn oom(&mut self) -> ! { use core::fmt::{self, Write}; // Same as with unix we ignore all errors here - drop(writeln!(Stderr, "fatal runtime error: {}", err)); + drop(writeln!(Stderr, "fatal runtime error: {}", AllocErr)); unsafe { ::core::intrinsics::abort(); } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 1c764dab000..1ba4c641065 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -572,7 +572,7 @@ pub unsafe trait Alloc { /// instead they should return an appropriate error from the /// invoked method, and let the client decide whether to invoke /// this `oom` method in response. - fn oom(&mut self, _: AllocErr) -> ! { + fn oom(&mut self) -> ! { unsafe { ::intrinsics::abort() } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c4ef9e62577..2a00241afc6 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -784,7 +784,7 @@ impl HashMap pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), + Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), Ok(()) => { /* yay */ } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 10bab5df8b5..fcc2eb8fef2 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -772,7 +772,7 @@ impl RawTable { unsafe fn new_uninitialized(capacity: usize) -> RawTable { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), + Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), Ok(table) => { table } } } @@ -811,7 +811,7 @@ impl RawTable { pub fn new(capacity: usize) -> RawTable { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Global.oom(e), + Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), Ok(table) => { table } } } diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index eaa5bc90805..38b8ab50cc7 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -14,8 +14,8 @@ use std::heap::{Heap, Alloc}; fn main() { unsafe { - let ptr = Heap.alloc_one::().unwrap_or_else(|e| { - Heap.oom(e) + let ptr = Heap.alloc_one::().unwrap_or_else(|_| { + Heap.oom() }); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index eddcd5a584a..a562165d21b 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Heap.alloc(layout.clone()).unwrap_or_else(|e| Heap.oom(e)); + let ret = Heap.alloc(layout.clone()).unwrap_or_else(|_| Heap.oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -73,7 +73,7 @@ unsafe fn test_triangle() -> bool { } let ret = Heap.realloc(ptr, old.clone(), new.clone()) - .unwrap_or_else(|e| Heap.oom(e)); + .unwrap_or_else(|_| Heap.oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 8f278a315d1..7d34b8fd00f 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -32,7 +32,7 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Heap.alloc(Layout::new::()) - .unwrap_or_else(|e| Heap.oom(e)); + .unwrap_or_else(|_| Heap.oom()); &*(ptr as *const _) } } -- cgit 1.4.1-3-g733a5 From 93a9ad4897e560ccd5ebc3397afb7d83d990ef42 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 3 Apr 2018 16:01:29 +0200 Subject: Remove the now-unit-struct AllocErr field inside CollectionAllocErr --- src/liballoc/raw_vec.rs | 4 ++-- src/liballoc/tests/string.rs | 12 ++++++------ src/liballoc/tests/vec.rs | 16 ++++++++-------- src/liballoc/tests/vec_deque.rs | 12 ++++++------ src/libcore/alloc.rs | 6 +++--- src/libstd/collections/hash/map.rs | 4 ++-- src/libstd/collections/hash/table.rs | 4 ++-- 7 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 25d759764a5..d7c30925f1a 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -444,7 +444,7 @@ impl RawVec { pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(_)) => self.a.oom(), + Err(AllocErr) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -554,7 +554,7 @@ impl RawVec { pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(_)) => self.a.oom(), + Err(AllocErr) => self.a.oom(), Ok(()) => { /* yay */ } } } diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 17d53e4cf3e..befb36baeef 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -575,11 +575,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_CAP + 1) { + if let Err(AllocErr) = empty_string.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_USIZE) { + if let Err(AllocErr) = empty_string.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -599,7 +599,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -637,10 +637,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_USIZE) { + if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -659,7 +659,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 2895c53009d..e329b45a617 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1016,11 +1016,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP + 1) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1040,7 +1040,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1063,7 +1063,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1103,10 +1103,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1125,7 +1125,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1146,7 +1146,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 75d3f01f8b6..4d55584e2f4 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1073,7 +1073,7 @@ fn test_try_reserve() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1093,7 +1093,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1116,7 +1116,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1160,7 +1160,7 @@ fn test_try_reserve_exact() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1179,7 +1179,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1200,7 +1200,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 1ba4c641065..23532c61721 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -356,13 +356,13 @@ pub enum CollectionAllocErr { /// (usually `isize::MAX` bytes). CapacityOverflow, /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr(AllocErr), + AllocErr, } #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] impl From for CollectionAllocErr { - fn from(err: AllocErr) -> Self { - CollectionAllocErr::AllocErr(err) + fn from(AllocErr: AllocErr) -> Self { + CollectionAllocErr::AllocErr } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2a00241afc6..20a4f9b508d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -784,7 +784,7 @@ impl HashMap pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(()) => { /* yay */ } } } @@ -3634,7 +3634,7 @@ mod test_map { if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } } else { - if let Err(AllocErr(_)) = empty_bytes.try_reserve(max_no_ovf) { + if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index fcc2eb8fef2..e9bdd4e7d07 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -772,7 +772,7 @@ impl RawTable { unsafe fn new_uninitialized(capacity: usize) -> RawTable { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(table) => { table } } } @@ -811,7 +811,7 @@ impl RawTable { pub fn new(capacity: usize) -> RawTable { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(_)) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(table) => { table } } } -- cgit 1.4.1-3-g733a5 From b017742136a5d02b6ba0f2080e97d18a8bfeba4b Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 4 Apr 2018 16:03:46 +0200 Subject: Return Result instead of Option in alloc::Layout constructors --- src/liballoc/raw_vec.rs | 4 +-- src/libcore/alloc.rs | 63 +++++++++++++++++++++++------------- src/libstd/collections/hash/table.rs | 2 +- src/libstd/error.rs | 11 ++++++- 4 files changed, 54 insertions(+), 26 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d7c30925f1a..18aaf1de08e 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -422,7 +422,7 @@ impl RawVec { // Nothing we can really do about these checks :( let new_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?; - let new_layout = Layout::array::(new_cap).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; alloc_guard(new_layout.size())?; @@ -530,7 +530,7 @@ impl RawVec { } let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; - let new_layout = Layout::array::(new_cap).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size())?; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 23532c61721..0acaf54e0d9 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -94,9 +94,9 @@ impl Layout { /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). #[inline] - pub fn from_size_align(size: usize, align: usize) -> Option { + pub fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { - return None; + return Err(LayoutErr { private: () }); } // (power-of-two implies align != 0.) @@ -114,11 +114,11 @@ impl Layout { // Above implies that checking for summation overflow is both // necessary and sufficient. if size > usize::MAX - (align - 1) { - return None; + return Err(LayoutErr { private: () }); } unsafe { - Some(Layout::from_size_align_unchecked(size, align)) + Ok(Layout::from_size_align_unchecked(size, align)) } } @@ -130,7 +130,7 @@ impl Layout { /// a power-of-two nor `size` aligned to `align` fits within the /// address space (i.e. the `Layout::from_size_align` preconditions). #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size: size, align: align } } @@ -229,15 +229,17 @@ impl Layout { /// /// On arithmetic overflow, returns `None`. #[inline] - pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; - let alloc_size = padded_size.checked_mul(n)?; + pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align)) + .ok_or(LayoutErr { private: () })?; + let alloc_size = padded_size.checked_mul(n) + .ok_or(LayoutErr { private: () })?; // We can assume that `self.align` is a power-of-two. // Furthermore, `alloc_size` has already been rounded up // to a multiple of `self.align`; therefore, the call to // `Layout::from_size_align` below should never panic. - Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + Ok((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) } /// Creates a layout describing the record for `self` followed by @@ -251,17 +253,19 @@ impl Layout { /// (assuming that the record itself starts at offset 0). /// /// On arithmetic overflow, returns `None`. - pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_align = cmp::max(self.align, next.align); let realigned = Layout::from_size_align(self.size, new_align)?; let pad = realigned.padding_needed_for(next.align); - let offset = self.size.checked_add(pad)?; - let new_size = offset.checked_add(next.size)?; + let offset = self.size.checked_add(pad) + .ok_or(LayoutErr { private: () })?; + let new_size = offset.checked_add(next.size) + .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, new_align)?; - Some((layout, offset)) + Ok((layout, offset)) } /// Creates a layout describing the record for `n` instances of @@ -276,8 +280,8 @@ impl Layout { /// aligned. /// /// On arithmetic overflow, returns `None`. - pub fn repeat_packed(&self, n: usize) -> Option { - let size = self.size().checked_mul(n)?; + pub fn repeat_packed(&self, n: usize) -> Result { + let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; Layout::from_size_align(size, self.align) } @@ -296,16 +300,17 @@ impl Layout { /// `extend`.) /// /// On arithmetic overflow, returns `None`. - pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { - let new_size = self.size().checked_add(next.size())?; + pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { + let new_size = self.size().checked_add(next.size()) + .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, self.align)?; - Some((layout, self.size())) + Ok((layout, self.size())) } /// Creates a layout describing the record for a `[T; n]`. /// /// On arithmetic overflow, returns `None`. - pub fn array(n: usize) -> Option { + pub fn array(n: usize) -> Result { Layout::new::() .repeat(n) .map(|(k, offs)| { @@ -315,6 +320,20 @@ impl Layout { } } +/// The parameters given to `Layout::from_size_align` do not satisfy +/// its documented constraints. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LayoutErr { + private: () +} + +// (we need this for downstream impl of trait Error) +impl fmt::Display for LayoutErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("invalid parameters to Layout::from_size_align") + } +} + /// The `AllocErr` error specifies whether an allocation failure is /// specifically due to resource exhaustion or if it is due to /// something wrong when combining the given input arguments with this @@ -990,7 +1009,7 @@ pub unsafe trait Alloc { where Self: Sized { match Layout::array::(n) { - Some(ref layout) if layout.size() > 0 => { + Ok(ref layout) if layout.size() > 0 => { unsafe { self.alloc(layout.clone()) .map(|p| { @@ -1041,7 +1060,7 @@ pub unsafe trait Alloc { where Self: Sized { match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + (Ok(ref k_old), Ok(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) .map(|p| NonNull::new_unchecked(p as *mut T)) } @@ -1076,7 +1095,7 @@ pub unsafe trait Alloc { { let raw_ptr = ptr.as_ptr() as *mut u8; match Layout::array::(n) { - Some(ref k) if k.size() > 0 => { + Ok(ref k) if k.size() > 0 => { Ok(self.dealloc(raw_ptr, k.clone())) } _ => { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index e9bdd4e7d07..50263705143 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -755,7 +755,7 @@ impl RawTable { } let buffer = Global.alloc(Layout::from_size_align(size, alignment) - .ok_or(CollectionAllocErr::CapacityOverflow)?)?; + .map_err(|_| CollectionAllocErr::CapacityOverflow)?)?; let hashes = buffer as *mut HashUint; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index ec55a3c021a..3c209928d43 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -57,7 +57,7 @@ use cell; use char; use core::array; use fmt::{self, Debug, Display}; -use heap::{AllocErr, CannotReallocInPlace}; +use heap::{AllocErr, LayoutErr, CannotReallocInPlace}; use mem::transmute; use num; use str; @@ -247,6 +247,15 @@ impl Error for AllocErr { } } +#[unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838")] +impl Error for LayoutErr { + fn description(&self) -> &str { + "invalid parameters to Layout::from_size_align" + } +} + #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -- cgit 1.4.1-3-g733a5 From eae0d468932660ca383e35bb9d8b0cb4943a82ae Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 4 Apr 2018 18:57:48 +0200 Subject: Restore Global.oom() functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … now that #[global_allocator] does not define a symbol for it --- src/Cargo.lock | 1 + src/liballoc/alloc.rs | 16 ++++++++++++++++ src/liballoc/lib.rs | 1 + src/liballoc_jemalloc/Cargo.toml | 1 + src/liballoc_jemalloc/lib.rs | 10 ++++++++++ src/liballoc_system/lib.rs | 4 ++++ src/libcore/alloc.rs | 4 ++++ src/librustc_allocator/expand.rs | 5 +++++ src/librustc_allocator/lib.rs | 6 ++++++ src/librustc_trans/allocator.rs | 2 ++ src/libstd/alloc.rs | 6 ++++++ src/test/compile-fail/allocator/not-an-allocator.rs | 1 + 12 files changed, 57 insertions(+) (limited to 'src/libstd') diff --git a/src/Cargo.lock b/src/Cargo.lock index 2e969f4ec2b..e5297d1482e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ + "alloc_system 0.0.0", "build_helper 0.1.0", "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index a6fc8d5004c..beae52726a6 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -26,6 +26,9 @@ extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom(err: *const u8) -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] @@ -44,6 +47,9 @@ extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom() -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] @@ -120,6 +126,16 @@ unsafe impl Alloc for Global { Err(AllocErr) } } + + #[inline] + fn oom(&mut self) -> ! { + unsafe { + #[cfg(not(stage0))] + __rust_oom(); + #[cfg(stage0)] + __rust_oom(&mut 0); + } + } } /// The allocator for unique pointers. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f6598fe5e89..a10820ebefd 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,6 +97,7 @@ #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] +#![feature(libc)] #![feature(needs_allocator)] #![feature(nonzero)] #![feature(optin_builtin_traits)] diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 7986d5dd2eb..02435170374 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -12,6 +12,7 @@ test = false doc = false [dependencies] +alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 661d7ab78da..2b66c293f21 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,6 +14,7 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] +#![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] #![feature(staged_api)] @@ -22,12 +23,15 @@ #![cfg_attr(not(dummy_jemalloc), feature(allocator_api))] #![rustc_alloc_kind = "exe"] +extern crate alloc_system; extern crate libc; #[cfg(not(dummy_jemalloc))] pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { + use core::alloc::GlobalAlloc; + use alloc_system::System; use libc::{c_int, c_void, size_t}; // Note that the symbols here are prefixed by default on macOS and Windows (we @@ -96,6 +100,12 @@ mod contents { ptr } + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rde_oom() -> ! { + System.oom() + } + #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_dealloc(ptr: *mut u8, diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 4516664e97c..c6507282b24 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -367,6 +367,7 @@ mod platform { } } +#[inline] fn oom() -> ! { write_to_stderr("fatal runtime error: memory allocation failed"); unsafe { @@ -375,6 +376,7 @@ fn oom() -> ! { } #[cfg(any(unix, target_os = "redox"))] +#[inline] fn write_to_stderr(s: &str) { extern crate libc; @@ -386,6 +388,7 @@ fn write_to_stderr(s: &str) { } #[cfg(windows)] +#[inline] fn write_to_stderr(s: &str) { use core::ptr; @@ -421,4 +424,5 @@ fn write_to_stderr(s: &str) { } #[cfg(not(any(windows, unix, target_os = "redox")))] +#[inline] fn write_to_stderr(_: &str) {} diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index cfa7df06a40..7334f986f2b 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -438,6 +438,10 @@ pub unsafe trait GlobalAlloc { } new_ptr } + + fn oom(&self) -> ! { + unsafe { ::intrinsics::abort() } + } } /// An implementation of `Alloc` can allocate, reallocate, and diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index ce41fe1f3bc..58d4c7f289c 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -231,6 +231,7 @@ impl<'a> AllocFnFactory<'a> { } AllocatorTy::ResultPtr | + AllocatorTy::Bang | AllocatorTy::Unit => { panic!("can't convert AllocatorTy to an argument") } @@ -248,6 +249,10 @@ impl<'a> AllocFnFactory<'a> { (self.ptr_u8(), expr) } + AllocatorTy::Bang => { + (self.cx.ty(self.span, TyKind::Never), expr) + } + AllocatorTy::Unit => { (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr) } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 969086815de..706eab72d44 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -23,6 +23,11 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, + AllocatorMethod { + name: "oom", + inputs: &[], + output: AllocatorTy::Bang, + }, AllocatorMethod { name: "dealloc", inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], @@ -47,6 +52,7 @@ pub struct AllocatorMethod { } pub enum AllocatorTy { + Bang, Layout, Ptr, ResultPtr, diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs index ffebb959ebf..f2dd2ed8460 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_trans/allocator.rs @@ -43,11 +43,13 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) AllocatorTy::Ptr => args.push(i8p), AllocatorTy::Usize => args.push(usize), + AllocatorTy::Bang | AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), } } let output = match method.output { + AllocatorTy::Bang => None, AllocatorTy::ResultPtr => Some(i8p), AllocatorTy::Unit => None, diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 335dc7e0412..4e728df010a 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -35,6 +35,12 @@ pub mod __default_lib_allocator { System.alloc(layout) as *mut u8 } + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_oom() -> ! { + System.oom() + } + #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs index 140cad22f34..1479d0b6264 100644 --- a/src/test/compile-fail/allocator/not-an-allocator.rs +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -16,5 +16,6 @@ static A: usize = 0; //~| the trait bound `usize: //~| the trait bound `usize: //~| the trait bound `usize: +//~| the trait bound `usize: fn main() {} -- cgit 1.4.1-3-g733a5 From fddf51ee0b9765484fc316dbf3d4feb8ceea715d Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 3 Apr 2018 08:51:02 +0900 Subject: Use NonNull instead of *mut u8 in the Alloc trait Fixes #49608 --- src/doc/nomicon | 2 +- .../src/language-features/global-allocator.md | 1 + src/liballoc/alloc.rs | 19 +++---- src/liballoc/arc.rs | 16 +++--- src/liballoc/btree/node.rs | 16 +++--- src/liballoc/heap.rs | 22 ++++++-- src/liballoc/lib.rs | 1 + src/liballoc/raw_vec.rs | 40 +++++++-------- src/liballoc/rc.rs | 18 +++---- src/liballoc/tests/heap.rs | 3 +- src/liballoc_system/lib.rs | 29 +++++------ src/libcore/alloc.rs | 58 ++++++++++------------ src/libcore/ptr.rs | 8 +++ src/libstd/collections/hash/table.rs | 6 +-- src/libstd/lib.rs | 1 + src/test/run-pass/allocator/xcrate-use2.rs | 2 +- src/test/run-pass/realloc-16687.rs | 18 +++---- src/test/run-pass/regions-mock-trans.rs | 5 +- 18 files changed, 136 insertions(+), 129 deletions(-) (limited to 'src/libstd') diff --git a/src/doc/nomicon b/src/doc/nomicon index 6a8f0a27e9a..498ac299742 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 6a8f0a27e9a58c55c89d07bc43a176fdae5e051c +Subproject commit 498ac2997420f7b25f7cd0a3f8202950d8ad93ec diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index 6ce12ba684d..a3f3ee65bf0 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -30,6 +30,7 @@ looks like: #![feature(global_allocator, allocator_api, heap_api)] use std::alloc::{GlobalAlloc, System, Layout, Void}; +use std::ptr::NonNull; struct MyAllocator; diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 063f0543ec4..af48aa7961e 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -16,6 +16,7 @@ issue = "32838")] use core::intrinsics::{min_align_of_val, size_of_val}; +use core::ptr::NonNull; use core::usize; #[doc(inline)] @@ -120,27 +121,27 @@ unsafe impl GlobalAlloc for Global { unsafe impl Alloc for Global { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc(self, layout).into() } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - GlobalAlloc::dealloc(self, ptr as *mut Void, layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result<*mut u8, AllocErr> + -> Result, AllocErr> { - GlobalAlloc::realloc(self, ptr as *mut Void, layout, new_size).into() + GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size).into() } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc_zeroed(self, layout).into() } @@ -195,8 +196,8 @@ mod tests { let ptr = Global.alloc_zeroed(layout.clone()) .unwrap_or_else(|_| Global.oom()); - let end = ptr.offset(layout.size() as isize); - let mut i = ptr; + let mut i = ptr.cast::().as_ptr(); + let end = i.offset(layout.size() as isize); while i < end { assert_eq!(*i, 0); i = i.offset(1); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index f0a325530ba..88754ace3ce 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -512,15 +512,13 @@ impl Arc { // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { - let ptr = self.ptr.as_ptr(); - // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). ptr::drop_in_place(&mut self.ptr.as_mut().data); if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) } } @@ -558,7 +556,7 @@ impl Arc { .unwrap_or_else(|_| Global.oom()); // Initialize the real ArcInner - let inner = set_data_ptr(ptr as *mut T, mem) as *mut ArcInner; + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); @@ -625,7 +623,7 @@ impl ArcFromSlice for Arc<[T]> { // In the event of a panic, elements that have been written // into the new ArcInner will be dropped, then the memory freed. struct Guard { - mem: *mut u8, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -639,7 +637,7 @@ impl ArcFromSlice for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem, self.layout.clone()); + Global.dealloc(self.mem.as_void(), self.layout.clone()); } } } @@ -655,7 +653,7 @@ impl ArcFromSlice for Arc<[T]> { let elems = &mut (*ptr).data as *mut [T] as *mut T; let mut guard = Guard{ - mem: mem, + mem: NonNull::new_unchecked(mem), elems: elems, layout: layout, n_elems: 0, @@ -1147,8 +1145,6 @@ impl Drop for Weak { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - let ptr = self.ptr.as_ptr(); - // If we find out that we were the last weak pointer, then its time to // deallocate the data entirely. See the discussion in Arc::drop() about // the memory orderings @@ -1160,7 +1156,7 @@ impl Drop for Weak { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 8e23228bd28..64aa40ac166 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -236,7 +236,7 @@ impl Root { pub fn pop_level(&mut self) { debug_assert!(self.height > 0); - let top = self.node.ptr.as_ptr() as *mut u8; + let top = self.node.ptr; self.node = unsafe { BoxedNode::from_ptr(self.as_mut() @@ -249,7 +249,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(top, Layout::new::>()); + Global.dealloc(NonNull::from(top).as_void(), Layout::new::>()); } } } @@ -433,9 +433,9 @@ impl NodeRef { marker::Edge > > { - let ptr = self.as_leaf() as *const LeafNode as *const u8 as *mut u8; + let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(ptr, Layout::new::>()); + Global.dealloc(node.as_void(), Layout::new::>()); ret } } @@ -454,9 +454,9 @@ impl NodeRef { marker::Edge > > { - let ptr = self.as_internal() as *const InternalNode as *const u8 as *mut u8; + let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(ptr, Layout::new::>()); + Global.dealloc(node.as_void(), Layout::new::>()); ret } } @@ -1239,12 +1239,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_ptr() as *mut u8, + right_node.node.as_void(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_ptr() as *mut u8, + right_node.node.as_void(), Layout::new::>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index e79383331e1..cfb6504e743 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -8,14 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use alloc::{Excess, Layout, AllocErr, CannotReallocInPlace}; +#![allow(deprecated)] + +pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Void}; use core::alloc::Alloc as CoreAlloc; +use core::ptr::NonNull; #[doc(hidden)] pub mod __core { pub use core::*; } +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); + /// Compatibility with older versions of #[global_allocator] during bootstrap pub unsafe trait Alloc { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; @@ -42,13 +48,13 @@ pub unsafe trait Alloc { new_layout: Layout) -> Result<(), CannotReallocInPlace>; } -#[allow(deprecated)] unsafe impl Alloc for T where T: CoreAlloc { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc(self, layout) + CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr()) } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::dealloc(self, ptr, layout) } @@ -64,28 +70,33 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::realloc(self, ptr, layout, new_layout.size()) + let ptr = NonNull::new_unchecked(ptr as *mut Void); + CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) } unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc_zeroed(self, layout) + CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr()) } unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { CoreAlloc::alloc_excess(self, layout) + .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } unsafe fn realloc_excess(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) + .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } @@ -93,6 +104,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let ptr = NonNull::new_unchecked(ptr as *mut Void); CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index a10820ebefd..3a106a2ff5c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -99,6 +99,7 @@ #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] +#![feature(nonnull_cast)] #![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 80b816878fb..d72301f5ad6 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -12,7 +12,7 @@ use alloc::{Alloc, Layout, Global}; use core::cmp; use core::mem; use core::ops::Drop; -use core::ptr::{self, Unique}; +use core::ptr::{self, NonNull, Unique}; use core::slice; use super::boxed::Box; use super::allocator::CollectionAllocErr; @@ -90,7 +90,7 @@ impl RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - mem::align_of::() as *mut u8 + NonNull::::dangling().as_void() } else { let align = mem::align_of::(); let result = if zeroed { @@ -105,7 +105,7 @@ impl RawVec { }; RawVec { - ptr: Unique::new_unchecked(ptr as *mut _), + ptr: ptr.cast().into(), cap, a, } @@ -310,11 +310,11 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - let ptr_res = self.a.realloc(self.ptr.as_ptr() as *mut u8, + let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_void(), cur, new_size); match ptr_res { - Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)), + Ok(ptr) => (new_cap, ptr.cast().into()), Err(_) => self.a.oom(), } } @@ -369,8 +369,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - let ptr = self.ptr() as *mut _; - match self.a.grow_in_place(ptr, old_layout, new_size) { + match self.a.grow_in_place(NonNull::from(self.ptr).as_void(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -427,13 +426,12 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; - self.ptr = Unique::new_unchecked(res? as *mut T); + self.ptr = res?.cast().into(); self.cap = new_cap; Ok(()) @@ -537,13 +535,12 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; - self.ptr = Unique::new_unchecked(res? as *mut T); + self.ptr = res?.cast().into(); self.cap = new_cap; Ok(()) @@ -600,11 +597,12 @@ impl RawVec { // (regardless of whether `self.cap - used_cap` wrapped). // Therefore we can safely call grow_in_place. - let ptr = self.ptr() as *mut _; let new_layout = Layout::new::().repeat(new_cap).unwrap().0; // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).expect("capacity overflow"); - match self.a.grow_in_place(ptr, old_layout, new_layout.size()) { + match self.a.grow_in_place( + NonNull::from(self.ptr).as_void(), old_layout, new_layout.size(), + ) { Ok(_) => { self.cap = new_cap; true @@ -664,10 +662,10 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - match self.a.realloc(self.ptr.as_ptr() as *mut u8, + match self.a.realloc(NonNull::from(self.ptr).as_void(), old_layout, new_size) { - Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T), + Ok(p) => self.ptr = p.cast().into(), Err(_) => self.a.oom(), } } @@ -700,8 +698,7 @@ impl RawVec { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - let ptr = self.ptr() as *mut u8; - self.a.dealloc(ptr, layout); + self.a.dealloc(NonNull::from(self.ptr).as_void(), layout); } } } @@ -737,6 +734,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { #[cfg(test)] mod tests { use super::*; + use alloc::Void; #[test] fn allocator_param() { @@ -756,7 +754,7 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); @@ -766,7 +764,7 @@ mod tests { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 3c0b11bfe74..1c835fe50de 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free}; +use alloc::{Global, Alloc, Layout, Void, box_free}; use string::String; use vec::Vec; @@ -671,7 +671,7 @@ impl Rc { .unwrap_or_else(|_| Global.oom()); // Initialize the real RcBox - let inner = set_data_ptr(ptr as *mut T, mem) as *mut RcBox; + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; ptr::write(&mut (*inner).strong, Cell::new(1)); ptr::write(&mut (*inner).weak, Cell::new(1)); @@ -737,7 +737,7 @@ impl RcFromSlice for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard { - mem: *mut u8, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -760,14 +760,14 @@ impl RcFromSlice for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut u8; + let mem = ptr as *mut _ as *mut Void; let layout = Layout::for_value(&*ptr); // Pointer to first element let elems = &mut (*ptr).value as *mut [T] as *mut T; let mut guard = Guard{ - mem: mem, + mem: NonNull::new_unchecked(mem), elems: elems, layout: layout, n_elems: 0, @@ -834,8 +834,6 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - let ptr = self.ptr.as_ptr(); - self.dec_strong(); if self.strong() == 0 { // destroy the contained object @@ -846,7 +844,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1266,13 +1264,11 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { unsafe { - let ptr = self.ptr.as_ptr(); - self.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Global.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/src/liballoc/tests/heap.rs b/src/liballoc/tests/heap.rs index 328131e2fef..6fa88ce969a 100644 --- a/src/liballoc/tests/heap.rs +++ b/src/liballoc/tests/heap.rs @@ -34,7 +34,8 @@ fn check_overalign_requests(mut allocator: T) { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() }).collect(); for &ptr in &pointers { - assert_eq!((ptr as usize) % align, 0, "Got a pointer less aligned than requested") + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") } // Clean up diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index c6507282b24..bf27e972177 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -42,6 +42,7 @@ const MIN_ALIGN: usize = 8; const MIN_ALIGN: usize = 16; use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Void}; +use core::ptr::NonNull; #[unstable(feature = "allocator_api", issue = "32838")] pub struct System; @@ -49,26 +50,26 @@ pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc(self, layout).into() } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc_zeroed(self, layout).into() } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - GlobalAlloc::dealloc(self, ptr as *mut Void, layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, old_layout: Layout, - new_size: usize) -> Result<*mut u8, AllocErr> { - GlobalAlloc::realloc(self, ptr as *mut Void, old_layout, new_size).into() + new_size: usize) -> Result, AllocErr> { + GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size).into() } #[inline] @@ -81,26 +82,26 @@ unsafe impl Alloc for System { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl<'a> Alloc for &'a System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc(*self, layout).into() } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { GlobalAlloc::alloc_zeroed(*self, layout).into() } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - GlobalAlloc::dealloc(*self, ptr as *mut Void, layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, old_layout: Layout, - new_size: usize) -> Result<*mut u8, AllocErr> { - GlobalAlloc::realloc(*self, ptr as *mut Void, old_layout, new_size).into() + new_size: usize) -> Result, AllocErr> { + GlobalAlloc::realloc(*self, ptr.as_ptr(), old_layout, new_size).into() } #[inline] diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 7334f986f2b..632eed96049 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -42,21 +42,17 @@ impl Void { } /// Convert from a return value of GlobalAlloc::alloc to that of Alloc::alloc -impl From<*mut Void> for Result<*mut u8, AllocErr> { +impl From<*mut Void> for Result, AllocErr> { fn from(ptr: *mut Void) -> Self { - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr) - } + NonNull::new(ptr).ok_or(AllocErr) } } /// Convert from a return value of Alloc::alloc to that of GlobalAlloc::alloc -impl From> for *mut Void { - fn from(result: Result<*mut u8, AllocErr>) -> Self { +impl From, AllocErr>> for *mut Void { + fn from(result: Result, AllocErr>) -> Self { match result { - Ok(ptr) => ptr as *mut Void, + Ok(ptr) => ptr.as_ptr(), Err(_) => Void::null_mut(), } } @@ -65,7 +61,7 @@ impl From> for *mut Void { /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -575,7 +571,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -592,7 +588,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); /// Allocator-specific method for signaling an out-of-memory /// condition. @@ -710,9 +706,9 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result<*mut u8, AllocErr> { + new_size: usize) -> Result, AllocErr> { let old_size = layout.size(); if new_size >= old_size { @@ -729,7 +725,9 @@ pub unsafe trait Alloc { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let result = self.alloc(new_layout); if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, + new_ptr.as_ptr() as *mut u8, + cmp::min(old_size, new_size)); self.dealloc(ptr, layout); } result @@ -751,11 +749,11 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { - ptr::write_bytes(p, 0, size); + ptr::write_bytes(p.as_ptr() as *mut u8, 0, size); } p } @@ -800,7 +798,7 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -845,7 +843,7 @@ pub unsafe trait Alloc { /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -900,7 +898,7 @@ pub unsafe trait Alloc { /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -951,7 +949,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + unsafe { self.alloc(k).map(|p| p.cast()) } } else { Err(AllocErr) } @@ -977,10 +975,9 @@ pub unsafe trait Alloc { unsafe fn dealloc_one(&mut self, ptr: NonNull) where Self: Sized { - let raw_ptr = ptr.as_ptr() as *mut u8; let k = Layout::new::(); if k.size() > 0 { - self.dealloc(raw_ptr, k); + self.dealloc(ptr.as_void(), k); } } @@ -1020,10 +1017,7 @@ pub unsafe trait Alloc { match Layout::array::(n) { Ok(ref layout) if layout.size() > 0 => { unsafe { - self.alloc(layout.clone()) - .map(|p| { - NonNull::new_unchecked(p as *mut T) - }) + self.alloc(layout.clone()).map(|p| p.cast()) } } _ => Err(AllocErr), @@ -1068,11 +1062,10 @@ pub unsafe trait Alloc { n_new: usize) -> Result, AllocErr> where Self: Sized { - match (Layout::array::(n_old), Layout::array::(n_new), ptr.as_ptr()) { - (Ok(ref k_old), Ok(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { + match (Layout::array::(n_old), Layout::array::(n_new)) { + (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr as *mut u8, k_old.clone(), k_new.size()) - .map(|p| NonNull::new_unchecked(p as *mut T)) + self.realloc(ptr.as_void(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { Err(AllocErr) @@ -1103,10 +1096,9 @@ pub unsafe trait Alloc { unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> where Self: Sized { - let raw_ptr = ptr.as_ptr() as *mut u8; match Layout::array::(n) { Ok(ref k) if k.size() > 0 => { - Ok(self.dealloc(raw_ptr, k.clone())) + Ok(self.dealloc(ptr.as_void(), k.clone())) } _ => { Err(AllocErr) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index c1e150e9fb9..f4e668328ce 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2750,6 +2750,14 @@ impl NonNull { NonNull::new_unchecked(self.as_ptr() as *mut U) } } + + /// Cast to a `Void` pointer + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn as_void(self) -> NonNull<::alloc::Void> { + unsafe { + NonNull::new_unchecked(self.as_ptr() as _) + } + } } #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 50263705143..38c99373788 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -757,12 +757,10 @@ impl RawTable { let buffer = Global.alloc(Layout::from_size_align(size, alignment) .map_err(|_| CollectionAllocErr::CapacityOverflow)?)?; - let hashes = buffer as *mut HashUint; - Ok(RawTable { capacity_mask: capacity.wrapping_sub(1), size: 0, - hashes: TaggedHashUintPtr::new(hashes), + hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()), marker: marker::PhantomData, }) } @@ -1185,7 +1183,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { debug_assert!(!oflo, "should be impossible"); unsafe { - Global.dealloc(self.hashes.ptr() as *mut u8, + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_void(), Layout::from_size_align(size, align).unwrap()); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 25ba75fd35e..a34fcb5a7f9 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,6 +275,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] +#![feature(nonnull_cast)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs index 52eb963efdb..b8e844522dc 100644 --- a/src/test/run-pass/allocator/xcrate-use2.rs +++ b/src/test/run-pass/allocator/xcrate-use2.rs @@ -30,7 +30,7 @@ fn main() { let layout = Layout::from_size_align(4, 2).unwrap(); // Global allocator routes to the `custom_as_global` global - let ptr = Global.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 1); Global.dealloc(ptr, layout.clone()); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index a562165d21b..49ab0ee3310 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -13,10 +13,10 @@ // Ideally this would be revised to use no_std, but for now it serves // well enough to reproduce (and illustrate) the bug from #16687. -#![feature(heap_api, allocator_api)] +#![feature(heap_api, allocator_api, nonnull_cast)] -use std::heap::{Heap, Alloc, Layout}; -use std::ptr; +use std::alloc::{Global, Alloc, Layout}; +use std::ptr::{self, NonNull}; fn main() { unsafe { @@ -50,13 +50,13 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Heap.alloc(layout.clone()).unwrap_or_else(|_| Heap.oom()); + let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); } - ret + ret.cast().as_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Heap.dealloc(ptr, layout); + Global.dealloc(NonNull::new_unchecked(ptr).as_void(), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { @@ -72,14 +72,14 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Heap.realloc(ptr, old.clone(), new.clone()) - .unwrap_or_else(|_| Heap.oom()); + let ret = Global.realloc(NonNull::new_unchecked(ptr).as_void(), old.clone(), new.size()) + .unwrap_or_else(|_| Global.oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ret); } - ret + ret.cast().as_ptr() } fn idx_to_size(i: usize) -> usize { (i+1) * 10 } diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 7d34b8fd00f..3c37243c8b9 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -13,6 +13,7 @@ #![feature(allocator_api)] use std::heap::{Alloc, Heap, Layout}; +use std::ptr::NonNull; struct arena(()); @@ -33,7 +34,7 @@ fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Heap.alloc(Layout::new::()) .unwrap_or_else(|_| Heap.oom()); - &*(ptr as *const _) + &*(ptr.as_ptr() as *const _) } } @@ -45,7 +46,7 @@ fn g(fcx : &Fcx) { let bcx = Bcx { fcx: fcx }; let bcx2 = h(&bcx); unsafe { - Heap.dealloc(bcx2 as *const _ as *mut _, Layout::new::()); + Heap.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); } } -- cgit 1.4.1-3-g733a5 From f607a3872addf380846cae28661a777ec3e3c9a2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 11 Apr 2018 17:19:48 +0200 Subject: Rename alloc::Void to alloc::Opaque --- src/doc/nomicon | 2 +- .../src/language-features/global-allocator.md | 6 +- src/liballoc/alloc.rs | 26 +++--- src/liballoc/arc.rs | 6 +- src/liballoc/btree/node.rs | 10 +- src/liballoc/heap.rs | 12 +-- src/liballoc/raw_vec.rs | 22 ++--- src/liballoc/rc.rs | 10 +- src/liballoc_system/lib.rs | 103 ++++++++++----------- src/libcore/alloc.rs | 38 ++++---- src/libcore/ptr.rs | 4 +- src/librustc_allocator/expand.rs | 12 +-- src/libstd/alloc.rs | 6 +- src/libstd/collections/hash/table.rs | 2 +- src/test/run-make-fulldeps/std-core-cycle/bar.rs | 4 +- src/test/run-pass/allocator/auxiliary/custom.rs | 6 +- src/test/run-pass/allocator/custom.rs | 6 +- src/test/run-pass/realloc-16687.rs | 4 +- 18 files changed, 139 insertions(+), 140 deletions(-) (limited to 'src/libstd') diff --git a/src/doc/nomicon b/src/doc/nomicon index 498ac299742..3c56329d1bd 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 498ac2997420f7b25f7cd0a3f8202950d8ad93ec +Subproject commit 3c56329d1bd9038e5341f1962bcd8d043312a712 diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index a3f3ee65bf0..031b6347445 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -29,17 +29,17 @@ looks like: ```rust #![feature(global_allocator, allocator_api, heap_api)] -use std::alloc::{GlobalAlloc, System, Layout, Void}; +use std::alloc::{GlobalAlloc, System, Layout, Opaque}; use std::ptr::NonNull; struct MyAllocator; unsafe impl GlobalAlloc for MyAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { System.dealloc(ptr, layout) } } diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 031babe5f6d..68a617e0ffe 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -76,36 +76,36 @@ pub const Heap: Global = Global; unsafe impl GlobalAlloc for Global { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { #[cfg(not(stage0))] let ptr = __rust_alloc(layout.size(), layout.align()); #[cfg(stage0)] let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0); - ptr as *mut Void + ptr as *mut Opaque } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { __rust_dealloc(ptr as *mut u8, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, layout: Layout, new_size: usize) -> *mut Void { + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { #[cfg(not(stage0))] let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); #[cfg(stage0)] let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size, layout.align(), &mut 0); - ptr as *mut Void + ptr as *mut Opaque } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { #[cfg(not(stage0))] let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); #[cfg(stage0)] let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); - ptr as *mut Void + ptr as *mut Opaque } #[inline] @@ -121,27 +121,27 @@ unsafe impl GlobalAlloc for Global { unsafe impl Alloc for Global { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result, AllocErr> + -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } @@ -178,7 +178,7 @@ pub(crate) unsafe fn box_free(ptr: *mut T) { // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr as *mut Void, layout); + Global.dealloc(ptr as *mut Opaque, layout); } } diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 88754ace3ce..225b055d8ee 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -518,7 +518,7 @@ impl Arc { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) } } @@ -637,7 +637,7 @@ impl ArcFromSlice for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem.as_void(), self.layout.clone()); + Global.dealloc(self.mem.as_opaque(), self.layout.clone()); } } } @@ -1156,7 +1156,7 @@ impl Drop for Weak { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 64aa40ac166..d6346662314 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -249,7 +249,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(NonNull::from(top).as_void(), Layout::new::>()); + Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::>()); } } } @@ -435,7 +435,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_void(), Layout::new::>()); + Global.dealloc(node.as_opaque(), Layout::new::>()); ret } } @@ -456,7 +456,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_void(), Layout::new::>()); + Global.dealloc(node.as_opaque(), Layout::new::>()); ret } } @@ -1239,12 +1239,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_void(), + right_node.node.as_opaque(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_void(), + right_node.node.as_opaque(), Layout::new::>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index cfb6504e743..faac38ca7ce 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -10,7 +10,7 @@ #![allow(deprecated)] -pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Void}; +pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque}; use core::alloc::Alloc as CoreAlloc; use core::ptr::NonNull; @@ -54,7 +54,7 @@ unsafe impl Alloc for T where T: CoreAlloc { } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::dealloc(self, ptr, layout) } @@ -70,7 +70,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) } @@ -87,7 +87,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } @@ -96,7 +96,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } @@ -104,7 +104,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Void); + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d72301f5ad6..214cc7d7d0c 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -90,7 +90,7 @@ impl RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - NonNull::::dangling().as_void() + NonNull::::dangling().as_opaque() } else { let align = mem::align_of::(); let result = if zeroed { @@ -310,7 +310,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_void(), + let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(), cur, new_size); match ptr_res { @@ -369,7 +369,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - match self.a.grow_in_place(NonNull::from(self.ptr).as_void(), old_layout, new_size) { + match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -426,7 +426,7 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -535,7 +535,7 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_void(), layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -601,7 +601,7 @@ impl RawVec { // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).expect("capacity overflow"); match self.a.grow_in_place( - NonNull::from(self.ptr).as_void(), old_layout, new_layout.size(), + NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(), ) { Ok(_) => { self.cap = new_cap; @@ -662,7 +662,7 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - match self.a.realloc(NonNull::from(self.ptr).as_void(), + match self.a.realloc(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), @@ -698,7 +698,7 @@ impl RawVec { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - self.a.dealloc(NonNull::from(self.ptr).as_void(), layout); + self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout); } } } @@ -734,7 +734,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { #[cfg(test)] mod tests { use super::*; - use alloc::Void; + use alloc::Opaque; #[test] fn allocator_param() { @@ -754,7 +754,7 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); @@ -764,7 +764,7 @@ mod tests { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 1c835fe50de..de0422d82bb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, Void, box_free}; +use alloc::{Global, Alloc, Layout, Opaque, box_free}; use string::String; use vec::Vec; @@ -737,7 +737,7 @@ impl RcFromSlice for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard { - mem: NonNull, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -760,7 +760,7 @@ impl RcFromSlice for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut Void; + let mem = ptr as *mut _ as *mut Opaque; let layout = Layout::for_value(&*ptr); // Pointer to first element @@ -844,7 +844,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1268,7 +1268,7 @@ impl Drop for Weak { // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Global.dealloc(self.ptr.as_void(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 7fea6061169..fd8109e2a4a 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -41,7 +41,7 @@ const MIN_ALIGN: usize = 8; #[allow(dead_code)] const MIN_ALIGN: usize = 16; -use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Void}; +use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque}; use core::ptr::NonNull; #[unstable(feature = "allocator_api", issue = "32838")] @@ -50,25 +50,25 @@ pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } @@ -82,25 +82,25 @@ unsafe impl Alloc for System { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl<'a> Alloc for &'a System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } @@ -112,13 +112,13 @@ unsafe impl<'a> Alloc for &'a System { #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] mod realloc_fallback { - use core::alloc::{GlobalAlloc, Void, Layout}; + use core::alloc::{GlobalAlloc, Opaque, Layout}; use core::cmp; use core::ptr; impl super::System { - pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Void, old_layout: Layout, - new_size: usize) -> *mut Void { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout, + new_size: usize) -> *mut Opaque { // Docs for GlobalAlloc::realloc require this to be valid: let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); @@ -141,20 +141,21 @@ mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Layout, Void}; + use core::alloc::{GlobalAlloc, Layout, Opaque}; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut Void + libc::malloc(layout.size()) as *mut Opaque } else { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - // FIXME: use Void::null_mut https://github.com/rust-lang/rust/issues/49659 - return 0 as *mut Void + // FIXME: use Opaque::null_mut + // https://github.com/rust-lang/rust/issues/49659 + return 0 as *mut Opaque } } aligned_malloc(&layout) @@ -162,9 +163,9 @@ mod platform { } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut Void + libc::calloc(layout.size(), 1) as *mut Opaque } else { let ptr = self.alloc(layout.clone()); if !ptr.is_null() { @@ -175,24 +176,23 @@ mod platform { } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) { libc::free(ptr as *mut libc::c_void) } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { - let align = old_layout.align(); - if align <= MIN_ALIGN && align <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Void + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque } else { - self.realloc_fallback(ptr, old_layout, new_size) + self.realloc_fallback(ptr, layout, new_size) } } } #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Void { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -210,19 +210,19 @@ mod platform { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut Void + libc::memalign(layout.align(), layout.size()) as *mut Opaque } #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Void { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { let mut out = ptr::null_mut(); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { - // FIXME: use Void::null_mut https://github.com/rust-lang/rust/issues/49659 - 0 as *mut Void + // FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659 + 0 as *mut Opaque } else { - out as *mut Void + out as *mut Opaque } } } @@ -232,7 +232,7 @@ mod platform { mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Void, Layout}; + use core::alloc::{GlobalAlloc, Opaque, Layout}; type LPVOID = *mut u8; type HANDLE = LPVOID; @@ -264,7 +264,7 @@ mod platform { } #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Void { + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque { let ptr = if layout.align() <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { @@ -276,23 +276,23 @@ mod platform { align_ptr(ptr, layout.align()) } }; - ptr as *mut Void + ptr as *mut Opaque } #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { allocate_with_flags(layout, 0) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { if layout.align() <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", @@ -306,12 +306,11 @@ mod platform { } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { - let align = old_layout.align(); - if align <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Void + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + if layout.align() <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque } else { - self.realloc_fallback(ptr, old_layout, new_size) + self.realloc_fallback(ptr, layout, new_size) } } } @@ -338,7 +337,7 @@ mod platform { mod platform { extern crate dlmalloc; - use core::alloc::{GlobalAlloc, Layout, Void}; + use core::alloc::{GlobalAlloc, Layout, Opaque}; use System; // No need for synchronization here as wasm is currently single-threaded @@ -347,23 +346,23 @@ mod platform { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Void { - DLMALLOC.malloc(layout.size(), layout.align()) as *mut Void + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { - DLMALLOC.calloc(layout.size(), layout.align()) as *mut Void + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque } #[inline] - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Void, layout: Layout, new_size: usize) -> *mut Void { - DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Void + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque } } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 97a49703baf..fdba91bec80 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -24,12 +24,12 @@ use ptr::{self, NonNull}; extern { /// An opaque, unsized type. Used for pointers to allocated memory. /// - /// This type can only be used behind a pointer like `*mut Void` or `ptr::NonNull`. + /// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull`. /// Such pointers are similar to C’s `void*` type. - pub type Void; + pub type Opaque; } -impl Void { +impl Opaque { /// Similar to `std::ptr::null`, which requires `T: Sized`. pub fn null() -> *const Self { 0 as _ @@ -44,7 +44,7 @@ impl Void { /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -pub struct Excess(pub NonNull, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -387,11 +387,11 @@ impl From for CollectionAllocErr { // FIXME: docs pub unsafe trait GlobalAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut Void; + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout); + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Void { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { let size = layout.size(); let ptr = self.alloc(layout); if !ptr.is_null() { @@ -404,7 +404,7 @@ pub unsafe trait GlobalAlloc { /// /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). - unsafe fn realloc(&self, ptr: *mut Void, old_layout: Layout, new_size: usize) -> *mut Void { + unsafe fn realloc(&self, ptr: *mut Opaque, old_layout: Layout, new_size: usize) -> *mut Opaque { let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); let new_ptr = self.alloc(new_layout); if !new_ptr.is_null() { @@ -554,7 +554,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -571,7 +571,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); /// Allocator-specific method for signaling an out-of-memory /// condition. @@ -689,9 +689,9 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { let old_size = layout.size(); if new_size >= old_size { @@ -732,7 +732,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { @@ -781,7 +781,7 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -826,7 +826,7 @@ pub unsafe trait Alloc { /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -881,7 +881,7 @@ pub unsafe trait Alloc { /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -960,7 +960,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - self.dealloc(ptr.as_void(), k); + self.dealloc(ptr.as_opaque(), k); } } @@ -1048,7 +1048,7 @@ pub unsafe trait Alloc { match (Layout::array::(n_old), Layout::array::(n_new)) { (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr.as_void(), k_old.clone(), k_new.size()).map(NonNull::cast) + self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { Err(AllocErr) @@ -1081,7 +1081,7 @@ pub unsafe trait Alloc { { match Layout::array::(n) { Ok(ref k) if k.size() > 0 => { - Ok(self.dealloc(ptr.as_void(), k.clone())) + Ok(self.dealloc(ptr.as_opaque(), k.clone())) } _ => { Err(AllocErr) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f4e668328ce..4a7d7c410eb 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2751,9 +2751,9 @@ impl NonNull { } } - /// Cast to a `Void` pointer + /// Cast to an `Opaque` pointer #[unstable(feature = "allocator_api", issue = "32838")] - pub fn as_void(self) -> NonNull<::alloc::Void> { + pub fn as_opaque(self) -> NonNull<::alloc::Opaque> { unsafe { NonNull::new_unchecked(self.as_ptr() as _) } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 58d4c7f289c..305502e7f06 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -221,7 +221,7 @@ impl<'a> AllocFnFactory<'a> { let ident = ident(); args.push(self.cx.arg(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_void()) + self.cx.expr_cast(self.span, arg, self.ptr_opaque()) } AllocatorTy::Usize => { @@ -276,13 +276,13 @@ impl<'a> AllocFnFactory<'a> { self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } - fn ptr_void(&self) -> P { - let void = self.cx.path(self.span, vec![ + fn ptr_opaque(&self) -> P { + let opaque = self.cx.path(self.span, vec![ self.core, Ident::from_str("alloc"), - Ident::from_str("Void"), + Ident::from_str("Opaque"), ]); - let ty_void = self.cx.ty_path(void); - self.cx.ty_ptr(self.span, ty_void, Mutability::Mutable) + let ty_opaque = self.cx.ty_path(opaque); + self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable) } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 4e728df010a..ff578ec42d2 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -21,7 +21,7 @@ #[doc(hidden)] #[allow(unused_attributes)] pub mod __default_lib_allocator { - use super::{System, Layout, GlobalAlloc, Void}; + use super::{System, Layout, GlobalAlloc, Opaque}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -46,7 +46,7 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { - System.dealloc(ptr as *mut Void, Layout::from_size_align_unchecked(size, align)) + System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align)) } #[no_mangle] @@ -56,7 +56,7 @@ pub mod __default_lib_allocator { align: usize, new_size: usize) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, align); - System.realloc(ptr as *mut Void, old_layout, new_size) as *mut u8 + System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8 } #[no_mangle] diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 38c99373788..93f059076d7 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1183,7 +1183,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { debug_assert!(!oflo, "should be impossible"); unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_void(), + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), Layout::from_size_align(size, align).unwrap()); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. diff --git a/src/test/run-make-fulldeps/std-core-cycle/bar.rs b/src/test/run-make-fulldeps/std-core-cycle/bar.rs index 20b87028fd1..62fd2ade1ca 100644 --- a/src/test/run-make-fulldeps/std-core-cycle/bar.rs +++ b/src/test/run-make-fulldeps/std-core-cycle/bar.rs @@ -16,11 +16,11 @@ use std::alloc::*; pub struct A; unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, _: Layout) -> *mut Void { + unsafe fn alloc(&self, _: Layout) -> *mut Opaque { loop {} } - unsafe fn dealloc(&self, _ptr: *mut Void, _: Layout) { + unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) { loop {} } } diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs index 95096efc7ef..e6a2e22983b 100644 --- a/src/test/run-pass/allocator/auxiliary/custom.rs +++ b/src/test/run-pass/allocator/auxiliary/custom.rs @@ -13,18 +13,18 @@ #![feature(heap_api, allocator_api)] #![crate_type = "rlib"] -use std::heap::{GlobalAlloc, System, Layout, Void}; +use std::heap::{GlobalAlloc, System, Layout, Opaque}; use std::sync::atomic::{AtomicUsize, Ordering}; pub struct A(pub AtomicUsize); unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { self.0.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { self.0.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index f7b2fd73c87..415d39a593e 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -15,7 +15,7 @@ extern crate helper; -use std::alloc::{self, Global, Alloc, System, Layout, Void}; +use std::alloc::{self, Global, Alloc, System, Layout, Opaque}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; static HITS: AtomicUsize = ATOMIC_USIZE_INIT; @@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT; struct A; unsafe impl alloc::GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Void { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { HITS.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 49ab0ee3310..38cc23c16a9 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Global.dealloc(NonNull::new_unchecked(ptr).as_void(), layout); + Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { @@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Global.realloc(NonNull::new_unchecked(ptr).as_void(), old.clone(), new.size()) + let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size()) .unwrap_or_else(|_| Global.oom()); if PRINT { -- cgit 1.4.1-3-g733a5 From c3a5d6b130e27d7d7587f56581247d5b08c38594 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 29 Mar 2018 14:59:13 -0700 Subject: std: Minimize size of panicking on wasm This commit applies a few code size optimizations for the wasm target to the standard library, namely around panics. We notably know that in most configurations it's impossible for us to print anything in wasm32-unknown-unknown so we can skip larger portions of panicking that are otherwise simply informative. This allows us to get quite a nice size reduction. Finally we can also tweak where the allocation happens for the `Box` that we panic with. By only allocating once unwinding starts we can reduce the size of a panicking wasm module from 44k to 350 bytes. --- src/ci/docker/wasm32-unknown/Dockerfile | 6 ++ src/libcore/panic.rs | 10 ++++ src/libpanic_abort/lib.rs | 2 +- src/libpanic_unwind/lib.rs | 12 ++-- src/libstd/lib.rs | 1 + src/libstd/panicking.rs | 88 ++++++++++++++++++++++------- src/libstd/sys/cloudabi/stdio.rs | 4 ++ src/libstd/sys/redox/stdio.rs | 4 ++ src/libstd/sys/unix/stdio.rs | 4 ++ src/libstd/sys/wasm/rwlock.rs | 4 +- src/libstd/sys/wasm/stdio.rs | 4 ++ src/libstd/sys/windows/stdio.rs | 4 ++ src/libstd/sys_common/backtrace.rs | 13 ++--- src/libstd/sys_common/mod.rs | 14 +++-- src/libstd/sys_common/thread_local.rs | 4 +- src/libstd/sys_common/util.rs | 5 +- src/libstd/thread/local.rs | 41 +++++++++++++- src/libstd/thread/mod.rs | 3 + src/test/run-make/wasm-panic-small/Makefile | 11 ++++ src/test/run-make/wasm-panic-small/foo.rs | 16 ++++++ 20 files changed, 205 insertions(+), 45 deletions(-) create mode 100644 src/test/run-make/wasm-panic-small/Makefile create mode 100644 src/test/run-make/wasm-panic-small/foo.rs (limited to 'src/libstd') diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile index 853923ad947..56eda548071 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/wasm32-unknown/Dockerfile @@ -25,6 +25,12 @@ ENV RUST_CONFIGURE_ARGS \ --set build.nodejs=/node-v9.2.0-linux-x64/bin/node \ --set rust.lld +# Some run-make tests have assertions about code size, and enabling debug +# assertions in libstd causes the binary to be much bigger than it would +# otherwise normally be. We already test libstd with debug assertions in lots of +# other contexts as well +ENV NO_DEBUG_ASSERTIONS=1 + ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ src/test/run-make \ src/test/ui \ diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 1720c9d8c60..37c79f2fafe 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -251,3 +251,13 @@ impl<'a> fmt::Display for Location<'a> { write!(formatter, "{}:{}:{}", self.file, self.line, self.col) } } + +/// An internal trait used by libstd to pass data from libstd to `panic_unwind` +/// and other panic runtimes. Not intended to be stabilized any time soon, do +/// not use. +#[unstable(feature = "std_internals", issue = "0")] +#[doc(hidden)] +pub unsafe trait BoxMeUp { + fn box_me_up(&mut self) -> *mut (Any + Send); + fn get(&self) -> &(Any + Send); +} diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 43c5bbbc618..392bf17968f 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -52,7 +52,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), // now hopefully. #[no_mangle] #[rustc_std_internal_symbol] -pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { +pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 { abort(); #[cfg(any(unix, target_os = "cloudabi"))] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 9321d6917d1..6c52c0fa10c 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -29,6 +29,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] +#![feature(allocator_api)] #![feature(alloc)] #![feature(core_intrinsics)] #![feature(lang_items)] @@ -36,6 +37,7 @@ #![feature(panic_unwind)] #![feature(raw)] #![feature(staged_api)] +#![feature(std_internals)] #![feature(unwind_attributes)] #![cfg_attr(target_env = "msvc", feature(raw))] @@ -47,9 +49,11 @@ extern crate libc; #[cfg(not(any(target_env = "msvc", all(windows, target_arch = "x86_64", target_env = "gnu"))))] extern crate unwind; +use alloc::boxed::Box; use core::intrinsics; use core::mem; use core::raw; +use core::panic::BoxMeUp; // Rust runtime's startup objects depend on these symbols, so make them public. #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] @@ -112,9 +116,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // implementation. #[no_mangle] #[unwind(allowed)] -pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { - imp::panic(mem::transmute(raw::TraitObject { - data: data as *mut (), - vtable: vtable as *mut (), - })) +pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 { + let payload = payload as *mut &mut BoxMeUp; + imp::panic(Box::from_raw((*payload).box_me_up())) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a34fcb5a7f9..dd96c57538c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -292,6 +292,7 @@ #![feature(rand)] #![feature(raw)] #![feature(rustc_attrs)] +#![feature(std_internals)] #![feature(stdsimd)] #![feature(shrink_to)] #![feature(slice_bytes)] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index fba3269204e..715fd45e490 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -17,6 +17,8 @@ //! * Executing a panic up to doing the actual implementation //! * Shims around "try" +use core::panic::BoxMeUp; + use io::prelude::*; use any::Any; @@ -27,7 +29,7 @@ use intrinsics; use mem; use ptr; use raw; -use sys::stdio::Stderr; +use sys::stdio::{Stderr, stderr_prints_nothing}; use sys_common::rwlock::RWLock; use sys_common::thread_info; use sys_common::util; @@ -56,7 +58,7 @@ extern { data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32; #[unwind(allowed)] - fn __rust_start_panic(data: usize, vtable: usize) -> u32; + fn __rust_start_panic(payload: usize) -> u32; } #[derive(Copy, Clone)] @@ -163,6 +165,12 @@ fn default_hook(info: &PanicInfo) { #[cfg(feature = "backtrace")] use sys_common::backtrace; + // Some platforms know that printing to stderr won't ever actually print + // anything, and if that's the case we can skip everything below. + if stderr_prints_nothing() { + return + } + // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. #[cfg(feature = "backtrace")] @@ -212,15 +220,15 @@ fn default_hook(info: &PanicInfo) { let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take()); match (prev, err.as_mut()) { - (Some(mut stderr), _) => { - write(&mut *stderr); - let mut s = Some(stderr); - LOCAL_STDERR.with(|slot| { - *slot.borrow_mut() = s.take(); - }); - } - (None, Some(ref mut err)) => { write(err) } - _ => {} + (Some(mut stderr), _) => { + write(&mut *stderr); + let mut s = Some(stderr); + LOCAL_STDERR.with(|slot| { + *slot.borrow_mut() = s.take(); + }); + } + (None, Some(ref mut err)) => { write(err) } + _ => {} } } @@ -344,7 +352,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, let mut s = String::new(); let _ = s.write_fmt(*msg); - rust_panic_with_hook(Box::new(s), Some(msg), file_line_col) + rust_panic_with_hook(&mut PanicPayload::new(s), Some(msg), file_line_col) } /// This is the entry point of panicking for panic!() and assert!(). @@ -360,7 +368,34 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(Box::new(msg), None, file_line_col) + rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col) +} + +struct PanicPayload { + inner: Option, +} + +impl PanicPayload { + fn new(inner: A) -> PanicPayload { + PanicPayload { inner: Some(inner) } + } +} + +unsafe impl BoxMeUp for PanicPayload { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let data = match self.inner.take() { + Some(a) => Box::new(a) as Box, + None => Box::new(()), + }; + Box::into_raw(data) + } + + fn get(&self) -> &(Any + Send) { + match self.inner { + Some(ref a) => a, + None => &(), + } + } } /// Executes the primary logic for a panic, including checking for recursive @@ -369,9 +404,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// This is the entry point or panics from libcore, formatted panics, and /// `Box` panics. Here we'll verify that we're not panicking recursively, /// run panic hooks, and then delegate to the actual implementation of panics. -#[inline(never)] -#[cold] -fn rust_panic_with_hook(payload: Box, +fn rust_panic_with_hook(payload: &mut BoxMeUp, message: Option<&fmt::Arguments>, file_line_col: &(&'static str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; @@ -391,7 +424,7 @@ fn rust_panic_with_hook(payload: Box, unsafe { let info = PanicInfo::internal_constructor( - &*payload, + payload.get(), message, Location::internal_constructor(file, line, col), ); @@ -419,16 +452,29 @@ fn rust_panic_with_hook(payload: Box, /// Shim around rust_panic. Called by resume_unwind. pub fn update_count_then_panic(msg: Box) -> ! { update_panic_count(1); - rust_panic(msg) + + struct RewrapBox(Box); + + unsafe impl BoxMeUp for RewrapBox { + fn box_me_up(&mut self) -> *mut (Any + Send) { + Box::into_raw(mem::replace(&mut self.0, Box::new(()))) + } + + fn get(&self) -> &(Any + Send) { + &*self.0 + } + } + + rust_panic(&mut RewrapBox(msg)) } /// A private no-mangle function on which to slap yer breakpoints. #[no_mangle] #[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints -pub fn rust_panic(msg: Box) -> ! { +pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! { let code = unsafe { - let obj = mem::transmute::<_, raw::TraitObject>(msg); - __rust_start_panic(obj.data as usize, obj.vtable as usize) + let obj = &mut msg as *mut &mut BoxMeUp; + __rust_start_panic(obj as usize) }; rtabort!("failed to initiate panic, error {}", code) } diff --git a/src/libstd/sys/cloudabi/stdio.rs b/src/libstd/sys/cloudabi/stdio.rs index 9519a926471..1d7344f921c 100644 --- a/src/libstd/sys/cloudabi/stdio.rs +++ b/src/libstd/sys/cloudabi/stdio.rs @@ -77,3 +77,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index 3abb094ac34..7a4d11b0ecb 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index e9b3d4affc7..87ba2aef4f1 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -75,3 +75,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { } pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs index 8b06f541674..6516010af47 100644 --- a/src/libstd/sys/wasm/rwlock.rs +++ b/src/libstd/sys/wasm/rwlock.rs @@ -30,7 +30,7 @@ impl RWLock { if *mode >= 0 { *mode += 1; } else { - panic!("rwlock locked for writing"); + rtabort!("rwlock locked for writing"); } } @@ -51,7 +51,7 @@ impl RWLock { if *mode == 0 { *mode = -1; } else { - panic!("rwlock locked for reading") + rtabort!("rwlock locked for reading") } } diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs index beb19c0ed2c..023f29576a2 100644 --- a/src/libstd/sys/wasm/stdio.rs +++ b/src/libstd/sys/wasm/stdio.rs @@ -69,3 +69,7 @@ pub const STDIN_BUF_SIZE: usize = 0; pub fn is_ebadf(_err: &io::Error) -> bool { true } + +pub fn stderr_prints_nothing() -> bool { + !cfg!(feature = "wasm_syscall") +} diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b43df20bddd..81b89da21d3 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -227,3 +227,7 @@ pub fn is_ebadf(err: &io::Error) -> bool { // idea is that on windows we use a slightly smaller buffer that's // been seen to be acceptable. pub const STDIN_BUF_SIZE: usize = 8 * 1024; + +pub fn stderr_prints_nothing() -> bool { + false +} diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 1955f3ec9a2..20109d2d0d5 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -139,10 +139,10 @@ pub fn __rust_begin_short_backtrace(f: F) -> T /// Controls how the backtrace should be formatted. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrintFormat { - /// Show all the frames with absolute path for files. - Full = 2, /// Show only relevant data from the backtrace. - Short = 3, + Short = 2, + /// Show all the frames with absolute path for files. + Full = 3, } // For now logging is turned off by default, and this function checks to see @@ -150,11 +150,10 @@ pub enum PrintFormat { pub fn log_enabled() -> Option { static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); match ENABLED.load(Ordering::SeqCst) { - 0 => {}, + 0 => {} 1 => return None, - 2 => return Some(PrintFormat::Full), - 3 => return Some(PrintFormat::Short), - _ => unreachable!(), + 2 => return Some(PrintFormat::Short), + _ => return Some(PrintFormat::Full), } let val = match env::var_os("RUST_BACKTRACE") { diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 27504d374dd..d0c4d6a7737 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -28,6 +28,16 @@ use sync::Once; use sys; +macro_rules! rtabort { + ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) +} + +macro_rules! rtassert { + ($e:expr) => (if !$e { + rtabort!(concat!("assertion failed: ", stringify!($e))); + }) +} + pub mod at_exit_imp; #[cfg(feature = "backtrace")] pub mod backtrace; @@ -101,10 +111,6 @@ pub fn at_exit(f: F) -> Result<(), ()> { if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } -macro_rules! rtabort { - ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) -} - /// One-time runtime cleanup. pub fn cleanup() { static CLEANUP: Once = Once::new(); diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index a4aa3d96d25..d0d6224de0a 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -169,7 +169,7 @@ impl StaticKey { self.key.store(key, Ordering::SeqCst); } INIT_LOCK.unlock(); - assert!(key != 0); + rtassert!(key != 0); return key } @@ -190,7 +190,7 @@ impl StaticKey { imp::destroy(key1); key2 }; - assert!(key != 0); + rtassert!(key != 0); match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) { // The CAS succeeded, so we've created the actual key 0 => key as usize, diff --git a/src/libstd/sys_common/util.rs b/src/libstd/sys_common/util.rs index a391c7cc6ef..a373e980b97 100644 --- a/src/libstd/sys_common/util.rs +++ b/src/libstd/sys_common/util.rs @@ -10,10 +10,13 @@ use fmt; use io::prelude::*; -use sys::stdio::Stderr; +use sys::stdio::{Stderr, stderr_prints_nothing}; use thread; pub fn dumb_print(args: fmt::Arguments) { + if stderr_prints_nothing() { + return + } let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 99479bc56ef..40d3280baa6 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -172,12 +172,16 @@ macro_rules! __thread_local_inner { &'static $crate::cell::UnsafeCell< $crate::option::Option<$t>>> { + #[cfg(target_arch = "wasm32")] + static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = + $crate::thread::__StaticLocalKeyInner::new(); + #[thread_local] - #[cfg(target_thread_local)] + #[cfg(all(target_thread_local, not(target_arch = "wasm32")))] static __KEY: $crate::thread::__FastLocalKeyInner<$t> = $crate::thread::__FastLocalKeyInner::new(); - #[cfg(not(target_thread_local))] + #[cfg(all(not(target_thread_local), not(target_arch = "wasm32")))] static __KEY: $crate::thread::__OsLocalKeyInner<$t> = $crate::thread::__OsLocalKeyInner::new(); @@ -295,6 +299,39 @@ impl LocalKey { } } +/// On some platforms like wasm32 there's no threads, so no need to generate +/// thread locals and we can instead just use plain statics! +#[doc(hidden)] +#[cfg(target_arch = "wasm32")] +pub mod statik { + use cell::UnsafeCell; + use fmt; + + pub struct Key { + inner: UnsafeCell>, + } + + unsafe impl ::marker::Sync for Key { } + + impl fmt::Debug for Key { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Key { .. }") + } + } + + impl Key { + pub const fn new() -> Key { + Key { + inner: UnsafeCell::new(None), + } + } + + pub unsafe fn get(&self) -> Option<&'static UnsafeCell>> { + Some(&*(&self.inner as *const _)) + } + } +} + #[doc(hidden)] #[cfg(target_thread_local)] pub mod fast { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 71aee673cfe..1b976b79b4c 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -202,6 +202,9 @@ pub use self::local::{LocalKey, AccessError}; // where fast TLS was not available; end-user code is compiled with fast TLS // where available, but both are needed. +#[unstable(feature = "libstd_thread_internals", issue = "0")] +#[cfg(target_arch = "wasm32")] +#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "0")] #[cfg(target_thread_local)] #[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner; diff --git a/src/test/run-make/wasm-panic-small/Makefile b/src/test/run-make/wasm-panic-small/Makefile new file mode 100644 index 00000000000..a11fba23595 --- /dev/null +++ b/src/test/run-make/wasm-panic-small/Makefile @@ -0,0 +1,11 @@ +-include ../../run-make-fulldeps/tools.mk + +ifeq ($(TARGET),wasm32-unknown-unknown) +all: + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown + wc -c < $(TMPDIR)/foo.wasm + [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "1024" ] +else +all: +endif + diff --git a/src/test/run-make/wasm-panic-small/foo.rs b/src/test/run-make/wasm-panic-small/foo.rs new file mode 100644 index 00000000000..9654d5f7c09 --- /dev/null +++ b/src/test/run-make/wasm-panic-small/foo.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "cdylib"] + +#[no_mangle] +pub fn foo() { + panic!("test"); +} -- cgit 1.4.1-3-g733a5 From 46d16b66e0b017430eb50b247926ea447c60ef07 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 6 Apr 2018 14:22:13 -0700 Subject: std: Avoid allocating panic message unless needed This commit removes allocation of the panic message in instances like `panic!("foo: {}", "bar")` if we don't actually end up needing the message. We don't need it in the case of wasm32 right now, and in general it's not needed for panic=abort instances that use the default panic hook. For now this commit only solves the wasm use case where with LTO the allocation is entirely removed, but the panic=abort use case can be implemented at a later date if needed. --- src/libcore/panic.rs | 14 +++- src/libstd/panicking.rs | 118 +++++++++++++++++----------- src/test/run-make/wasm-panic-small/Makefile | 8 +- src/test/run-make/wasm-panic-small/foo.rs | 13 +++ 4 files changed, 103 insertions(+), 50 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 37c79f2fafe..27ec4aaac75 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -49,11 +49,17 @@ impl<'a> PanicInfo<'a> { and related macros", issue = "0")] #[doc(hidden)] - pub fn internal_constructor(payload: &'a (Any + Send), - message: Option<&'a fmt::Arguments<'a>>, + #[inline] + pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>) -> Self { - PanicInfo { payload, location, message } + PanicInfo { payload: &(), location, message } + } + + #[doc(hidden)] + #[inline] + pub fn set_payload(&mut self, info: &'a (Any + Send)) { + self.payload = info; } /// Returns the payload associated with the panic. @@ -259,5 +265,5 @@ impl<'a> fmt::Display for Location<'a> { #[doc(hidden)] pub unsafe trait BoxMeUp { fn box_me_up(&mut self) -> *mut (Any + Send); - fn get(&self) -> &(Any + Send); + fn get(&mut self) -> &(Any + Send); } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 715fd45e490..24eae6a4c82 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -165,12 +165,6 @@ fn default_hook(info: &PanicInfo) { #[cfg(feature = "backtrace")] use sys_common::backtrace; - // Some platforms know that printing to stderr won't ever actually print - // anything, and if that's the case we can skip everything below. - if stderr_prints_nothing() { - return - } - // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. #[cfg(feature = "backtrace")] @@ -185,9 +179,6 @@ fn default_hook(info: &PanicInfo) { }; let location = info.location().unwrap(); // The current implementation always returns Some - let file = location.file(); - let line = location.line(); - let col = location.column(); let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, @@ -201,8 +192,8 @@ fn default_hook(info: &PanicInfo) { let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let write = |err: &mut ::io::Write| { - let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}:{}", - name, msg, file, line, col); + let _ = writeln!(err, "thread '{}' panicked at '{}', {}", + name, msg, location); #[cfg(feature = "backtrace")] { @@ -350,9 +341,38 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, // panic + OOM properly anyway (see comment in begin_panic // below). - let mut s = String::new(); - let _ = s.write_fmt(*msg); - rust_panic_with_hook(&mut PanicPayload::new(s), Some(msg), file_line_col) + rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); + + struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option, + } + + impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } + } + + fn fill(&mut self) -> &mut String { + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) + } + } + + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } + + fn get(&mut self) -> &(Any + Send) { + self.fill() + } + } } /// This is the entry point of panicking for panic!() and assert!(). @@ -368,42 +388,41 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col) -} - -struct PanicPayload { - inner: Option, -} + rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col); -impl PanicPayload { - fn new(inner: A) -> PanicPayload { - PanicPayload { inner: Some(inner) } + struct PanicPayload { + inner: Option, } -} -unsafe impl BoxMeUp for PanicPayload { - fn box_me_up(&mut self) -> *mut (Any + Send) { - let data = match self.inner.take() { - Some(a) => Box::new(a) as Box, - None => Box::new(()), - }; - Box::into_raw(data) + impl PanicPayload { + fn new(inner: A) -> PanicPayload { + PanicPayload { inner: Some(inner) } + } } - fn get(&self) -> &(Any + Send) { - match self.inner { - Some(ref a) => a, - None => &(), + unsafe impl BoxMeUp for PanicPayload { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let data = match self.inner.take() { + Some(a) => Box::new(a) as Box, + None => Box::new(()), + }; + Box::into_raw(data) + } + + fn get(&mut self) -> &(Any + Send) { + match self.inner { + Some(ref a) => a, + None => &(), + } } } } -/// Executes the primary logic for a panic, including checking for recursive -/// panics and panic hooks. +/// Central point for dispatching panics. /// -/// This is the entry point or panics from libcore, formatted panics, and -/// `Box` panics. Here we'll verify that we're not panicking recursively, -/// run panic hooks, and then delegate to the actual implementation of panics. +/// Executes the primary logic for a panic, including checking for recursive +/// panics, panic hooks, and finally dispatching to the panic runtime to either +/// abort or unwind. fn rust_panic_with_hook(payload: &mut BoxMeUp, message: Option<&fmt::Arguments>, file_line_col: &(&'static str, u32, u32)) -> ! { @@ -423,15 +442,24 @@ fn rust_panic_with_hook(payload: &mut BoxMeUp, } unsafe { - let info = PanicInfo::internal_constructor( - payload.get(), + let mut info = PanicInfo::internal_constructor( message, Location::internal_constructor(file, line, col), ); HOOK_LOCK.read(); match HOOK { - Hook::Default => default_hook(&info), - Hook::Custom(ptr) => (*ptr)(&info), + // Some platforms know that printing to stderr won't ever actually + // print anything, and if that's the case we can skip the default + // hook. + Hook::Default if stderr_prints_nothing() => {} + Hook::Default => { + info.set_payload(payload.get()); + default_hook(&info); + } + Hook::Custom(ptr) => { + info.set_payload(payload.get()); + (*ptr)(&info); + } } HOOK_LOCK.read_unlock(); } @@ -460,7 +488,7 @@ pub fn update_count_then_panic(msg: Box) -> ! { Box::into_raw(mem::replace(&mut self.0, Box::new(()))) } - fn get(&self) -> &(Any + Send) { + fn get(&mut self) -> &(Any + Send) { &*self.0 } } diff --git a/src/test/run-make/wasm-panic-small/Makefile b/src/test/run-make/wasm-panic-small/Makefile index a11fba23595..330ae300c44 100644 --- a/src/test/run-make/wasm-panic-small/Makefile +++ b/src/test/run-make/wasm-panic-small/Makefile @@ -2,9 +2,15 @@ ifeq ($(TARGET),wasm32-unknown-unknown) all: - $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg a wc -c < $(TMPDIR)/foo.wasm [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "1024" ] + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg b + wc -c < $(TMPDIR)/foo.wasm + [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ] + $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg c + wc -c < $(TMPDIR)/foo.wasm + [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ] else all: endif diff --git a/src/test/run-make/wasm-panic-small/foo.rs b/src/test/run-make/wasm-panic-small/foo.rs index 9654d5f7c09..1ea724ca94d 100644 --- a/src/test/run-make/wasm-panic-small/foo.rs +++ b/src/test/run-make/wasm-panic-small/foo.rs @@ -11,6 +11,19 @@ #![crate_type = "cdylib"] #[no_mangle] +#[cfg(a)] pub fn foo() { panic!("test"); } + +#[no_mangle] +#[cfg(b)] +pub fn foo() { + panic!("{}", 1); +} + +#[no_mangle] +#[cfg(c)] +pub fn foo() { + panic!("{}", "a"); +} -- cgit 1.4.1-3-g733a5 From 182d99cfd1a551b9daa3d7f6896775278fb2962e Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 9 Apr 2018 17:44:28 -0700 Subject: Add doc links to `std::os` extension traits Add documentation links to the original type for various OS-specific extension traits and normalize the language for introducing such traits. Also, remove some outdated comments around the extension trait definitions. --- src/libstd/os/android/fs.rs | 4 +++- src/libstd/os/bitrig/fs.rs | 4 +++- src/libstd/os/dragonfly/fs.rs | 4 +++- src/libstd/os/emscripten/fs.rs | 4 +++- src/libstd/os/freebsd/fs.rs | 4 +++- src/libstd/os/fuchsia/fs.rs | 4 +++- src/libstd/os/haiku/fs.rs | 4 +++- src/libstd/os/ios/fs.rs | 4 +++- src/libstd/os/linux/fs.rs | 4 +++- src/libstd/os/macos/fs.rs | 4 +++- src/libstd/os/netbsd/fs.rs | 4 +++- src/libstd/os/openbsd/fs.rs | 4 +++- src/libstd/os/solaris/fs.rs | 4 +++- src/libstd/sys/redox/ext/ffi.rs | 10 +++++++--- src/libstd/sys/redox/ext/fs.rs | 36 ++++++++++++++++++++++++----------- src/libstd/sys/redox/ext/process.rs | 10 +++++++--- src/libstd/sys/redox/ext/thread.rs | 6 ++++-- src/libstd/sys/unix/ext/ffi.rs | 8 ++++++-- src/libstd/sys/unix/ext/fs.rs | 33 ++++++++++++++++++-------------- src/libstd/sys/unix/ext/process.rs | 8 ++++++-- src/libstd/sys/unix/ext/thread.rs | 4 +++- src/libstd/sys/windows/ext/ffi.rs | 8 ++++++-- src/libstd/sys/windows/ext/fs.rs | 20 ++++++++++--------- src/libstd/sys/windows/ext/process.rs | 8 ++++++-- 24 files changed, 139 insertions(+), 64 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/os/android/fs.rs b/src/libstd/os/android/fs.rs index a51b4655985..5899dc688e2 100644 --- a/src/libstd/os/android/fs.rs +++ b/src/libstd/os/android/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::android::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/bitrig/fs.rs b/src/libstd/os/bitrig/fs.rs index e4f1c9432f3..24caf326ab0 100644 --- a/src/libstd/os/bitrig/fs.rs +++ b/src/libstd/os/bitrig/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::bitrig::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/dragonfly/fs.rs b/src/libstd/os/dragonfly/fs.rs index db672e56435..6aea450774f 100644 --- a/src/libstd/os/dragonfly/fs.rs +++ b/src/libstd/os/dragonfly/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::dragonfly::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/emscripten/fs.rs b/src/libstd/os/emscripten/fs.rs index 8056ce4fdc4..e0e197dc122 100644 --- a/src/libstd/os/emscripten/fs.rs +++ b/src/libstd/os/emscripten/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::emscripten::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/freebsd/fs.rs b/src/libstd/os/freebsd/fs.rs index 2f17d2f7409..5f24cd636d5 100644 --- a/src/libstd/os/freebsd/fs.rs +++ b/src/libstd/os/freebsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::freebsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/fuchsia/fs.rs b/src/libstd/os/fuchsia/fs.rs index d22f9a628bd..16802576356 100644 --- a/src/libstd/os/fuchsia/fs.rs +++ b/src/libstd/os/fuchsia/fs.rs @@ -13,7 +13,9 @@ use fs::Metadata; use sys_common::AsInner; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { #[stable(feature = "metadata_ext2", since = "1.8.0")] diff --git a/src/libstd/os/haiku/fs.rs b/src/libstd/os/haiku/fs.rs index 54f8ea1b71b..453136e0ac8 100644 --- a/src/libstd/os/haiku/fs.rs +++ b/src/libstd/os/haiku/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::haiku::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/ios/fs.rs b/src/libstd/os/ios/fs.rs index 275daf3d3a0..296ce69ff43 100644 --- a/src/libstd/os/ios/fs.rs +++ b/src/libstd/os/ios/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::ios::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index 2be2fbcb2db..76fb10da850 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::linux::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/macos/fs.rs b/src/libstd/os/macos/fs.rs index 12b44901d03..0b14c05cb55 100644 --- a/src/libstd/os/macos/fs.rs +++ b/src/libstd/os/macos/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::macos::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/netbsd/fs.rs b/src/libstd/os/netbsd/fs.rs index cd7d5fafd1c..e9cad33fee6 100644 --- a/src/libstd/os/netbsd/fs.rs +++ b/src/libstd/os/netbsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::netbsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/openbsd/fs.rs b/src/libstd/os/openbsd/fs.rs index cc812fcf12c..0f6b83b6e32 100644 --- a/src/libstd/os/openbsd/fs.rs +++ b/src/libstd/os/openbsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::openbsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/solaris/fs.rs b/src/libstd/os/solaris/fs.rs index 5dc43d03a86..19dce1ba34c 100644 --- a/src/libstd/os/solaris/fs.rs +++ b/src/libstd/os/solaris/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::solaris::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs index d59b4fc0b70..060edbd22e4 100644 --- a/src/libstd/sys/redox/ext/ffi.rs +++ b/src/libstd/sys/redox/ext/ffi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extension to the primitives in the `std::ffi` module +//! Redox-specific extension to the primitives in the `std::ffi` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -17,7 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Unix-specific extensions to `OsString`. +/// Redox-specific extensions to [`ffi::OsString`]. +/// +/// [`ffi::OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an `OsString` from a byte vector. @@ -39,7 +41,9 @@ impl OsStringExt for OsString { } } -/// Unix-specific extensions to `OsStr`. +/// Redox-specific extensions to [`ffi::OsStr`]. +/// +/// [`ffi::OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 0f4762aa881..b39c6f5d022 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -18,7 +18,9 @@ use path::Path; use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; -/// Redox-specific extensions to `Permissions` +/// Redox-specific extensions to [`fs::Permissions`]. +/// +/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { /// Returns the underlying raw `mode_t` bits that are the standard Redox @@ -95,7 +97,9 @@ impl PermissionsExt for Permissions { } } -/// Redox-specific extensions to `OpenOptions` +/// Redox-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait OpenOptionsExt { /// Sets the mode bits that a new file will be created with. @@ -163,13 +167,9 @@ impl OpenOptionsExt for OpenOptions { } } -// Hm, why are there casts here to the returned type, shouldn't the types always -// be the same? Right you are! Turns out, however, on android at least the types -// in the raw `stat` structure are not the same as the types being returned. Who -// knew! -// -// As a result to make sure this compiles for all platforms we do the manual -// casts and rely on manual lowering to `stat` if the raw type is desired. +/// Redox-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -204,6 +204,13 @@ pub trait MetadataExt { fn blocks(&self) -> u64; } +// Hm, why are there casts here to the returned type, shouldn't the types always +// be the same? Right you are! Turns out, however, on android at least the types +// in the raw `stat` structure are not the same as the types being returned. Who +// knew! +// +// As a result to make sure this compiles for all platforms we do the manual +// casts and rely on manual lowering to `stat` if the raw type is desired. #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for fs::Metadata { fn dev(&self) -> u64 { @@ -253,7 +260,12 @@ impl MetadataExt for fs::Metadata { } } -/// Add special Redox types (block/char device, fifo and socket) +/// Redox-specific extensions for [`fs::FileType`]. +/// +/// Adds support for special Unix file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`fs::FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. @@ -307,8 +319,10 @@ pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> sys::fs::symlink(src.as_ref(), dst.as_ref()) } +/// Redox-specific extensions to [`fs::DirBuilder`]. +/// +/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html #[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for `fs::DirBuilder` for Redox-specific options. pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index e68e180acf1..608740a5cf7 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extensions to primitives in the `std::process` module. +//! Redox-specific extensions to primitives in the `std::process` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -18,7 +18,9 @@ use process; use sys; use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; -/// Unix-specific extensions to the `std::process::Command` builder +/// Redox-specific extensions to the [`process::Command`] builder. +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { /// Sets the child process's user id. This translates to a @@ -107,7 +109,9 @@ impl CommandExt for process::Command { } } -/// Unix-specific extensions to `std::process::ExitStatus` +/// Redox-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of diff --git a/src/libstd/sys/redox/ext/thread.rs b/src/libstd/sys/redox/ext/thread.rs index 52be2ccd9f9..71ff0d46b91 100644 --- a/src/libstd/sys/redox/ext/thread.rs +++ b/src/libstd/sys/redox/ext/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extensions to primitives in the `std::thread` module. +//! Redox-specific extensions to primitives in the `std::thread` module. #![stable(feature = "thread_extensions", since = "1.9.0")] @@ -19,7 +19,9 @@ use thread::JoinHandle; #[allow(deprecated)] pub type RawPthread = usize; -/// Unix-specific extensions to `std::thread::JoinHandle` +/// Redox-specific extensions to [`thread::JoinHandle`]. +/// +/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html #[stable(feature = "thread_extensions", since = "1.9.0")] pub trait JoinHandleExt { /// Extracts the raw pthread_t without taking ownership diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs index fb9984ccbdd..3103ad0416e 100644 --- a/src/libstd/sys/unix/ext/ffi.rs +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -17,7 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Unix-specific extensions to `OsString`. +/// Unix-specific extensions to [`ffi::OsString`]. +/// +/// [`ffi::OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an [`OsString`] from a byte vector. @@ -66,7 +68,9 @@ impl OsStringExt for OsString { } } -/// Unix-specific extensions to `OsStr`. +/// Unix-specific extensions to [`ffi::OsStr`]. +/// +/// [`ffi::OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 3c5b9424fb0..844e0106df0 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -20,9 +20,9 @@ use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; use sys::platform::fs::MetadataExt as UnixMetadataExt; -/// Unix-specific extensions to [`File`]. +/// Unix-specific extensions to [`fs::File`]. /// -/// [`File`]: ../../../../std/fs/struct.File.html +/// [`fs::File`]: ../../../../std/fs/struct.File.html #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Reads a number of bytes starting from a given offset. @@ -105,7 +105,9 @@ impl FileExt for fs::File { } } -/// Unix-specific extensions to `Permissions` +/// Unix-specific extensions to [`fs::Permissions`]. +/// +/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { /// Returns the underlying raw `st_mode` bits that contain the standard @@ -180,7 +182,9 @@ impl PermissionsExt for Permissions { } } -/// Unix-specific extensions to `OpenOptions` +/// Unix-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait OpenOptionsExt { /// Sets the mode bits that a new file will be created with. @@ -246,13 +250,9 @@ impl OpenOptionsExt for OpenOptions { } } -// Hm, why are there casts here to the returned type, shouldn't the types always -// be the same? Right you are! Turns out, however, on android at least the types -// in the raw `stat` structure are not the same as the types being returned. Who -// knew! -// -// As a result to make sure this compiles for all platforms we do the manual -// casts and rely on manual lowering to `stat` if the raw type is desired. +/// Unix-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Returns the ID of the device containing the file. @@ -555,7 +555,12 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } } -/// Add support for special unix types (block/char device, fifo and socket). +/// Unix-specific extensions for [`fs::FileType`]. +/// +/// Adds support for special Unix file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`fs::FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. @@ -701,10 +706,10 @@ pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> sys::fs::symlink(src.as_ref(), dst.as_ref()) } -#[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for [`fs::DirBuilder`] for unix-specific options. +/// Unix-specific extensions to [`fs::DirBuilder`]. /// /// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html +#[stable(feature = "dir_builder", since = "1.6.0")] pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 7b4ec20d91f..21630ae9746 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -18,7 +18,9 @@ use process; use sys; use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; -/// Unix-specific extensions to the `std::process::Command` builder +/// Unix-specific extensions to the [`process::Command`] builder. +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { /// Sets the child process's user id. This translates to a @@ -117,7 +119,9 @@ impl CommandExt for process::Command { } } -/// Unix-specific extensions to `std::process::ExitStatus` +/// Unix-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of diff --git a/src/libstd/sys/unix/ext/thread.rs b/src/libstd/sys/unix/ext/thread.rs index fe2a48764dc..8dadf29945c 100644 --- a/src/libstd/sys/unix/ext/thread.rs +++ b/src/libstd/sys/unix/ext/thread.rs @@ -21,7 +21,9 @@ use thread::JoinHandle; #[allow(deprecated)] pub type RawPthread = pthread_t; -/// Unix-specific extensions to `std::thread::JoinHandle` +/// Unix-specific extensions to [`thread::JoinHandle`]. +/// +/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html #[stable(feature = "thread_extensions", since = "1.9.0")] pub trait JoinHandleExt { /// Extracts the raw pthread_t without taking ownership diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index d6b8896ac09..b3f7635efd3 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -76,7 +76,9 @@ use sys_common::{FromInner, AsInner}; #[stable(feature = "rust1", since = "1.0.0")] pub use sys_common::wtf8::EncodeWide; -/// Windows-specific extensions to `OsString`. +/// Windows-specific extensions to [`ffi::OsString`]. +/// +/// [`ffi::OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of @@ -109,7 +111,9 @@ impl OsStringExt for OsString { } } -/// Windows-specific extensions to `OsStr`. +/// Windows-specific extensions to [`ffi::OsStr`]. +/// +/// [`ffi::OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index e5cd51b6550..5daeb5282cd 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -18,9 +18,9 @@ use path::Path; use sys; use sys_common::{AsInnerMut, AsInner}; -/// Windows-specific extensions to [`File`]. +/// Windows-specific extensions to [`fs::File`]. /// -/// [`File`]: ../../../fs/struct.File.html +/// [`fs::File`]: ../../../fs/struct.File.html #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Seeks to a given position and reads a number of bytes. @@ -103,9 +103,9 @@ impl FileExt for fs::File { } } -/// Windows-specific extensions to [`OpenOptions`]. +/// Windows-specific extensions to [`fs::OpenOptions`]. /// -/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] @@ -281,13 +281,12 @@ impl OpenOptionsExt for OpenOptions { } } -/// Extension methods for [`fs::Metadata`] to access the raw fields contained -/// within. +/// Windows-specific extensions to [`fs::Metadata`]. /// /// The data members that this trait exposes correspond to the members /// of the [`BY_HANDLE_FILE_INFORMATION`] structure. /// -/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html /// [`BY_HANDLE_FILE_INFORMATION`]: /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -445,8 +444,11 @@ impl MetadataExt for Metadata { fn file_size(&self) -> u64 { self.as_inner().size() } } -/// Add support for the Windows specific fact that a symbolic link knows whether it is a file -/// or directory. +/// Windows-specific extensions to [`fs::FileType`]. +/// +/// On Windows, a symbolic link knows whether it is a file or directory. +/// +/// [`fs::FileType`]: ../../../../std/fs/struct.FileType.html #[unstable(feature = "windows_file_type_ext", issue = "0")] pub trait FileTypeExt { /// Returns whether this file type is a symbolic link that is also a directory. diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 759f055c4b1..a02bcbe0c87 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -82,7 +82,9 @@ impl IntoRawHandle for process::ChildStderr { } } -/// Windows-specific extensions to `std::process::ExitStatus` +/// Windows-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "exit_status_from", since = "1.12.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of @@ -98,7 +100,9 @@ impl ExitStatusExt for process::ExitStatus { } } -/// Windows-specific extensions to the `std::process::Command` builder +/// Windows-specific extensions to the [`process::Command`] builder. +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. -- cgit 1.4.1-3-g733a5 From d5bee64df400126279e71562352936d5e4d14433 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 10 Apr 2018 17:03:07 -0700 Subject: Prefer unprefixed paths for well known structs --- src/libstd/sys/redox/ext/ffi.rs | 8 ++++---- src/libstd/sys/redox/ext/fs.rs | 4 ++-- src/libstd/sys/redox/ext/process.rs | 2 +- src/libstd/sys/unix/ext/ffi.rs | 8 ++++---- src/libstd/sys/unix/ext/fs.rs | 8 ++++---- src/libstd/sys/windows/ext/ffi.rs | 8 ++++---- src/libstd/sys/windows/ext/fs.rs | 8 ++++---- 7 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs index 060edbd22e4..cd88c8f46b3 100644 --- a/src/libstd/sys/redox/ext/ffi.rs +++ b/src/libstd/sys/redox/ext/ffi.rs @@ -17,9 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Redox-specific extensions to [`ffi::OsString`]. +/// Redox-specific extensions to [`OsString`]. /// -/// [`ffi::OsString`]: ../../../../std/ffi/struct.OsString.html +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an `OsString` from a byte vector. @@ -41,9 +41,9 @@ impl OsStringExt for OsString { } } -/// Redox-specific extensions to [`ffi::OsStr`]. +/// Redox-specific extensions to [`OsStr`]. /// -/// [`ffi::OsStr`]: ../../../../std/ffi/struct.OsStr.html +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index b39c6f5d022..c1dba6edda4 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -260,12 +260,12 @@ impl MetadataExt for fs::Metadata { } } -/// Redox-specific extensions for [`fs::FileType`]. +/// Redox-specific extensions for [`FileType`]. /// /// Adds support for special Unix file types such as block/character devices, /// pipes, and sockets. /// -/// [`fs::FileType`]: ../../../../std/fs/struct.FileType.html +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index 608740a5cf7..cfb6d5fc703 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -18,7 +18,7 @@ use process; use sys; use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; -/// Redox-specific extensions to the [`process::Command`] builder. +/// Redox-specific extensions to the [`process::Command`] builder, /// /// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs index 3103ad0416e..8347145db5a 100644 --- a/src/libstd/sys/unix/ext/ffi.rs +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -17,9 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Unix-specific extensions to [`ffi::OsString`]. +/// Unix-specific extensions to [`OsString`]. /// -/// [`ffi::OsString`]: ../../../../std/ffi/struct.OsString.html +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an [`OsString`] from a byte vector. @@ -68,9 +68,9 @@ impl OsStringExt for OsString { } } -/// Unix-specific extensions to [`ffi::OsStr`]. +/// Unix-specific extensions to [`OsStr`]. /// -/// [`ffi::OsStr`]: ../../../../std/ffi/struct.OsStr.html +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 844e0106df0..4e981012669 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -20,9 +20,9 @@ use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; use sys::platform::fs::MetadataExt as UnixMetadataExt; -/// Unix-specific extensions to [`fs::File`]. +/// Unix-specific extensions to [`File`]. /// -/// [`fs::File`]: ../../../../std/fs/struct.File.html +/// [`File`]: ../../../../std/fs/struct.File.html #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Reads a number of bytes starting from a given offset. @@ -555,12 +555,12 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } } -/// Unix-specific extensions for [`fs::FileType`]. +/// Unix-specific extensions for [`FileType`]. /// /// Adds support for special Unix file types such as block/character devices, /// pipes, and sockets. /// -/// [`fs::FileType`]: ../../../../std/fs/struct.FileType.html +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index b3f7635efd3..98d43552489 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -76,9 +76,9 @@ use sys_common::{FromInner, AsInner}; #[stable(feature = "rust1", since = "1.0.0")] pub use sys_common::wtf8::EncodeWide; -/// Windows-specific extensions to [`ffi::OsString`]. +/// Windows-specific extensions to [`OsString`]. /// -/// [`ffi::OsString`]: ../../../../std/ffi/struct.OsString.html +/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of @@ -111,9 +111,9 @@ impl OsStringExt for OsString { } } -/// Windows-specific extensions to [`ffi::OsStr`]. +/// Windows-specific extensions to [`OsStr`]. /// -/// [`ffi::OsStr`]: ../../../../std/ffi/struct.OsStr.html +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index 5daeb5282cd..78c9e95a055 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -18,9 +18,9 @@ use path::Path; use sys; use sys_common::{AsInnerMut, AsInner}; -/// Windows-specific extensions to [`fs::File`]. +/// Windows-specific extensions to [`File`]. /// -/// [`fs::File`]: ../../../fs/struct.File.html +/// [`File`]: ../../../fs/struct.File.html #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Seeks to a given position and reads a number of bytes. @@ -444,11 +444,11 @@ impl MetadataExt for Metadata { fn file_size(&self) -> u64 { self.as_inner().size() } } -/// Windows-specific extensions to [`fs::FileType`]. +/// Windows-specific extensions to [`FileType`]. /// /// On Windows, a symbolic link knows whether it is a file or directory. /// -/// [`fs::FileType`]: ../../../../std/fs/struct.FileType.html +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[unstable(feature = "windows_file_type_ext", issue = "0")] pub trait FileTypeExt { /// Returns whether this file type is a symbolic link that is also a directory. -- cgit 1.4.1-3-g733a5 From 7cbeddb7b78cc54a52d63ed8556da7121d1d2e68 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 14 Apr 2018 23:49:37 +0200 Subject: Deprecate Read::chars and char::decode_utf8 Per FCP: * https://github.com/rust-lang/rust/issues/27802#issuecomment-377537778 * https://github.com/rust-lang/rust/issues/33906#issuecomment-377534308 --- src/libcore/char/decode.rs | 11 +++++++++++ src/libcore/char/mod.rs | 3 +++ src/libcore/tests/char.rs | 1 + src/libstd/io/buffered.rs | 2 ++ src/libstd/io/cursor.rs | 2 ++ src/libstd/io/mod.rs | 14 +++++++++++++- 6 files changed, 32 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 48b531104f8..45a73191db2 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -17,11 +17,17 @@ use super::from_u32_unchecked; /// An iterator over an iterator of bytes of the characters the bytes represent /// as UTF-8 #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(Clone, Debug)] +#[allow(deprecated)] pub struct DecodeUtf8>(::iter::Peekable); /// Decodes an `Iterator` of bytes as UTF-8. #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[allow(deprecated)] #[inline] pub fn decode_utf8>(i: I) -> DecodeUtf8 { DecodeUtf8(i.into_iter().peekable()) @@ -29,10 +35,14 @@ pub fn decode_utf8>(i: I) -> DecodeUtf8 /// `::next` returns this for an invalid input sequence. #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(PartialEq, Eq, Debug)] +#[allow(deprecated)] pub struct InvalidSequence(()); #[unstable(feature = "decode_utf8", issue = "33906")] +#[allow(deprecated)] impl> Iterator for DecodeUtf8 { type Item = Result; #[inline] @@ -127,6 +137,7 @@ impl> Iterator for DecodeUtf8 { } #[unstable(feature = "decode_utf8", issue = "33906")] +#[allow(deprecated)] impl> FusedIterator for DecodeUtf8 {} /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 9edc0c88756..bfe05af3c1c 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -51,6 +51,9 @@ pub use unicode::tables::UNICODE_VERSION; #[unstable(feature = "unicode_version", issue = "49726")] pub use unicode::version::UnicodeVersion; #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[allow(deprecated)] pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; use fmt::{self, Write}; diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index 4e10ceac878..ab90763abf8 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -364,6 +364,7 @@ fn eu_iterator_specializations() { } #[test] +#[allow(deprecated)] fn test_decode_utf8() { macro_rules! assert_decode_utf8 { ($input_bytes: expr, $expected_str: expr) => { diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index d6eac748334..ee297d3783e 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -1251,6 +1251,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn read_char_buffered() { let buf = [195, 159]; let reader = BufReader::with_capacity(1, &buf[..]); @@ -1258,6 +1259,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_chars() { let buf = [195, 159, b'a']; let reader = BufReader::with_capacity(1, &buf[..]); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 2673f3ccfa3..8ac52572810 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -566,6 +566,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_read_char() { let b = &b"Vi\xE1\xBB\x87t"[..]; let mut c = Cursor::new(b).chars(); @@ -577,6 +578,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_read_bad_char() { let b = &b"\x80"[..]; let mut c = Cursor::new(b).chars(); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b02e133ee4d..eba4e9fe703 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -840,6 +840,9 @@ pub trait Read { of where errors happen is currently \ unclear and may change", issue = "27802")] + #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] + #[allow(deprecated)] fn chars(self) -> Chars where Self: Sized { Chars { inner: self } } @@ -2010,16 +2013,22 @@ impl Iterator for Bytes { /// [chars]: trait.Read.html#method.chars #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(Debug)] +#[allow(deprecated)] pub struct Chars { inner: R, } /// An enumeration of possible errors that can be generated from the `Chars` /// adapter. -#[derive(Debug)] #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[derive(Debug)] +#[allow(deprecated)] pub enum CharsError { /// Variant representing that the underlying stream was read successfully /// but it did not contain valid utf8 data. @@ -2031,6 +2040,7 @@ pub enum CharsError { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl Iterator for Chars { type Item = result::Result; @@ -2063,6 +2073,7 @@ impl Iterator for Chars { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl std_error::Error for CharsError { fn description(&self) -> &str { match *self { @@ -2080,6 +2091,7 @@ impl std_error::Error for CharsError { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl fmt::Display for CharsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { -- cgit 1.4.1-3-g733a5 From 20a795e6c6be5b27e16df257f104f5f26ab730e9 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sun, 15 Apr 2018 17:07:39 -0400 Subject: Mention Result in never docs. --- src/libstd/primitive_docs.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index ce4bbfffc2e..8905f7c9e16 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -112,6 +112,8 @@ mod prim_bool { } /// /// # `!` and generics /// +/// ## Infalliable errors +/// /// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] /// trait: /// @@ -140,9 +142,59 @@ mod prim_bool { } /// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain /// enum variants from generic types like `Result`. /// +/// ## Infinite loops +/// +/// While [`Result`] is very useful for removing errors, `!` can also be used to removed +/// successes as well. If we think of [`Result`] as "if this function returns, it has not +/// errored," we get a very intuitive idea of [`Result`] as well: if the function returns, it +/// *has* errored. +/// +/// For example, consider the case of a simple web server, which can be simplified to: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// let (client, request) = get_request().expect("disconnected"); +/// let response = request.process(); +/// response.send(client); +/// } +/// ``` +/// +/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection. +/// Instead, we'd like to keep track of this error, like this: +/// +/// ```ignore (hypothetical-example) +/// loop { +/// match get_request() { +/// Err(err) => break err, +/// Ok((client, request)) => { +/// let response = request.process(); +/// response.send(client); +/// }, +/// } +/// } +/// ``` +/// +/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it +/// might be intuitive to simply return the error, we might want to wrap it in a [`Result`] +/// instead: +/// +/// ```ignore (hypothetical-example) +/// fn server_loop() -> Result { +/// Ok(loop { +/// let (client, request) = get_request()?; +/// let response = request.process(); +/// response.send(client); +/// }) +/// } +/// ``` +/// +/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop +/// ever stops, it means that an error occurred. +/// /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str /// [`Result`]: result/enum.Result.html /// [`Result`]: result/enum.Result.html +/// [`Result`]: result/enum.Result.html /// [`Ok`]: result/enum.Result.html#variant.Ok /// [`String`]: string/struct.String.html /// [`Err`]: result/enum.Result.html#variant.Err -- cgit 1.4.1-3-g733a5 From 5fe8c59f1219705ea54f842f9868ad0017643a33 Mon Sep 17 00:00:00 2001 From: kennytm Date: Thu, 12 Apr 2018 21:47:38 +0800 Subject: Stabilize core::hint::unreachable_unchecked. Closes #43751. --- src/libcore/hint.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++++ src/libcore/intrinsics.rs | 3 +++ src/libcore/lib.rs | 1 + src/libcore/macros.rs | 8 +++---- src/libcore/mem.rs | 12 ---------- src/libstd/lib.rs | 2 ++ 6 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 src/libcore/hint.rs (limited to 'src/libstd') diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs new file mode 100644 index 00000000000..f4e96e67b2c --- /dev/null +++ b/src/libcore/hint.rs @@ -0,0 +1,61 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "core_hint", since = "1.27.0")] + +//! Hints to compiler that affects how code should be emitted or optimized. + +use intrinsics; + +/// Informs the compiler that this point in the code is not reachable, enabling +/// further optimizations. +/// +/// # Safety +/// +/// Reaching this function is completely *undefined behavior* (UB). In +/// particular, the compiler assumes that all UB must never happen, and +/// therefore will eliminate all branches that reach to a call to +/// `unreachable_unchecked()`. +/// +/// Like all instances of UB, if this assumption turns out to be wrong, i.e. the +/// `unreachable_unchecked()` call is actually reachable among all possible +/// control flow, the compiler will apply the wrong optimization strategy, and +/// may sometimes even corrupt seemingly unrelated code, causing +/// difficult-to-debug problems. +/// +/// Use this function only when you can prove that the code will never call it. +/// +/// The [`unreachable!()`] macro is the safe counterpart of this function, which +/// will panic instead when executed. +/// +/// [`unreachable!()`]: ../macro.unreachable.html +/// +/// # Example +/// +/// ``` +/// fn div_1(a: u32, b: u32) -> u32 { +/// use std::hint::unreachable_unchecked; +/// +/// // `b.saturating_add(1)` is always positive (not zero), +/// // hence `checked_div` will never return None. +/// // Therefore, the else branch is unreachable. +/// a.checked_div(b.saturating_add(1)) +/// .unwrap_or_else(|| unsafe { unreachable_unchecked() }) +/// } +/// +/// assert_eq!(div_1(7, 0), 7); +/// assert_eq!(div_1(9, 1), 4); +/// assert_eq!(div_1(11, std::u32::MAX), 0); +/// ``` +#[inline] +#[stable(feature = "unreachable", since = "1.27.0")] +pub unsafe fn unreachable_unchecked() -> ! { + intrinsics::unreachable() +} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 83274682250..fb0d2d9c882 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -638,6 +638,9 @@ extern "rust-intrinsic" { /// NB: This is very different from the `unreachable!()` macro: Unlike the /// macro, which panics when it is executed, it is *undefined behavior* to /// reach code marked with this function. + /// + /// The stabilized version of this intrinsic is + /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html). pub fn unreachable() -> !; /// Informs the optimizer that a condition is always true. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5ebd9e4334c..1968c11d062 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -149,6 +149,7 @@ pub mod intrinsics; pub mod mem; pub mod nonzero; pub mod ptr; +pub mod hint; /* Core language traits */ diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 90a9cb3379b..1e2551e36f5 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -420,13 +420,13 @@ macro_rules! writeln { /// * Iterators that dynamically terminate. /// /// If the determination that the code is unreachable proves incorrect, the -/// program immediately terminates with a [`panic!`]. The function [`unreachable`], -/// which belongs to the [`std::intrinsics`] module, informs the compilier to +/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`], +/// which belongs to the [`std::hint`] module, informs the compilier to /// optimize the code out of the release version entirely. /// /// [`panic!`]: ../std/macro.panic.html -/// [`unreachable`]: ../std/intrinsics/fn.unreachable.html -/// [`std::intrinsics`]: ../std/intrinsics/index.html +/// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html +/// [`std::hint`]: ../std/hint/index.html /// /// # Panics /// diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e3f08926610..10efab82ddf 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1094,18 +1094,6 @@ impl ::hash::Hash for ManuallyDrop { } } -/// Tells LLVM that this point in the code is not reachable, enabling further -/// optimizations. -/// -/// NB: This is very different from the `unreachable!()` macro: Unlike the -/// macro, which panics when it is executed, it is *undefined behavior* to -/// reach code marked with this function. -#[inline] -#[unstable(feature = "unreachable", issue = "43751")] -pub unsafe fn unreachable() -> ! { - intrinsics::unreachable() -} - /// A pinned reference. /// /// A pinned reference is a lot like a mutable reference, except that it is not diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a34fcb5a7f9..d92a4526549 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -457,6 +457,8 @@ pub use alloc_crate::vec; pub use core::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; +#[stable(feature = "core_hint", since = "1.27.0")] +pub use core::hint; pub mod f32; pub mod f64; -- cgit 1.4.1-3-g733a5 From 598d836fff59787892de1d736e521b10d9117531 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Apr 2018 11:11:49 -0700 Subject: Stabilize x86/x86_64 SIMD This commit stabilizes the SIMD in Rust for the x86/x86_64 platforms. Notably this commit is stabilizing: * The `std::arch::{x86, x86_64}` modules and the intrinsics contained inside. * The `is_x86_feature_detected!` macro in the standard library * The `#[target_feature(enable = "...")]` attribute * The `#[cfg(target_feature = "...")]` matcher Stabilization of the module and intrinsics were primarily done in rust-lang-nursery/stdsimd#414 and the two attribute stabilizations are done in this commit. The standard library is also tweaked a bit with the new way that stdsimd is integrated. Note that other architectures like `std::arch::arm` are not stabilized as part of this commit, they will likely stabilize in the future after they've been implemented and fleshed out. Similarly the `std::simd` module is also not being stabilized in this commit, only `std::arch`. Finally, nothing related to `__m64` is stabilized in this commit either (MMX), only SSE and up types and intrinsics are stabilized. Closes #29717 Closes #44839 Closes #48556 --- .gitmodules | 2 +- src/libcore/lib.rs | 21 +++++++++++-- src/libstd/lib.rs | 2 +- src/libsyntax/feature_gate.rs | 16 ++++------ src/stdsimd | 2 +- src/test/ui/feature-gate-cfg-target-feature.rs | 21 ------------- src/test/ui/feature-gate-cfg-target-feature.stderr | 35 ---------------------- src/test/ui/feature-gate-target_feature.rs | 13 -------- src/test/ui/feature-gate-target_feature.stderr | 11 ------- 9 files changed, 26 insertions(+), 97 deletions(-) delete mode 100644 src/test/ui/feature-gate-cfg-target-feature.rs delete mode 100644 src/test/ui/feature-gate-cfg-target-feature.stderr delete mode 100644 src/test/ui/feature-gate-target_feature.rs delete mode 100644 src/test/ui/feature-gate-target_feature.stderr (limited to 'src/libstd') diff --git a/.gitmodules b/.gitmodules index 55f586389b1..1d56c0c637a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,7 +49,7 @@ url = https://github.com/rust-lang/llvm [submodule "src/stdsimd"] path = src/stdsimd - url = https://github.com/rust-lang-nursery/stdsimd + url = https://github.com/alexcrichton/stdsimd [submodule "src/tools/lld"] path = src/tools/lld url = https://github.com/rust-lang/lld.git diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5ebd9e4334c..d6861922f86 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -68,7 +68,6 @@ #![feature(asm)] #![feature(associated_type_defaults)] #![feature(attr_literals)] -#![feature(cfg_target_feature)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] @@ -96,11 +95,13 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] -#![feature(target_feature)] #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![cfg_attr(stage0, feature(target_feature))] +#![cfg_attr(stage0, feature(cfg_target_feature))] + #[prelude_import] #[allow(unused)] use prelude::v1::*; @@ -204,6 +205,20 @@ mod unit; // things like SIMD and such. Note that the actual source for all this lies in a // different repository, rust-lang-nursery/stdsimd. That's why the setup here is // a bit wonky. +#[allow(unused_macros)] +macro_rules! test_v16 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v32 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v64 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v128 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v256 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! test_v512 { ($item:item) => {}; } +#[allow(unused_macros)] +macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } } #[path = "../stdsimd/coresimd/mod.rs"] #[allow(missing_docs, missing_debug_implementations, dead_code)] #[unstable(feature = "stdsimd", issue = "48556")] @@ -213,6 +228,6 @@ mod coresimd; #[unstable(feature = "stdsimd", issue = "48556")] #[cfg(not(stage0))] pub use coresimd::simd; -#[unstable(feature = "stdsimd", issue = "48556")] +#[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(not(stage0))] pub use coresimd::arch; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a34fcb5a7f9..01de49ef5df 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -525,7 +525,7 @@ mod coresimd { #[unstable(feature = "stdsimd", issue = "48556")] #[cfg(all(not(stage0), not(test)))] pub use stdsimd::simd; -#[unstable(feature = "stdsimd", issue = "48556")] +#[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(all(not(stage0), not(test)))] pub use stdsimd::arch; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 73ebfc20876..ab3364a18ec 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -231,9 +231,6 @@ declare_features! ( // allow `repr(simd)`, and importing the various simd intrinsics (active, repr_simd, "1.4.0", Some(27731), None), - // Allows cfg(target_feature = "..."). - (active, cfg_target_feature, "1.4.0", Some(29717), None), - // allow `extern "platform-intrinsic" { ... }` (active, platform_intrinsics, "1.4.0", Some(27731), None), @@ -293,9 +290,6 @@ declare_features! ( (active, use_extern_macros, "1.15.0", Some(35896), None), - // Allows #[target_feature(...)] - (active, target_feature, "1.15.0", None, None), - // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None, None), @@ -574,6 +568,10 @@ declare_features! ( (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) (accepted, generic_param_attrs, "1.26.0", Some(48848), None), + // Allows cfg(target_feature = "..."). + (accepted, cfg_target_feature, "1.27.0", Some(29717), None), + // Allows #[target_feature(...)] + (accepted, target_feature, "1.27.0", None, None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -918,10 +916,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "the `#[naked]` attribute \ is an experimental feature", cfg_fn!(naked_functions))), - ("target_feature", Whitelisted, Gated( - Stability::Unstable, "target_feature", - "the `#[target_feature]` attribute is an experimental feature", - cfg_fn!(target_feature))), + ("target_feature", Normal, Ungated), ("export_name", Whitelisted, Ungated), ("inline", Whitelisted, Ungated), ("link", Whitelisted, Ungated), @@ -1052,7 +1047,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG // cfg(...)'s that are feature gated const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[ // (name in cfg, feature, function to check if the feature is enabled) - ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)), ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), diff --git a/src/stdsimd b/src/stdsimd index bcb720e5586..01ed2bb1dea 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit bcb720e55861c38db47f2ebdf26b7198338cb39d +Subproject commit 01ed2bb1dea492324fbe21c3069cb8efacb14ec0 diff --git a/src/test/ui/feature-gate-cfg-target-feature.rs b/src/test/ui/feature-gate-cfg-target-feature.rs deleted file mode 100644 index 7832e1c7c51..00000000000 --- a/src/test/ui/feature-gate-cfg-target-feature.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental -#[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental -struct Foo(u64, u64); - -#[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental -fn foo() {} - -fn main() { - cfg!(target_feature = "x"); - //~^ ERROR `cfg(target_feature)` is experimental and subject to change -} diff --git a/src/test/ui/feature-gate-cfg-target-feature.stderr b/src/test/ui/feature-gate-cfg-target-feature.stderr deleted file mode 100644 index bf9e596e71a..00000000000 --- a/src/test/ui/feature-gate-cfg-target-feature.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:12:12 - | -LL | #[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:11:7 - | -LL | #[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:15:19 - | -LL | #[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717) - --> $DIR/feature-gate-cfg-target-feature.rs:19:10 - | -LL | cfg!(target_feature = "x"); - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(cfg_target_feature)] to the crate attributes to enable - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-target_feature.rs b/src/test/ui/feature-gate-target_feature.rs deleted file mode 100644 index da2e41a0f5e..00000000000 --- a/src/test/ui/feature-gate-target_feature.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[target_feature = "+sse2"] -//~^ the `#[target_feature]` attribute is an experimental feature -fn foo() {} diff --git a/src/test/ui/feature-gate-target_feature.stderr b/src/test/ui/feature-gate-target_feature.stderr deleted file mode 100644 index 0f31abf7b42..00000000000 --- a/src/test/ui/feature-gate-target_feature.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: the `#[target_feature]` attribute is an experimental feature - --> $DIR/feature-gate-target_feature.rs:11:1 - | -LL | #[target_feature = "+sse2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(target_feature)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From b2192ae157eab3b83d7cbc42d2e08925cbdfd8b6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 1 Apr 2018 21:06:35 +0200 Subject: Add rustdoc-ui test suite --- src/bootstrap/builder.rs | 2 +- src/bootstrap/test.rs | 28 ++++++++++---- src/librustdoc/html/render.rs | 2 +- src/libstd/lib.rs | 4 +- src/libtest/lib.rs | 1 - src/test/rustdoc-ui/intra-links-warning.rs | 19 ++++++++++ src/test/rustdoc-ui/intra-links-warning.stderr | 6 +++ src/tools/compiletest/src/main.rs | 6 ++- src/tools/compiletest/src/runtest.rs | 51 ++++++++++++++++---------- 9 files changed, 85 insertions(+), 34 deletions(-) create mode 100644 src/test/rustdoc-ui/intra-links-warning.rs create mode 100644 src/test/rustdoc-ui/intra-links-warning.stderr (limited to 'src/libstd') diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7ff64af9196..d30933d2efd 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -326,7 +326,7 @@ impl<'a> Builder<'a> { test::TheBook, test::UnstableBook, test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme, // Run run-make last, since these won't pass without make on Windows - test::RunMake), + test::RunMake, test::RustdocUi), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e7610976f8e..992dec5217d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -886,8 +886,12 @@ impl Step for Compiletest { cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target)); cmd.arg("--rustc-path").arg(builder.rustc(compiler)); + let is_rustdoc_ui = suite.ends_with("rustdoc-ui"); + // Avoid depending on rustdoc when we don't need it. - if mode == "rustdoc" || (mode == "run-make" && suite.ends_with("fulldeps")) { + if mode == "rustdoc" || + (mode == "run-make" && suite.ends_with("fulldeps")) || + (mode == "ui" && is_rustdoc_ui) { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); } @@ -903,14 +907,24 @@ impl Step for Compiletest { cmd.arg("--nodejs").arg(nodejs); } - let mut flags = vec!["-Crpath".to_string()]; - if build.config.rust_optimize_tests { - flags.push("-O".to_string()); + let mut flags = if is_rustdoc_ui { + Vec::new() + } else { + vec!["-Crpath".to_string()] + }; + if !is_rustdoc_ui { + if build.config.rust_optimize_tests { + flags.push("-O".to_string()); + } + if build.config.rust_debuginfo_tests { + flags.push("-g".to_string()); + } } - if build.config.rust_debuginfo_tests { - flags.push("-g".to_string()); + if !is_rustdoc_ui { + flags.push("-Zmiri -Zunstable-options".to_string()); + } else { + flags.push("-Zunstable-options".to_string()); } - flags.push("-Zunstable-options".to_string()); flags.push(build.config.cmd.rustc_args().join(" ")); if let Some(linker) = build.linker(target) { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9e2c7bd7ef1..abeaef723d4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -107,7 +107,7 @@ pub struct SharedContext { /// This describes the layout of each page, and is not modified after /// creation of the context (contains info like the favicon and added html). pub layout: layout::Layout, - /// This flag indicates whether [src] links should be generated or not. If + /// This flag indicates whether `[src]` links should be generated or not. If /// the source files are present in the html rendering, then this will be /// `true`. pub include_sources: bool, diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a34fcb5a7f9..3242e136ff3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -44,10 +44,10 @@ //! //! Once you are familiar with the contents of the standard library you may //! begin to find the verbosity of the prose distracting. At this stage in your -//! development you may want to press the **[-]** button near the top of the +//! development you may want to press the `[-]` button near the top of the //! page to collapse it into a more skimmable view. //! -//! While you are looking at that **[-]** button also notice the **[src]** +//! While you are looking at that `[-]` button also notice the `[src]` //! button. Rust's API documentation comes with the source code and you are //! encouraged to read it. The standard library source is generally high //! quality and a peek behind the curtains is often enlightening. diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 9291eaa910b..a4d1797c3ec 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -1288,7 +1288,6 @@ fn get_concurrency() -> usize { pub fn filter_tests(opts: &TestOpts, tests: Vec) -> Vec { let mut filtered = tests; - // Remove tests that don't match the test filter filtered = match opts.filter { None => filtered, diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-links-warning.rs new file mode 100644 index 00000000000..36bcc307d55 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-warning.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(warnings)] + +// must-compile-successfully + +//! Test with [Foo::baz], [Bar::foo], [Uniooon::X] + +pub struct Foo { + pub bar: usize, +} diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr new file mode 100644 index 00000000000..67d7bdd02b3 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -0,0 +1,6 @@ +warning: [Foo::baz] cannot be resolved, ignoring it... + +warning: [Bar::foo] cannot be resolved, ignoring it... + +warning: [Uniooon::X] cannot be resolved, ignoring it... + diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 80cab96434b..ae4f4aa4046 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -283,6 +283,8 @@ pub fn parse_config(args: Vec) -> Config { ), }; + let src_base = opt_path(matches, "src-base"); + let run_ignored = matches.opt_present("ignored"); Config { compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), @@ -293,7 +295,7 @@ pub fn parse_config(args: Vec) -> Config { valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), llvm_filecheck: matches.opt_str("llvm-filecheck").map(|s| PathBuf::from(&s)), - src_base: opt_path(matches, "src-base"), + src_base, build_base: opt_path(matches, "build-base"), stage_id: matches.opt_str("stage-id").unwrap(), mode: matches @@ -301,7 +303,7 @@ pub fn parse_config(args: Vec) -> Config { .unwrap() .parse() .expect("invalid mode"), - run_ignored: matches.opt_present("ignored"), + run_ignored, filter: matches.free.first().cloned(), filter_exact: matches.opt_present("exact"), logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index db0ac927904..9fa176aa68c 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1288,7 +1288,9 @@ impl<'test> TestCx<'test> { // want to actually assert warnings about all this code. Instead // let's just ignore unused code warnings by defaults and tests // can turn it back on if needed. - rustc.args(&["-A", "unused"]); + if !self.config.src_base.ends_with("rustdoc-ui") { + rustc.args(&["-A", "unused"]); + } } _ => {} } @@ -1582,7 +1584,12 @@ impl<'test> TestCx<'test> { } fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command { - let mut rustc = Command::new(&self.config.rustc_path); + let is_rustdoc = self.config.src_base.ends_with("rustdoc-ui"); + let mut rustc = if !is_rustdoc { + Command::new(&self.config.rustc_path) + } else { + Command::new(&self.config.rustdoc_path.clone().expect("no rustdoc built yet")) + }; rustc.arg(input_file).arg("-L").arg(&self.config.build_base); // Optionally prevent default --target if specified in test compile-flags. @@ -1605,17 +1612,19 @@ impl<'test> TestCx<'test> { rustc.args(&["--cfg", revision]); } - if let Some(ref incremental_dir) = self.props.incremental_dir { - rustc.args(&[ - "-C", - &format!("incremental={}", incremental_dir.display()), - ]); - rustc.args(&["-Z", "incremental-verify-ich"]); - rustc.args(&["-Z", "incremental-queries"]); - } + if !is_rustdoc { + if let Some(ref incremental_dir) = self.props.incremental_dir { + rustc.args(&[ + "-C", + &format!("incremental={}", incremental_dir.display()), + ]); + rustc.args(&["-Z", "incremental-verify-ich"]); + rustc.args(&["-Z", "incremental-queries"]); + } - if self.config.mode == CodegenUnits { - rustc.args(&["-Z", "human_readable_cgu_names"]); + if self.config.mode == CodegenUnits { + rustc.args(&["-Z", "human_readable_cgu_names"]); + } } match self.config.mode { @@ -1668,11 +1677,12 @@ impl<'test> TestCx<'test> { } } - - if self.config.target == "wasm32-unknown-unknown" { - // rustc.arg("-g"); // get any backtrace at all on errors - } else if !self.props.no_prefer_dynamic { - rustc.args(&["-C", "prefer-dynamic"]); + if !is_rustdoc { + if self.config.target == "wasm32-unknown-unknown" { + // rustc.arg("-g"); // get any backtrace at all on errors + } else if !self.props.no_prefer_dynamic { + rustc.args(&["-C", "prefer-dynamic"]); + } } match output_file { @@ -1696,8 +1706,10 @@ impl<'test> TestCx<'test> { } else { rustc.args(self.split_maybe_args(&self.config.target_rustcflags)); } - if let Some(ref linker) = self.config.linker { - rustc.arg(format!("-Clinker={}", linker)); + if !is_rustdoc { + if let Some(ref linker) = self.config.linker { + rustc.arg(format!("-Clinker={}", linker)); + } } rustc.args(&self.props.compile_flags); @@ -2509,7 +2521,6 @@ impl<'test> TestCx<'test> { .compile_flags .iter() .any(|s| s.contains("--error-format")); - let proc_res = self.compile_test(); self.check_if_test_should_compile(&proc_res); -- cgit 1.4.1-3-g733a5 From 05275dafaaa602fe4a5d275ef724ced39d30465f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 15 Apr 2018 16:17:18 +0200 Subject: Remove unwanted auto-linking and update --- src/libcore/iter/iterator.rs | 2 +- src/libcore/str/pattern.rs | 2 +- src/librustc/ty/sty.rs | 2 +- src/libstd/ffi/os_str.rs | 5 +++-- src/libstd/macros.rs | 4 ++-- src/libsyntax_pos/hygiene.rs | 4 ++-- src/libunwind/macros.rs | 4 ++-- src/test/run-pass/issue-16819.rs | 2 +- src/test/rustdoc-ui/intra-links-warning.rs | 2 +- 9 files changed, 14 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 4ccf446aa63..6a77de2c986 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -998,7 +998,7 @@ pub trait Iterator { /// an extra layer of indirection. `flat_map()` will remove this extra layer /// on its own. /// - /// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent + /// You can think of `flat_map(f)` as the semantic equivalent /// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`. /// /// Another way of thinking about `flat_map()`: [`map`]'s closure returns diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 95bb8f18947..464d57a2702 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -258,7 +258,7 @@ pub struct CharSearcher<'a> { /// `finger` is the current byte index of the forward search. /// Imagine that it exists before the byte at its index, i.e. - /// haystack[finger] is the first byte of the slice we must inspect during + /// `haystack[finger]` is the first byte of the slice we must inspect during /// forward searching finger: usize, /// `finger_back` is the current byte index of the reverse search. diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d68393956ef..310fcbcfcb3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1550,7 +1550,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - /// Returns the type of ty[i] + /// Returns the type of `ty[i]`. pub fn builtin_index(&self) -> Option> { match self.sty { TyArray(ty, _) | TySlice(ty) => Some(ty), diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 7520121a8c2..4850ed0c5be 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -61,7 +61,7 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// # Conversions /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsString` implements for conversions from/to native representations. +/// the traits which `OsString` implements for [conversions] from/to native representations. /// /// [`OsStr`]: struct.OsStr.html /// [`&OsStr`]: struct.OsStr.html @@ -74,6 +74,7 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// [`new`]: #method.new /// [`push`]: #method.push /// [`as_os_str`]: #method.as_os_str +/// [conversions]: index.html#conversions #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -89,7 +90,7 @@ pub struct OsString { /// references; the latter are owned strings. /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -/// the traits which `OsStr` implements for conversions from/to native representations. +/// the traits which `OsStr` implements for [conversions] from/to native representations. /// /// [`OsString`]: struct.OsString.html /// [`&str`]: ../primitive.str.html diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 5ef7c159655..6902ec82047 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -787,13 +787,13 @@ pub mod builtin { } } -/// A macro for defining #[cfg] if-else statements. +/// A macro for defining `#[cfg]` if-else statements. /// /// This is similar to the `if/elif` C preprocessor macro by allowing definition /// of a cascade of `#[cfg]` cases, emitting the implementation which matches /// first. /// -/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code /// without having to rewrite each clause multiple times. macro_rules! cfg_if { ($( diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 8cb5776fdeb..5e96b5ce673 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Machinery for hygienic macros, inspired by the MTWT[1] paper. +//! Machinery for hygienic macros, inspired by the `MTWT[1]` paper. //! -//! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012. +//! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012. //! *Macros that work together: Compile-time bindings, partial expansion, //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 diff --git a/src/libunwind/macros.rs b/src/libunwind/macros.rs index 26376a3733f..a962d5fc415 100644 --- a/src/libunwind/macros.rs +++ b/src/libunwind/macros.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// A macro for defining #[cfg] if-else statements. +/// A macro for defining `#[cfg]` if-else statements. /// /// This is similar to the `if/elif` C preprocessor macro by allowing definition /// of a cascade of `#[cfg]` cases, emitting the implementation which matches /// first. /// -/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code /// without having to rewrite each clause multiple times. macro_rules! cfg_if { ($( diff --git a/src/test/run-pass/issue-16819.rs b/src/test/run-pass/issue-16819.rs index fb35ce33157..ecd8a3390b7 100644 --- a/src/test/run-pass/issue-16819.rs +++ b/src/test/run-pass/issue-16819.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//`#[cfg]` on struct field permits empty unusable struct +// `#[cfg]` on struct field permits empty unusable struct struct S { #[cfg(untrue)] diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-links-warning.rs index 9a3709b0dd8..2a00d31e3d7 100644 --- a/src/test/rustdoc-ui/intra-links-warning.rs +++ b/src/test/rustdoc-ui/intra-links-warning.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// must-compile-successfully +// compile-pass //! Test with [Foo::baz], [Bar::foo], [Uniooon::X] -- cgit 1.4.1-3-g733a5 From b84baf23788e96a1d79de543eb264ff7d2334c63 Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 00:59:16 -0400 Subject: stabilize `nonnull_cast` feature --- src/liballoc/lib.rs | 1 - src/libcore/ptr.rs | 2 +- src/libstd/lib.rs | 1 - src/test/run-pass/realloc-16687.rs | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f2a61bda4aa..163aef61b43 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -99,7 +99,6 @@ #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] -#![feature(nonnull_cast)] #![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f953b29fdc8..74bb264cc67 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2742,7 +2742,7 @@ impl NonNull { } /// Cast to a pointer of another type - #[unstable(feature = "nonnull_cast", issue = "47653")] + #[stable(feature = "nonnull_cast", since = "1.27.0")] pub fn cast(self) -> NonNull { unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index dd96c57538c..63e4a17d32e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,7 +275,6 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] -#![feature(nonnull_cast)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 38cc23c16a9..afa3494c389 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -13,7 +13,7 @@ // Ideally this would be revised to use no_std, but for now it serves // well enough to reproduce (and illustrate) the bug from #16687. -#![feature(heap_api, allocator_api, nonnull_cast)] +#![feature(heap_api, allocator_api)] use std::alloc::{Global, Alloc, Layout}; use std::ptr::{self, NonNull}; -- cgit 1.4.1-3-g733a5 From fd042eee0002bc2640447c08034de00171ca1aa3 Mon Sep 17 00:00:00 2001 From: tinaun Date: Tue, 17 Apr 2018 01:06:29 -0400 Subject: stabilize `hash_map_remove_entry` feature --- src/libstd/collections/hash/map.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 20a4f9b508d..14ef8563bb0 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1379,7 +1379,6 @@ impl HashMap /// # Examples /// /// ``` - /// #![feature(hash_map_remove_entry)] /// use std::collections::HashMap; /// /// # fn main() { @@ -1389,7 +1388,7 @@ impl HashMap /// assert_eq!(map.remove(&1), None); /// # } /// ``` - #[unstable(feature = "hash_map_remove_entry", issue = "46344")] + #[stable(feature = "hash_map_remove_entry", since = "1.27.0")] pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> where K: Borrow, Q: Hash + Eq -- cgit 1.4.1-3-g733a5 From bc4bd5642ab7ccfdaf84c95c8b62f620acbca644 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Tue, 17 Apr 2018 08:00:48 +0100 Subject: fixup! std: Child::kill() returns error if process has already exited --- src/libstd/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 60759de8afc..431226453ff 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1121,7 +1121,7 @@ impl ExitCode { } impl Child { - /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] + /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] /// error is returned. /// /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function, -- cgit 1.4.1-3-g733a5 From c7f3621f0e9e6ca617ff5debc634e1e16d0a662f Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Fri, 16 Feb 2018 15:41:24 -0500 Subject: The prior check causes abstract unix domain sockets to return unnamed on Android. Signed-off-by: Nicholas Rishel --- src/libstd/sys/unix/ext/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index ba80cbe47c8..2010b0218db 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -214,7 +214,7 @@ impl SocketAddr { let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) { + if len == 0 || (cfg!(not(any(target_os = "linux", target_os = "android"))) && self.addr.sun_path[0] == 0) { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { AddressKind::Abstract(&path[1..len]) -- cgit 1.4.1-3-g733a5 From da6142c81057342d8d6686ae4078995aab73b5bc Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Thu, 19 Apr 2018 17:27:05 -0400 Subject: Rustfmt result (for relevant changes) to satisfy Travis line length check. Signed-off-by: Nicholas Rishel --- src/libstd/sys/unix/ext/net.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 2010b0218db..e277b1aa7b5 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -214,7 +214,10 @@ impl SocketAddr { let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 || (cfg!(not(any(target_os = "linux", target_os = "android"))) && self.addr.sun_path[0] == 0) { + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { AddressKind::Abstract(&path[1..len]) -- cgit 1.4.1-3-g733a5 From ca79ba300a0934864d6ea520f9424d5f08ece687 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 19 Apr 2018 15:52:14 -0700 Subject: Tweak some stabilizations in libstd This commit tweaks a few stable APIs in the `beta` branch before they hit stable. The `str::is_whitespace` and `str::is_alphanumeric` functions were deleted (added in #49381, issue at #49657). The `and_modify` APIs added in #44734 were altered to take a `FnOnce` closure rather than a `FnMut` closure. Closes #49581 Closes #49657 --- src/liballoc/btree/map.rs | 4 ++-- src/liballoc/str.rs | 42 -------------------------------------- src/librustdoc/test.rs | 2 +- src/libstd/collections/hash/map.rs | 4 ++-- 4 files changed, 5 insertions(+), 47 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 82cbec0517e..3984379ea86 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -2155,8 +2155,8 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 43); /// ``` #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify(self, mut f: F) -> Self - where F: FnMut(&mut V) + pub fn and_modify(self, f: F) -> Self + where F: FnOnce(&mut V) { match self { Occupied(mut entry) => { diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 0e708465332..686a0408a7c 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -2140,48 +2140,6 @@ impl str { unsafe { String::from_utf8_unchecked(buf) } } - /// Returns true if this `str` is entirely whitespace, and false otherwise. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived Core - /// Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(" \t ".is_whitespace()); - /// - /// // a non-breaking space - /// assert!("\u{A0}".is_whitespace()); - /// - /// assert!(!" 越".is_whitespace()); - /// ``` - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - #[inline] - pub fn is_whitespace(&self) -> bool { - StrExt::is_whitespace(self) - } - - /// Returns true if this `str` is entirely alphanumeric, and false otherwise. - /// - /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!("٣7৬Kو藏".is_alphanumeric()); - /// assert!(!"¾①".is_alphanumeric()); - /// ``` - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - #[inline] - pub fn is_alphanumeric(&self) -> bool { - StrExt::is_alphanumeric(self) - } - /// Checks if all characters in this string are within the ASCII range. /// /// # Examples diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 600e9eaa05f..8cd5f373efe 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -437,7 +437,7 @@ fn partition_source(s: &str) -> (String, String) { for line in s.lines() { let trimline = line.trim(); - let header = trimline.is_whitespace() || + let header = trimline.chars().all(|c| c.is_whitespace()) || trimline.starts_with("#![") || trimline.starts_with("#[macro_use] extern crate") || trimline.starts_with("extern crate"); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 20a4f9b508d..64590fc0d10 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2127,8 +2127,8 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 43); /// ``` #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify(self, mut f: F) -> Self - where F: FnMut(&mut V) + pub fn and_modify(self, f: F) -> Self + where F: FnOnce(&mut V) { match self { Occupied(mut entry) => { -- cgit 1.4.1-3-g733a5 From fadabd6fbbfe1a401bbdd4ba0919b21ba4f7c5d2 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 Apr 2018 17:07:58 +0200 Subject: Revert stabilization of `feature(never_type)`. This commit is just covering the feature gate itself and the tests that made direct use of `!` and thus need to opt back into the feature. A follow on commit brings back the other change that motivates the revert: Namely, going back to the old rules for falling back to `()`. --- src/libcore/clone.rs | 2 +- src/libcore/cmp.rs | 8 ++-- src/libcore/fmt/mod.rs | 4 +- src/libcore/lib.rs | 1 + src/libcore/marker.rs | 2 +- src/librustc/lib.rs | 1 + src/librustc_mir/build/matches/simplify.rs | 1 + src/libstd/error.rs | 2 +- src/libstd/lib.rs | 1 + src/libsyntax/feature_gate.rs | 7 ++++ .../compile-fail/call-fn-never-arg-wrong-type.rs | 2 + src/test/compile-fail/coerce-to-bang-cast.rs | 2 + src/test/compile-fail/coerce-to-bang.rs | 2 + .../compile-fail/inhabitedness-infinite-loop.rs | 1 + src/test/compile-fail/loop-break-value.rs | 2 + src/test/compile-fail/match-privately-empty.rs | 1 + src/test/compile-fail/never-assign-dead-code.rs | 1 + src/test/compile-fail/never-assign-wrong-type.rs | 1 + src/test/compile-fail/uninhabited-irrefutable.rs | 1 + src/test/compile-fail/uninhabited-patterns.rs | 1 + src/test/compile-fail/unreachable-loop-patterns.rs | 1 + src/test/compile-fail/unreachable-try-pattern.rs | 1 + .../run-pass/diverging-fallback-control-flow.rs | 2 + src/test/run-pass/empty-types-in-patterns.rs | 1 + src/test/run-pass/impl-for-never.rs | 2 + src/test/run-pass/issue-44402.rs | 1 + src/test/run-pass/loop-break-value.rs | 2 + src/test/run-pass/mir_calls_to_shims.rs | 1 + src/test/run-pass/never-result.rs | 2 + src/test/run-pass/type-sizes.rs | 1 + src/test/ui/feature-gate-exhaustive-patterns.rs | 2 +- src/test/ui/feature-gate-never_type.rs | 27 ++++++++++++++ src/test/ui/feature-gate-never_type.stderr | 43 ++++++++++++++++++++++ src/test/ui/print_type_sizes/uninhabited.rs | 1 + src/test/ui/reachable/expr_add.rs | 2 +- src/test/ui/reachable/expr_assign.rs | 2 +- src/test/ui/reachable/expr_call.rs | 2 +- src/test/ui/reachable/expr_cast.rs | 2 +- src/test/ui/reachable/expr_method.rs | 2 +- src/test/ui/reachable/expr_type.rs | 2 +- src/test/ui/reachable/expr_unary.rs | 2 +- 41 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/feature-gate-never_type.rs create mode 100644 src/test/ui/feature-gate-never_type.stderr (limited to 'src/libstd') diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 58a8439162c..f79f7351698 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -179,7 +179,7 @@ mod impls { bool char } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Clone for ! { #[inline] fn clone(&self) -> Self { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 3ae9b05b865..c91aa06609d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -881,24 +881,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Eq for ! {} - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 277bef2bf66..a8430f14410 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1780,14 +1780,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ea7a46f44ae..ac1a8091eb3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -82,6 +82,7 @@ #![feature(iterator_repeat_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(macro_at_most_once_rep)] #![feature(no_core)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 885aabe0806..feb689dbc1f 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -630,7 +630,7 @@ mod copy_impls { bool char } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a2cefe488c6..bb495049483 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -52,6 +52,7 @@ #![cfg_attr(windows, feature(libc))] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(non_exhaustive)] #![feature(nonzero)] diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 4e95ee6444d..147b8cc2175 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,6 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { + self.hir.tcx().features().never_type && self.hir.tcx().features().exhaustive_patterns && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3c209928d43..6c149b2e0f1 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -233,7 +233,7 @@ impl<'a> From> for Box { } } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Error for ! { fn description(&self) -> &str { *self } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7d896695311..8980cd8c6a4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -275,6 +275,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7b7cfe5eea0..a515b591f69 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -272,6 +272,9 @@ declare_features! ( // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), + // The `!` type. Does not imply exhaustive_patterns (below) any more. + (active, never_type, "1.13.0", Some(35121), None), + // Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", None, None), @@ -1635,6 +1638,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_abi(bare_fn_ty.abi, ty.span); } + ast::TyKind::Never => { + gate_feature_post!(&self, never_type, ty.span, + "The `!` type is experimental"); + } ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { gate_feature_post!(&self, dyn_trait, ty.span, "`dyn Trait` syntax is unstable"); diff --git a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs index c2f157cd35c..583befed1e8 100644 --- a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs +++ b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs @@ -10,6 +10,8 @@ // Test that we can't pass other types for ! +#![feature(never_type)] + fn foo(x: !) -> ! { x } diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs index 5efb4dadc64..14a06b306d8 100644 --- a/src/test/compile-fail/coerce-to-bang-cast.rs +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn foo(x: usize, y: !, z: usize) { } fn cast_a() { diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 15049232a4d..62ff09f4616 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn foo(x: usize, y: !, z: usize) { } fn call_foo_a() { diff --git a/src/test/compile-fail/inhabitedness-infinite-loop.rs b/src/test/compile-fail/inhabitedness-infinite-loop.rs index b9741e0add6..d11aacec196 100644 --- a/src/test/compile-fail/inhabitedness-infinite-loop.rs +++ b/src/test/compile-fail/inhabitedness-infinite-loop.rs @@ -10,6 +10,7 @@ // error-pattern:reached recursion limit +#![feature(never_type)] #![feature(exhaustive_patterns)] struct Foo<'a, T: 'a> { diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index 5ef46bb27fd..938f7fba2a0 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn main() { let val: ! = loop { break break; }; //~^ ERROR mismatched types diff --git a/src/test/compile-fail/match-privately-empty.rs b/src/test/compile-fail/match-privately-empty.rs index e18c7d77ce3..8777ef2ffe3 100644 --- a/src/test/compile-fail/match-privately-empty.rs +++ b/src/test/compile-fail/match-privately-empty.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] mod private { diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 4e987d1ddce..0fb75b535c6 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -10,6 +10,7 @@ // Test that an assignment of type ! makes the rest of the block dead code. +#![feature(never_type)] #![feature(rustc_attrs)] #![warn(unused)] diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index 8c2de7d68d3..c0dd2cab749 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -10,6 +10,7 @@ // Test that we can't use another type in place of ! +#![feature(never_type)] #![deny(warnings)] fn main() { diff --git a/src/test/compile-fail/uninhabited-irrefutable.rs b/src/test/compile-fail/uninhabited-irrefutable.rs index 72b0afa6bd3..05a97b855e7 100644 --- a/src/test/compile-fail/uninhabited-irrefutable.rs +++ b/src/test/compile-fail/uninhabited-irrefutable.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] mod foo { diff --git a/src/test/compile-fail/uninhabited-patterns.rs b/src/test/compile-fail/uninhabited-patterns.rs index e130df5c845..2cf4b78bdff 100644 --- a/src/test/compile-fail/uninhabited-patterns.rs +++ b/src/test/compile-fail/uninhabited-patterns.rs @@ -10,6 +10,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![deny(unreachable_patterns)] diff --git a/src/test/compile-fail/unreachable-loop-patterns.rs b/src/test/compile-fail/unreachable-loop-patterns.rs index dca79bdfb87..cfd829e416e 100644 --- a/src/test/compile-fail/unreachable-loop-patterns.rs +++ b/src/test/compile-fail/unreachable-loop-patterns.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] diff --git a/src/test/compile-fail/unreachable-try-pattern.rs b/src/test/compile-fail/unreachable-try-pattern.rs index 0caf7d51234..df340095bb4 100644 --- a/src/test/compile-fail/unreachable-try-pattern.rs +++ b/src/test/compile-fail/unreachable-try-pattern.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns, rustc_attrs)] #![warn(unreachable_code)] #![warn(unreachable_patterns)] diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs index a96f98b9efd..723a98bcdfa 100644 --- a/src/test/run-pass/diverging-fallback-control-flow.rs +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -14,6 +14,8 @@ // These represent current behavior, but are pretty dubious. I would // like to revisit these and potentially change them. --nmatsakis +#![feature(never_type)] + trait BadDefault { fn default() -> Self; } diff --git a/src/test/run-pass/empty-types-in-patterns.rs b/src/test/run-pass/empty-types-in-patterns.rs index 87db4401929..86cf9b5ec47 100644 --- a/src/test/run-pass/empty-types-in-patterns.rs +++ b/src/test/run-pass/empty-types-in-patterns.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![allow(unreachable_patterns)] diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs index cf54e1c3bd5..794f5969bff 100644 --- a/src/test/run-pass/impl-for-never.rs +++ b/src/test/run-pass/impl-for-never.rs @@ -10,6 +10,8 @@ // Test that we can call static methods on ! both directly and when it appears in a generic +#![feature(never_type)] + trait StringifyType { fn stringify_type() -> &'static str; } diff --git a/src/test/run-pass/issue-44402.rs b/src/test/run-pass/issue-44402.rs index a5a0a5a5794..5cbd3446d9b 100644 --- a/src/test/run-pass/issue-44402.rs +++ b/src/test/run-pass/issue-44402.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] // Regression test for inhabitedness check. The old diff --git a/src/test/run-pass/loop-break-value.rs b/src/test/run-pass/loop-break-value.rs index ffdd99ebf6e..39053769b24 100644 --- a/src/test/run-pass/loop-break-value.rs +++ b/src/test/run-pass/loop-break-value.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + #[allow(unused)] fn never_returns() { loop { diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs index dda7a46f325..9641ed28293 100644 --- a/src/test/run-pass/mir_calls_to_shims.rs +++ b/src/test/run-pass/mir_calls_to_shims.rs @@ -11,6 +11,7 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] +#![feature(never_type)] use std::panic; diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs index 8aa2a13ed8c..5c0af392f44 100644 --- a/src/test/run-pass/never-result.rs +++ b/src/test/run-pass/never-result.rs @@ -10,6 +10,8 @@ // Test that we can extract a ! through pattern matching then use it as several different types. +#![feature(never_type)] + fn main() { let x: Result = Ok(123); match x { diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 0bb18d8729a..7bd9a1703ee 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] use std::mem::size_of; diff --git a/src/test/ui/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gate-exhaustive-patterns.rs index 477dd1b38eb..c83d9b56bc3 100644 --- a/src/test/ui/feature-gate-exhaustive-patterns.rs +++ b/src/test/ui/feature-gate-exhaustive-patterns.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] fn foo() -> Result { Ok(123) } diff --git a/src/test/ui/feature-gate-never_type.rs b/src/test/ui/feature-gate-never_type.rs new file mode 100644 index 00000000000..ebbe17a821f --- /dev/null +++ b/src/test/ui/feature-gate-never_type.rs @@ -0,0 +1,27 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that ! errors when used in illegal positions with feature(never_type) disabled + +trait Foo { + type Wub; +} + +type Ma = (u32, !, i32); //~ ERROR type is experimental +type Meeshka = Vec; //~ ERROR type is experimental +type Mow = &fn(!) -> !; //~ ERROR type is experimental +type Skwoz = &mut !; //~ ERROR type is experimental + +impl Foo for Meeshka { + type Wub = !; //~ ERROR type is experimental +} + +fn main() { +} diff --git a/src/test/ui/feature-gate-never_type.stderr b/src/test/ui/feature-gate-never_type.stderr new file mode 100644 index 00000000000..187be6d8291 --- /dev/null +++ b/src/test/ui/feature-gate-never_type.stderr @@ -0,0 +1,43 @@ +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:17:17 + | +LL | type Ma = (u32, !, i32); //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:18:20 + | +LL | type Meeshka = Vec; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:19:16 + | +LL | type Mow = &fn(!) -> !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:20:19 + | +LL | type Skwoz = &mut !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:23:16 + | +LL | type Wub = !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index 1908ef244cf..9ae86136a90 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -11,6 +11,7 @@ // compile-flags: -Z print-type-sizes // compile-pass +#![feature(never_type)] #![feature(start)] #[start] diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs index 3e39b75d8c0..26760cfea44 100644 --- a/src/test/ui/reachable/expr_add.rs +++ b/src/test/ui/reachable/expr_add.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![deny(unreachable_code)] diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs index 73083af34d9..308f2483be5 100644 --- a/src/test/ui/reachable/expr_assign.rs +++ b/src/test/ui/reachable/expr_assign.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs index 2772dd429d1..9696bdadf87 100644 --- a/src/test/ui/reachable/expr_call.rs +++ b/src/test/ui/reachable/expr_call.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs index 88846b63841..fc0041daf7c 100644 --- a/src/test/ui/reachable/expr_cast.rs +++ b/src/test/ui/reachable/expr_cast.rs @@ -12,7 +12,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(type_ascription)] +#![feature(never_type, type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs index 7dabb307097..c91646cfa1e 100644 --- a/src/test/ui/reachable/expr_method.rs +++ b/src/test/ui/reachable/expr_method.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs index 2381ea2ac7a..ce12412ba74 100644 --- a/src/test/ui/reachable/expr_type.rs +++ b/src/test/ui/reachable/expr_type.rs @@ -12,7 +12,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(type_ascription)] +#![feature(never_type, type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index 4096865f4c6..5b7ea57b166 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] -- cgit 1.4.1-3-g733a5 From d141fdc3bfce5ab675a0c74b2fd6cf89ac4ef3f8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 Apr 2018 17:41:31 +0200 Subject: Revert "Stabilize the TryFrom and TryInto traits" This reverts commit e53a2a72743810e05f58c61c9d8a4c89b712ad2e. --- src/libcore/array.rs | 6 +++--- src/libcore/char/convert.rs | 6 +++--- src/libcore/char/mod.rs | 2 +- src/libcore/convert.rs | 12 ++++-------- src/libcore/num/mod.rs | 12 ++++++------ src/libcore/tests/lib.rs | 1 + src/librustc_apfloat/lib.rs | 1 + src/libstd/error.rs | 6 +++--- src/libstd/lib.rs | 1 + src/test/ui/e0119/conflict-with-std.rs | 2 ++ src/test/ui/e0119/conflict-with-std.stderr | 6 +++--- 11 files changed, 28 insertions(+), 27 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 87144c27c9e..3d24f8902bd 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -59,7 +59,7 @@ unsafe impl> FixedSizeArray for A { } /// The error type returned when a conversion from a slice to an array fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); @@ -148,7 +148,7 @@ macro_rules! array_impls { } } - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { type Error = TryFromSliceError; @@ -162,7 +162,7 @@ macro_rules! array_impls { } } - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { type Error = TryFromSliceError; diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 150562a4a9b..803a924eb3a 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -204,7 +204,7 @@ impl FromStr for char { } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl TryFrom for char { type Error = CharTryFromError; @@ -219,11 +219,11 @@ impl TryFrom for char { } /// The error type returned when a conversion from u32 to char fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CharTryFromError(()); -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl fmt::Display for CharTryFromError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { "converted integer out of range for `char`".fmt(f) diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 9edc0c88756..210eceebc51 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -40,7 +40,7 @@ pub use self::convert::{from_u32, from_digit}; pub use self::convert::from_u32_unchecked; #[stable(feature = "char_from_str", since = "1.20.0")] pub use self::convert::ParseCharError; -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub use self::convert::CharTryFromError; #[stable(feature = "decode_utf16", since = "1.9.0")] pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 63721395784..7324df95bc5 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -322,26 +322,22 @@ pub trait From: Sized { /// /// [`TryFrom`]: trait.TryFrom.html /// [`Into`]: trait.Into.html -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. - #[stable(feature = "try_from", since = "1.26.0")] fn try_into(self) -> Result; } /// Attempt to construct `Self` via a conversion. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. - #[stable(feature = "try_from", since = "1.26.0")] fn try_from(value: T) -> Result; } @@ -409,7 +405,7 @@ impl From for T { // TryFrom implies TryInto -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl TryInto for T where U: TryFrom { type Error = U::Error; @@ -421,7 +417,7 @@ impl TryInto for T where U: TryFrom // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl TryFrom for T where T: From { type Error = !; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f2e8caaad14..801e2328a4b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4192,7 +4192,7 @@ macro_rules! from_str_radix_int_impl { from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } /// The error type returned when a checked integral type conversion fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Debug, Copy, Clone)] pub struct TryFromIntError(()); @@ -4207,14 +4207,14 @@ impl TryFromIntError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.__description().fmt(fmt) } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl From for TryFromIntError { fn from(never: !) -> TryFromIntError { never @@ -4224,7 +4224,7 @@ impl From for TryFromIntError { // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -4243,7 +4243,7 @@ macro_rules! try_from_lower_bounded { // unsigned to signed (only positive bound) macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -4262,7 +4262,7 @@ macro_rules! try_from_upper_bounded { // all other cases macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bb875c7219a..3b080689cb3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -36,6 +36,7 @@ #![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] +#![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] #![cfg_attr(stage0, feature(atomic_nand))] diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 0f051ea5981..08438805a70 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -45,6 +45,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![forbid(unsafe_code)] +#![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 6c149b2e0f1..749b8ccc13d 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -284,14 +284,14 @@ impl Error for num::ParseIntError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for num::TryFromIntError { fn description(&self) -> &str { self.__description() } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for array::TryFromSliceError { fn description(&self) -> &str { self.__description() @@ -365,7 +365,7 @@ impl Error for cell::BorrowMutError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for char::CharTryFromError { fn description(&self) -> &str { "converted integer out of range for `char`" diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 8980cd8c6a4..e53e009678c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -307,6 +307,7 @@ #![feature(test, rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] +#![feature(try_from)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(untagged_unions)] diff --git a/src/test/ui/e0119/conflict-with-std.rs b/src/test/ui/e0119/conflict-with-std.rs index a9f747d09ec..ed9033ad53d 100644 --- a/src/test/ui/e0119/conflict-with-std.rs +++ b/src/test/ui/e0119/conflict-with-std.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(try_from)] + use std::marker::PhantomData; use std::convert::{TryFrom, AsRef}; diff --git a/src/test/ui/e0119/conflict-with-std.stderr b/src/test/ui/e0119/conflict-with-std.stderr index 417ff1de3f8..e8b2c84c0df 100644 --- a/src/test/ui/e0119/conflict-with-std.stderr +++ b/src/test/ui/e0119/conflict-with-std.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `std::convert::AsRef` for type `std::boxed::Box`: - --> $DIR/conflict-with-std.rs:15:1 + --> $DIR/conflict-with-std.rs:17:1 | LL | impl AsRef for Box { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | impl AsRef for Box { //~ ERROR conflicting implementations where T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: - --> $DIR/conflict-with-std.rs:22:1 + --> $DIR/conflict-with-std.rs:24:1 | LL | impl From for S { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | impl From for S { //~ ERROR conflicting implementations - impl std::convert::From for T; error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: - --> $DIR/conflict-with-std.rs:29:1 + --> $DIR/conflict-with-std.rs:31:1 | LL | impl TryFrom for X { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 42b6d4653a2ad22be695760aba3514fc64c18d66 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 21 Apr 2018 02:48:56 +0800 Subject: Add back missing `#![feature(never_type)]`s --- src/librustc_mir/lib.rs | 1 + src/librustc_typeck/lib.rs | 1 + src/libstd/primitive_docs.rs | 2 ++ src/test/run-fail/adjust_never.rs | 3 +++ src/test/run-fail/call-fn-never-arg.rs | 1 + src/test/run-fail/cast-never.rs | 3 +++ src/test/run-fail/never-associated-type.rs | 2 ++ src/test/run-fail/never-type-arg.rs | 2 ++ 8 files changed, 15 insertions(+) (limited to 'src/libstd') diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index de3063a5756..a47b3cacc51 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -33,6 +33,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(nonzero)] #![feature(inclusive_range_fields)] #![feature(crate_visibility_modifier)] +#![feature(never_type)] #![cfg_attr(stage0, feature(try_trait))] extern crate arena; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 4b66939963e..ed0cfe38a7a 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -82,6 +82,7 @@ This API is completely unstable and subject to change. #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] #![feature(dyn_trait)] +#![feature(never_type)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index ce4bbfffc2e..42bac605511 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -79,6 +79,7 @@ mod prim_bool { } /// write: /// /// ``` +/// #![feature(never_type)] /// # fn foo() -> u32 { /// let x: ! = { /// return 123 @@ -155,6 +156,7 @@ mod prim_bool { } /// for example: /// /// ``` +/// #![feature(never_type)] /// # use std::fmt; /// # trait Debug { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; diff --git a/src/test/run-fail/adjust_never.rs b/src/test/run-fail/adjust_never.rs index 7a4b5e59eeb..da68dc39f85 100644 --- a/src/test/run-fail/adjust_never.rs +++ b/src/test/run-fail/adjust_never.rs @@ -11,6 +11,9 @@ // Test that a variable of type ! can coerce to another type. // error-pattern:explicit + +#![feature(never_type)] + fn main() { let x: ! = panic!(); let y: u32 = x; diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/run-fail/call-fn-never-arg.rs index 56454586bb9..95101e70db9 100644 --- a/src/test/run-fail/call-fn-never-arg.rs +++ b/src/test/run-fail/call-fn-never-arg.rs @@ -12,6 +12,7 @@ // error-pattern:wowzers! +#![feature(never_type)] #![allow(unreachable_code)] fn foo(x: !) -> ! { diff --git a/src/test/run-fail/cast-never.rs b/src/test/run-fail/cast-never.rs index 0155332c51d..8f7b0c40538 100644 --- a/src/test/run-fail/cast-never.rs +++ b/src/test/run-fail/cast-never.rs @@ -11,6 +11,9 @@ // Test that we can explicitly cast ! to another type // error-pattern:explicit + +#![feature(never_type)] + fn main() { let x: ! = panic!(); let y: u32 = x as u32; diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/run-fail/never-associated-type.rs index d9b8461a1d0..fdd21e08c20 100644 --- a/src/test/run-fail/never-associated-type.rs +++ b/src/test/run-fail/never-associated-type.rs @@ -12,6 +12,8 @@ // error-pattern:kapow! +#![feature(never_type)] + trait Foo { type Wow; diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/run-fail/never-type-arg.rs index 0fe10d43910..826ca3a08c0 100644 --- a/src/test/run-fail/never-type-arg.rs +++ b/src/test/run-fail/never-type-arg.rs @@ -12,6 +12,8 @@ // error-pattern:oh no! +#![feature(never_type)] + struct Wub; impl PartialEq for Wub { -- cgit 1.4.1-3-g733a5 From 572256772e10513ff61e9932d421d0a1e4656e02 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 7 Apr 2018 11:12:35 +0200 Subject: Remove unused methods on the private Wtf8 type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The type and its direct parent module are `pub`, but they’re not reachable outside of std --- src/libstd/sys_common/wtf8.rs | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index dda4e1bab3b..fe7e058091e 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -876,21 +876,7 @@ impl Hash for Wtf8 { } impl Wtf8 { - pub fn is_ascii(&self) -> bool { - self.bytes.is_ascii() - } - pub fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() } - } - pub fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() } - } - pub fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { - self.bytes.eq_ignore_ascii_case(&other.bytes) - } - pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } - pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } } #[cfg(test)] -- cgit 1.4.1-3-g733a5 From 8a374f2827a222322a631e313cd8fd8d9ba34932 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 8 Apr 2018 10:09:52 +0200 Subject: Add some f32 and f64 inherent methods in libcore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … previously in the unstable core::num::Float trait. Per https://github.com/rust-lang/rust/issues/32110#issuecomment-379503183, the `abs`, `signum`, and `powi` methods are *not* included for now since they rely on LLVM intrinsics and we haven’t determined yet whether those instrinsics lower to calls to libm functions on any platform. --- src/liballoc/vec.rs | 1 + src/libcore/lib.rs | 1 + src/libcore/num/f32.rs | 284 +++++++++++++++++++++++ src/libcore/num/f64.rs | 296 +++++++++++++++++++++++- src/librustc/middle/lang_items.rs | 2 + src/librustc_typeck/check/method/probe.rs | 6 + src/librustc_typeck/coherence/inherent_impls.rs | 4 +- src/librustdoc/clean/inline.rs | 2 + src/libstd/f32.rs | 283 +--------------------- src/libstd/f64.rs | 291 +---------------------- 10 files changed, 611 insertions(+), 559 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 7d1b2ed85c7..b184404c15b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -74,6 +74,7 @@ use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; use core::mem; #[cfg(not(test))] +#[cfg(stage0)] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds}; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5a107951b0b..215886069f5 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -71,6 +71,7 @@ #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] +#![feature(core_float)] #![feature(custom_attribute)] #![feature(doc_cfg)] #![feature(doc_spotlight)] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 3586fa5442f..0edf63bce12 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -20,6 +20,7 @@ use intrinsics; use mem; use num::Float; +#[cfg(not(stage0))] use num::FpCategory; use num::FpCategory as Fp; /// The radix or base of the internal representation of `f32`. @@ -292,3 +293,286 @@ impl Float for f32 { unsafe { mem::transmute(v) } } } + +// FIXME: remove (inline) this macro and the Float trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_float", issue = "32110")] +macro_rules! f32_core_methods { () => { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let nan = f32::NAN; + /// let f = 7.0_f32; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_nan(self) -> bool { Float::is_nan(self) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_finite(self) -> bool { Float::is_finite(self) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0_f32; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f32::NAN.is_normal()); + /// assert!(!f32::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_normal(self) -> bool { Float::is_normal(self) } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f32; + /// + /// let num = 12.4_f32; + /// let inf = f32::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn classify(self) -> FpCategory { Float::classify(self) } + + /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// positive sign bit and positive infinity. + /// + /// ``` + /// let f = 7.0_f32; + /// let g = -7.0_f32; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + + /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// negative sign bit and negative infinity. + /// + /// ``` + /// let f = 7.0f32; + /// let g = -7.0f32; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0_f32; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f32 { Float::recip(self) } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] + #[inline] + pub fn to_degrees(self) -> f32 { Float::to_degrees(self) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = 180.0f32; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] + #[inline] + pub fn to_radians(self) -> f32 { Float::to_radians(self) } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn max(self, other: f32) -> f32 { + Float::max(self, other) + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn min(self, other: f32) -> f32 { + Float::min(self, other) + } + + /// Raw transmutation to `u32`. + /// + /// This is currently identical to `transmute::(self)` on all platforms. + /// + /// See `from_bits` for some discussion of the portability of this operation + /// (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! + /// assert_eq!((12.5f32).to_bits(), 0x41480000); + /// + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn to_bits(self) -> u32 { + Float::to_bits(self) + } + + /// Raw transmutation from `u32`. + /// + /// This is currently identical to `transmute::(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE-754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favours preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// use std::f32; + /// let v = f32::from_bits(0x41480000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn from_bits(v: u32) -> Self { + Float::from_bits(v) + } +}} + +#[lang = "f32"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl f32 { + f32_core_methods!(); +} diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 64c0d508b38..38f3d63ea8d 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -19,8 +19,9 @@ use intrinsics; use mem; -use num::FpCategory as Fp; use num::Float; +#[cfg(not(stage0))] use num::FpCategory; +use num::FpCategory as Fp; /// The radix or base of the internal representation of `f64`. #[stable(feature = "rust1", since = "1.0.0")] @@ -291,3 +292,296 @@ impl Float for f64 { unsafe { mem::transmute(v) } } } + +// FIXME: remove (inline) this macro and the Float trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_float", issue = "32110")] +macro_rules! f64_core_methods { () => { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let nan = f64::NAN; + /// let f = 7.0_f64; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_nan(self) -> bool { Float::is_nan(self) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf = f64::INFINITY; + /// let neg_inf = f64::NEG_INFINITY; + /// let nan = f64::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf: f64 = f64::INFINITY; + /// let neg_inf: f64 = f64::NEG_INFINITY; + /// let nan: f64 = f64::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_finite(self) -> bool { Float::is_finite(self) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0f64; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f64::NAN.is_normal()); + /// assert!(!f64::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_normal(self) -> bool { Float::is_normal(self) } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f64; + /// + /// let num = 12.4_f64; + /// let inf = f64::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn classify(self) -> FpCategory { Float::classify(self) } + + /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// positive sign bit and positive infinity. + /// + /// ``` + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] + #[inline] + #[doc(hidden)] + pub fn is_positive(self) -> bool { Float::is_sign_positive(self) } + + /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// negative sign bit and negative infinity. + /// + /// ``` + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] + #[inline] + #[doc(hidden)] + pub fn is_negative(self) -> bool { Float::is_sign_negative(self) } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f64 { Float::recip(self) } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_degrees(self) -> f64 { Float::to_degrees(self) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = 180.0_f64; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_radians(self) -> f64 { Float::to_radians(self) } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn max(self, other: f64) -> f64 { + Float::max(self, other) + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn min(self, other: f64) -> f64 { + Float::min(self, other) + } + + /// Raw transmutation to `u64`. + /// + /// This is currently identical to `transmute::(self)` on all platforms. + /// + /// See `from_bits` for some discussion of the portability of this operation + /// (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! + /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + /// + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn to_bits(self) -> u64 { + Float::to_bits(self) + } + + /// Raw transmutation from `u64`. + /// + /// This is currently identical to `transmute::(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE-754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favours preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// use std::f64; + /// let v = f64::from_bits(0x4029000000000000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn from_bits(v: u64) -> Self { + Float::from_bits(v) + } +}} + +#[lang = "f64"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl f64 { + f64_core_methods!(); +} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 24c7f3b0aba..c7412dbeeb3 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -233,6 +233,8 @@ language_item_table! { UsizeImplItem, "usize", usize_impl; F32ImplItem, "f32", f32_impl; F64ImplItem, "f64", f64_impl; + F32RuntimeImplItem, "f32_runtime", f32_runtime_impl; + F64RuntimeImplItem, "f64_runtime", f64_runtime_impl; SizedTraitLangItem, "sized", sized_trait; UnsizeTraitLangItem, "unsize", unsize_trait; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c538004c838..073f36b9f3c 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -547,10 +547,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyFloat(ast::FloatTy::F32) => { let lang_def_id = lang_items.f32_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.f32_runtime_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TyFloat(ast::FloatTy::F64) => { let lang_def_id = lang_items.f64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.f64_runtime_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } _ => {} } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 97e57ba668f..532f1da4f30 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -258,7 +258,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F32) => { self.check_primitive_impl(def_id, lang_items.f32_impl(), - None, + lang_items.f32_runtime_impl(), "f32", "f32", item.span); @@ -266,7 +266,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F64) => { self.check_primitive_impl(def_id, lang_items.f64_impl(), - None, + lang_items.f64_runtime_impl(), "f64", "f64", item.span); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 65f6b227a56..23e0c2625ee 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -286,6 +286,8 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 - /// let max = f32::MAX; - /// let lower_than_min = 1.0e-40_f32; - /// let zero = 0.0_f32; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f32::NAN.is_normal()); - /// assert!(!f32::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f32; - /// - /// let num = 12.4_f32; - /// let inf = f32::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } + #[cfg(stage0)] + f32_core_methods!(); /// Returns the largest integer less than or equal to a number. /// @@ -257,7 +163,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f32 { num::Float::abs(self) } + pub fn abs(self) -> f32 { Float::abs(self) } /// Returns a number that represents the sign of `self`. /// @@ -277,35 +183,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f32 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f32; - /// let g = -7.0_f32; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - /// - /// ``` - /// let f = 7.0f32; - /// let g = -7.0f32; - /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } + pub fn signum(self) -> f32 { Float::signum(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -380,20 +258,6 @@ impl f32 { } - /// Takes the reciprocal (inverse) of a number, `1/x`. - /// - /// ``` - /// use std::f32; - /// - /// let x = 2.0_f32; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn recip(self) -> f32 { num::Float::recip(self) } - /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` @@ -408,7 +272,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f32 { Float::powi(self, n) } /// Raises a number to a floating point power. /// @@ -584,68 +448,6 @@ impl f32 { return unsafe { intrinsics::log10f32(self) }; } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = 180.0f32; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f32) -> f32 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f32) -> f32 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` @@ -1046,73 +848,6 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - /// Raw transmutation to `u32`. - /// - /// This is currently identical to `transmute::(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! - /// assert_eq!((12.5f32).to_bits(), 0x41480000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u32 { - num::Float::to_bits(self) - } - - /// Raw transmutation from `u32`. - /// - /// This is currently identical to `transmute::(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// let v = f32::from_bits(0x41480000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u32) -> Self { - num::Float::from_bits(v) - } } #[cfg(test)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a9585670ad0..d4a8f700a90 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -19,10 +19,11 @@ #![allow(missing_docs)] #[cfg(not(test))] -use core::num; +use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] +#[cfg(stage0)] use num::FpCategory; #[cfg(not(test))] use sys::cmath; @@ -39,106 +40,11 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX}; pub use core::f64::consts; #[cfg(not(test))] -#[lang = "f64"] +#[cfg_attr(stage0, lang = "f64")] +#[cfg_attr(not(stage0), lang = "f64_runtime")] impl f64 { - /// Returns `true` if this value is `NaN` and false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let nan = f64::NAN; - /// let f = 7.0_f64; - /// - /// assert!(nan.is_nan()); - /// assert!(!f.is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_nan(self) -> bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf = f64::INFINITY; - /// let neg_inf = f64::NEG_INFINITY; - /// let nan = f64::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf: f64 = f64::INFINITY; - /// let neg_inf: f64 = f64::NEG_INFINITY; - /// let nan: f64 = f64::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 - /// let max = f64::MAX; - /// let lower_than_min = 1.0e-308_f64; - /// let zero = 0.0f64; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f64::NAN.is_normal()); - /// assert!(!f64::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f64; - /// - /// let num = 12.4_f64; - /// let inf = f64::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } + #[cfg(stage0)] + f64_core_methods!(); /// Returns the largest integer less than or equal to a number. /// @@ -235,7 +141,7 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f64 { num::Float::abs(self) } + pub fn abs(self) -> f64 { Float::abs(self) } /// Returns a number that represents the sign of `self`. /// @@ -255,45 +161,7 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f64 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] - #[inline] - pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; - /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] - #[inline] - pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) } + pub fn signum(self) -> f64 { Float::signum(self) } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -365,18 +233,6 @@ impl f64 { } } - /// Takes the reciprocal (inverse) of a number, `1/x`. - /// - /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn recip(self) -> f64 { num::Float::recip(self) } - /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` @@ -389,7 +245,7 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f64 { Float::powi(self, n) } /// Raises a number to a floating point power. /// @@ -535,68 +391,6 @@ impl f64 { self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } }) } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = 180.0_f64; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f64) -> f64 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f64) -> f64 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` @@ -1000,73 +794,6 @@ impl f64 { } } } - - /// Raw transmutation to `u64`. - /// - /// This is currently identical to `transmute::(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! - /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u64 { - num::Float::to_bits(self) - } - - /// Raw transmutation from `u64`. - /// - /// This is currently identical to `transmute::(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// let v = f64::from_bits(0x4029000000000000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u64) -> Self { - num::Float::from_bits(v) - } } #[cfg(test)] -- cgit 1.4.1-3-g733a5 From 18ab16b5104403ef7a55a2d241c566e35c5ae57a Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 10 Apr 2018 16:36:23 +0200 Subject: Move intrinsics-based float methods out of libcore into libstd Affected methods are `abs`, `signum`, and `powi`. CC https://github.com/rust-lang/rust/issues/32110#issuecomment-379503183 --- src/libcore/num/f32.rs | 27 ---------------------- src/libcore/num/f64.rs | 27 ---------------------- src/libcore/num/mod.rs | 18 --------------- src/librustc_typeck/diagnostics.rs | 10 ++++---- src/libstd/f32.rs | 17 +++++++++++--- src/libstd/f64.rs | 17 +++++++++++--- .../ui/macros/macro-backtrace-invalid-internals.rs | 4 ++-- .../macro-backtrace-invalid-internals.stderr | 16 ++++++------- .../method-on-ambiguous-numeric-type.rs | 8 +++---- .../method-on-ambiguous-numeric-type.stderr | 14 +++++------ 10 files changed, 54 insertions(+), 104 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 0edf63bce12..8d5f6f601da 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -17,7 +17,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use intrinsics; use mem; use num::Float; #[cfg(not(stage0))] use num::FpCategory; @@ -189,27 +188,6 @@ impl Float for f32 { } } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[inline] - fn abs(self) -> f32 { - unsafe { intrinsics::fabsf32(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[inline] - fn signum(self) -> f32 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf32(1.0, self) } - } - } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. #[inline] @@ -232,11 +210,6 @@ impl Float for f32 { 1.0 / self } - #[inline] - fn powi(self, n: i32) -> f32 { - unsafe { intrinsics::powif32(self, n) } - } - /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f32 { diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 38f3d63ea8d..08b869734d4 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -17,7 +17,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use intrinsics; use mem; use num::Float; #[cfg(not(stage0))] use num::FpCategory; @@ -189,27 +188,6 @@ impl Float for f64 { } } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[inline] - fn abs(self) -> f64 { - unsafe { intrinsics::fabsf64(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[inline] - fn signum(self) -> f64 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf64(1.0, self) } - } - } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. #[inline] @@ -230,11 +208,6 @@ impl Float for f64 { 1.0 / self } - #[inline] - fn powi(self, n: i32) -> f64 { - unsafe { intrinsics::powif64(self, n) } - } - /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f64 { diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f2e8caaad14..55fad62d871 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4125,18 +4125,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[stable(feature = "core", since = "1.6.0")] - fn abs(self) -> Self; - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[stable(feature = "core", since = "1.6.0")] - fn signum(self) -> Self; - /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. #[stable(feature = "core", since = "1.6.0")] @@ -4150,12 +4138,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn recip(self) -> Self; - /// Raise a number to an integer power. - /// - /// Using this function is generally faster than using `powf` - #[stable(feature = "core", since = "1.6.0")] - fn powi(self, n: i32) -> Self; - /// Convert radians to degrees. #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_degrees(self) -> Self; diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ae3b2b22ea1..e3f7ff5cb3f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4526,23 +4526,23 @@ but the type of the numeric value or binding could not be identified. The error happens on numeric literals: ```compile_fail,E0689 -2.0.powi(2); +2.0.recip(); ``` and on numeric bindings without an identified concrete type: ```compile_fail,E0689 let x = 2.0; -x.powi(2); // same error as above +x.recip(); // same error as above ``` Because of this, you must give the numeric literal or binding a type: ``` -let _ = 2.0_f32.powi(2); +let _ = 2.0_f32.recip(); let x: f32 = 2.0; -let _ = x.powi(2); -let _ = (2.0 as f32).powi(2); +let _ = x.recip(); +let _ = (2.0 as f32).recip(); ``` "##, diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 82f4192de19..26644c76957 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -19,6 +19,7 @@ #![allow(missing_docs)] #[cfg(not(test))] +#[cfg(stage0)] use core::num::Float; #[cfg(not(test))] use intrinsics; @@ -163,7 +164,9 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f32 { Float::abs(self) } + pub fn abs(self) -> f32 { + unsafe { intrinsics::fabsf32(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -183,7 +186,13 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f32 { Float::signum(self) } + pub fn signum(self) -> f32 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf32(1.0, self) } + } + } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -272,7 +281,9 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f32 { Float::powi(self, n) } + pub fn powi(self, n: i32) -> f32 { + unsafe { intrinsics::powif32(self, n) } + } /// Raises a number to a floating point power. /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index d4a8f700a90..a7e63f59b1c 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -19,6 +19,7 @@ #![allow(missing_docs)] #[cfg(not(test))] +#[cfg(stage0)] use core::num::Float; #[cfg(not(test))] use intrinsics; @@ -141,7 +142,9 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f64 { Float::abs(self) } + pub fn abs(self) -> f64 { + unsafe { intrinsics::fabsf64(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -161,7 +164,13 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f64 { Float::signum(self) } + pub fn signum(self) -> f64 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf64(1.0, self) } + } + } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -245,7 +254,9 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f64 { Float::powi(self, n) } + pub fn powi(self, n: i32) -> f64 { + unsafe { intrinsics::powif64(self, n) } + } /// Raises a number to a floating point power. /// diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs index bff64ad4892..090ff817eb0 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -48,13 +48,13 @@ macro_rules! fake_anon_field_expr { macro_rules! real_method_stmt { () => { - 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` + 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` } } macro_rules! real_method_expr { () => { - 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` + 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` } } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index cb7d422b7f3..284960d2f6e 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -25,17 +25,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | fake_anon_field_stmt!(); | ------------------------ in this macro invocation -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:51:15 | -LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` - | ^^^^ +LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + | ^^^^^ ... LL | real_method_stmt!(); | -------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` +LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` | ^^^^^^^ error[E0599]: no method named `fake` found for type `{integer}` in the current scope @@ -65,17 +65,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | let _ = fake_anon_field_expr!(); | ----------------------- in this macro invocation -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:57:15 | -LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` - | ^^^^ +LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + | ^^^^^ ... LL | let _ = real_method_expr!(); | ------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` +LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs index fa5bafab871..2e452f9671f 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs @@ -9,10 +9,10 @@ // except according to those terms. fn main() { - let x = 2.0.powi(2); - //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}` + let x = 2.0.recip(); + //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` let y = 2.0; - let x = y.powi(2); - //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}` + let x = y.recip(); + //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` println!("{:?}", x); } diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr index 92ad2280615..477b4c3821d 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr @@ -1,18 +1,18 @@ -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:12:17 | -LL | let x = 2.0.powi(2); - | ^^^^ +LL | let x = 2.0.recip(); + | ^^^^^ help: you must specify a concrete type for this numeric value, like `f32` | -LL | let x = 2.0_f32.powi(2); +LL | let x = 2.0_f32.recip(); | ^^^^^^^ -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:15:15 | -LL | let x = y.powi(2); - | ^^^^ +LL | let x = y.recip(); + | ^^^^^ help: you must specify a type for this binding, like `f32` | LL | let y: f32 = 2.0; -- cgit 1.4.1-3-g733a5 From 70fdd1b5c0f6a0673fcf924b3d8880af034bdee0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 12 Apr 2018 08:36:31 +0200 Subject: Make the unstable StrExt and SliceExt traits private to libcore in not(stage0) `Float` still needs to be public for libcore unit tests. --- src/liballoc/lib.rs | 2 +- src/libcore/internal_macros.rs | 13 +++++++++ src/libcore/num/mod.rs | 31 +++++++++------------- src/libcore/slice/mod.rs | 7 +++-- src/libcore/str/mod.rs | 8 +++--- src/libcore/tests/lib.rs | 1 + src/libstd/lib.rs | 3 ++- .../method-suggestion-no-duplication.stderr | 4 +-- 8 files changed, 40 insertions(+), 29 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 702d7b70cd3..6399be98cd5 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -75,7 +75,7 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(not(test), feature(core_float))] +#![cfg_attr(all(not(test), stage0), feature(float_internals))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index cb215a38e53..58eef649287 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -87,3 +87,16 @@ macro_rules! forward_ref_op_assign { } } +#[cfg(stage0)] +macro_rules! public_in_stage0 { + ( { $(#[$attr:meta])* } $($Item: tt)*) => { + $(#[$attr])* pub $($Item)* + } +} + +#[cfg(not(stage0))] +macro_rules! public_in_stage0 { + ( { $(#[$attr:meta])* } $($Item: tt)*) => { + $(#[$attr])* pub(crate) $($Item)* + } +} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 55fad62d871..70c704267d2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4098,65 +4098,58 @@ pub enum FpCategory { Normal, } -/// A built-in floating point number. +// Technically private and only exposed for coretests: #[doc(hidden)] -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] +#[unstable(feature = "float_internals", + reason = "internal routines only exposed for testing", + issue = "0")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. - #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; + /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. - #[stable(feature = "core", since = "1.6.0")] fn is_infinite(self) -> bool; + /// Returns `true` if this number is neither infinite nor NaN. - #[stable(feature = "core", since = "1.6.0")] fn is_finite(self) -> bool; + /// Returns `true` if this number is neither zero, infinite, denormal, or NaN. - #[stable(feature = "core", since = "1.6.0")] fn is_normal(self) -> bool; + /// Returns the category that this number falls into. - #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. - #[stable(feature = "core", since = "1.6.0")] fn is_sign_positive(self) -> bool; + /// Returns `true` if `self` is negative, including `-0.0` and /// `Float::neg_infinity()`. - #[stable(feature = "core", since = "1.6.0")] fn is_sign_negative(self) -> bool; /// Take the reciprocal (inverse) of a number, `1/x`. - #[stable(feature = "core", since = "1.6.0")] fn recip(self) -> Self; /// Convert radians to degrees. - #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_degrees(self) -> Self; + /// Convert degrees to radians. - #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_radians(self) -> Self; /// Returns the maximum of the two numbers. - #[stable(feature = "core_float_min_max", since="1.20.0")] fn max(self, other: Self) -> Self; + /// Returns the minimum of the two numbers. - #[stable(feature = "core_float_min_max", since="1.20.0")] fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; + /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0a260c663c2..cc42acd77ae 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -68,12 +68,15 @@ struct Repr { // Extension traits // +public_in_stage0! { +{ /// Extension methods for slices. #[unstable(feature = "core_slice_ext", reason = "stable interface provided by `impl [T]` in later crates", issue = "32110")] #[allow(missing_docs)] // documented elsewhere -pub trait SliceExt { +} +trait SliceExt { type Item; #[stable(feature = "core", since = "1.6.0")] @@ -238,7 +241,7 @@ pub trait SliceExt { fn sort_unstable_by_key(&mut self, f: F) where F: FnMut(&Self::Item) -> B, B: Ord; -} +}} // Use macros to be generic over const/mut macro_rules! slice_offset { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d33eaace79d..a76de79107b 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2117,14 +2117,16 @@ mod traits { } - +public_in_stage0! { +{ /// Methods for string slices #[allow(missing_docs)] #[doc(hidden)] #[unstable(feature = "core_str_ext", reason = "stable interface provided by `impl str` in later crates", issue = "32110")] -pub trait StrExt { +} +trait StrExt { // NB there are no docs here are they're all located on the StrExt trait in // liballoc, not here. @@ -2224,7 +2226,7 @@ pub trait StrExt { fn trim_left(&self) -> &str; #[stable(feature = "rust1", since = "1.0.0")] fn trim_right(&self) -> &str; -} +}} // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bb875c7219a..2cc2ac289bf 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -17,6 +17,7 @@ #![feature(decode_utf8)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] +#![feature(float_internals)] #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7d896695311..3b98abb9293 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -252,7 +252,7 @@ #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] -#![feature(core_float)] +#![cfg_attr(stage0, feature(core_float))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] @@ -260,6 +260,7 @@ #![feature(fs_read_write)] #![feature(fixed_size_array)] #![feature(float_from_str_radix)] +#![cfg_attr(stage0, feature(float_internals))] #![feature(fn_traits)] #![feature(fnbox)] #![cfg_attr(stage0, feature(generic_param_attrs))] diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr index 438d29f0535..f7aaab4242c 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -8,10 +8,8 @@ LL | foo(|s| s.is_empty()); | ^^^^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `is_empty`, perhaps you need to implement one of them: + = note: the following trait defines an item `is_empty`, perhaps you need to implement it: candidate #1: `std::iter::ExactSizeIterator` - candidate #2: `core::slice::SliceExt` - candidate #3: `core::str::StrExt` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 57bcabc1082c948e2cfda3f005c41d8236ead7a4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Apr 2018 17:46:13 +0200 Subject: Generate alias file --- src/librustdoc/html/item_type.rs | 2 +- src/librustdoc/html/layout.rs | 1 + src/librustdoc/html/render.rs | 80 +++++++++++++++++++++++++++++++++++++--- src/libstd/lib.rs | 1 + src/libstd/primitive_docs.rs | 3 ++ src/libsyntax/feature_gate.rs | 7 ++++ 6 files changed, 87 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index e9c6488c49c..537828de2c7 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -19,7 +19,7 @@ use clean; /// discriminants. JavaScript then is used to decode them into the original value. /// Consequently, every change to this type should be synchronized to /// the `itemTypes` mapping table in `static/main.js`. -#[derive(Copy, PartialEq, Clone)] +#[derive(Copy, PartialEq, Clone, Debug)] pub enum ItemType { Module = 0, ExternCrate = 1, diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 583c9f2b671..1880baeddf4 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -145,6 +145,7 @@ pub fn render( \ \ \ + \ \ ", css_extension = if css_file_extension { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 651319743aa..8fe8fe671dd 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -329,6 +329,10 @@ pub struct Cache { // yet when its implementation methods are being indexed. Caches such methods // and their parent id here and indexes them at the end of crate parsing. orphan_impl_items: Vec<(DefId, clean::Item)>, + + /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, + /// we need the alias element to have an array of items. + aliases: FxHashMap>, } /// Temporary storage for data obtained during `RustdocVisitor::clean()`. @@ -369,6 +373,7 @@ struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, } /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. +#[derive(Debug)] struct IndexItem { ty: ItemType, name: String, @@ -396,6 +401,7 @@ impl ToJson for IndexItem { } /// A type used for the search index. +#[derive(Debug)] struct Type { name: Option, generics: Option>, @@ -418,9 +424,10 @@ impl ToJson for Type { } /// Full type of functions/methods in the search index. +#[derive(Debug)] struct IndexItemFunctionType { inputs: Vec, - output: Option + output: Option, } impl ToJson for IndexItemFunctionType { @@ -609,6 +616,7 @@ pub fn run(mut krate: clean::Crate, owned_box_did, masked_crates: mem::replace(&mut krate.masked_crates, FxHashSet()), typarams: external_typarams, + aliases: FxHashMap(), }; // Cache where all our extern crates are located @@ -847,8 +855,7 @@ themePicker.onclick = function() {{ write(cx.dst.join("COPYRIGHT.txt"), include_bytes!("static/COPYRIGHT.txt"))?; - fn collect(path: &Path, krate: &str, - key: &str) -> io::Result> { + fn collect(path: &Path, krate: &str, key: &str) -> io::Result> { let mut ret = Vec::new(); if path.exists() { for line in BufReader::new(File::open(path)?).lines() { @@ -865,6 +872,36 @@ themePicker.onclick = function() {{ Ok(ret) } + fn show_item(item: &IndexItem, krate: &str) -> String { + format!("{{'crate':'{}','ty':'{}','name':'{}','path':'{}','parent':{}}}", + krate, item.ty, item.name, item.path, + if let Some(p) = item.parent_idx { p.to_string() } else { "null".to_owned() }) + } + + let dst = cx.dst.join("aliases.js"); + { + let mut all_aliases = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst); + let mut w = try_err!(File::create(&dst), &dst); + let mut output = String::with_capacity(100); + for (alias, items) in &cache.aliases { + if items.is_empty() { + continue + } + output.push_str(&format!("\"{}\":[{}],", + alias, + items.iter() + .map(|v| show_item(v, &krate.name)) + .collect::>() + .join(","))); + } + all_aliases.push(format!("ALIASES['{}'] = {{{}}};", krate.name, output)); + all_aliases.sort(); + try_err!(writeln!(&mut w, "var ALIASES = {{}};"), &dst); + for aliases in &all_aliases { + try_err!(writeln!(&mut w, "{}", aliases), &dst); + } + } + // Update the search index let dst = cx.dst.join("search-index.js"); let mut all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst); @@ -1251,13 +1288,13 @@ impl DocFolder for Cache { // `public_items` map, so we can skip inserting into the // paths map if there was already an entry present and we're // not a public item. - if - !self.paths.contains_key(&item.def_id) || - self.access_levels.is_public(item.def_id) + if !self.paths.contains_key(&item.def_id) || + self.access_levels.is_public(item.def_id) { self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } + self.add_aliases(&item); } // Link variants to their parent enum because pages aren't emitted // for each variant. @@ -1268,6 +1305,7 @@ impl DocFolder for Cache { } clean::PrimitiveItem(..) if item.visibility.is_some() => { + self.add_aliases(&item); self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } @@ -1372,6 +1410,36 @@ impl<'a> Cache { } } } + + fn add_aliases(&mut self, item: &clean::Item) { + if item.def_id.index == CRATE_DEF_INDEX { + return + } + if let Some(ref item_name) = item.name { + let path = self.paths.get(&item.def_id) + .map(|p| p.0.join("::").to_string()) + .unwrap_or("std".to_owned()); + for alias in item.attrs.lists("doc") + .filter(|a| a.check_name("alias")) + .filter_map(|a| a.value_str() + .map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::>() + .into_iter() { + self.aliases.entry(alias) + .or_insert(Vec::with_capacity(1)) + .push(IndexItem { + ty: item.type_(), + name: item_name.to_string(), + path: path.clone(), + desc: String::new(), + parent: None, + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + } } #[derive(Debug, Eq, PartialEq, Hash)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7d896695311..579fd0eaf3f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -316,6 +316,7 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] +#![feature(doc_alias)] #![default_lib_allocator] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index ce4bbfffc2e..e2fcfb7c4b1 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -9,6 +9,8 @@ // except according to those terms. #[doc(primitive = "bool")] +#[doc(alias = "true")] +#[doc(alias = "false")] // /// The boolean type. /// @@ -68,6 +70,7 @@ mod prim_bool { } #[doc(primitive = "never")] +#[doc(alias = "!")] // /// The `!` type, also called "never". /// diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6426c9a92f2..3f0a402c213 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -460,6 +460,9 @@ declare_features! ( (active, proc_macro_mod, "1.27.0", None, None), (active, proc_macro_expr, "1.27.0", None, None), (active, proc_macro_non_items, "1.27.0", None, None), + + // #[doc(alias = "...")] + (active, doc_alias, "1.27.0", None, None), ); declare_features! ( @@ -1455,6 +1458,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, doc_spotlight, attr.span, "#[doc(spotlight)] is experimental" ); + } else if content.iter().any(|c| c.check_name("alias")) { + gate_feature_post!(&self, doc_alias, attr.span, + "#[doc(alias = \"...\")] is experimental" + ); } } } -- cgit 1.4.1-3-g733a5 From 84b91d6f5c7a49159f46f9bec37b57bd7e0a61be Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 19 Apr 2018 19:56:10 +0200 Subject: add more aliases --- src/libcore/lib.rs | 1 + src/libcore/macros.rs | 1 + src/libcore/ops/arith.rs | 16 ++++++++++++++++ src/libcore/ops/index.rs | 6 ++++++ src/libcore/ops/try.rs | 1 + src/libstd/primitive_docs.rs | 7 +++++++ 6 files changed, 32 insertions(+) (limited to 'src/libstd') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ea7a46f44ae..2f3a7ebbe77 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -98,6 +98,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(doc_alias)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 90a9cb3379b..346d404fa8c 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -295,6 +295,7 @@ macro_rules! debug_assert_ne { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "?")] macro_rules! try { ($expr:expr) => (match $expr { $crate::result::Result::Ok(val) => val, diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 88db019b02f..a1f6030428f 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -87,6 +87,7 @@ message="cannot add `{RHS}` to `{Self}`", label="no implementation for `{Self} + {RHS}`", )] +#[doc(alias = "+")] pub trait Add { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -183,6 +184,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot subtract `{RHS}` from `{Self}`", label="no implementation for `{Self} - {RHS}`")] +#[doc(alias = "-")] pub trait Sub { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -301,6 +303,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`", label="no implementation for `{Self} * {RHS}`")] +#[doc(alias = "*")] pub trait Mul { /// The resulting type after applying the `*` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -423,6 +426,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`", label="no implementation for `{Self} / {RHS}`")] +#[doc(alias = "/")] pub trait Div { /// The resulting type after applying the `/` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -506,6 +510,7 @@ div_impl_float! { f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`", label="no implementation for `{Self} % {RHS}`")] +#[doc(alias = "%")] pub trait Rem { /// The resulting type after applying the `%` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -589,6 +594,7 @@ rem_impl_float! { f32 f64 } /// ``` #[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "-")] pub trait Neg { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] @@ -664,6 +670,8 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`", label="no implementation for `{Self} += {Rhs}`")] +#[doc(alias = "+")] +#[doc(alias = "+=")] pub trait AddAssign { /// Performs the `+=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -718,6 +726,8 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot subtract-assign `{Rhs}` from `{Self}`", label="no implementation for `{Self} -= {Rhs}`")] +#[doc(alias = "-")] +#[doc(alias = "-=")] pub trait SubAssign { /// Performs the `-=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -763,6 +773,8 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`", label="no implementation for `{Self} *= {Rhs}`")] +#[doc(alias = "*")] +#[doc(alias = "*=")] pub trait MulAssign { /// Performs the `*=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -808,6 +820,8 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`", label="no implementation for `{Self} /= {Rhs}`")] +#[doc(alias = "/")] +#[doc(alias = "/=")] pub trait DivAssign { /// Performs the `/=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -856,6 +870,8 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``", label="no implementation for `{Self} %= {Rhs}`")] +#[doc(alias = "%")] +#[doc(alias = "%=")] pub trait RemAssign { /// Performs the `%=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index d65c0aba504..0a0e92a9180 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -62,6 +62,9 @@ #[lang = "index"] #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "]")] +#[doc(alias = "[")] +#[doc(alias = "[]")] pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -146,6 +149,9 @@ pub trait Index { #[lang = "index_mut"] #[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] pub trait IndexMut: Index { /// Performs the mutable indexing (`container[index]`) operation. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index ef6a8fb6a61..4f2d30aa6a8 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -28,6 +28,7 @@ that implement `{Try}`", label="the `?` operator cannot be applied to type `{Self}`") )] +#[doc(alias = "?")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index e2fcfb7c4b1..8248ee71474 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -502,6 +502,9 @@ mod prim_pointer { } mod prim_array { } #[doc(primitive = "slice")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] // /// A dynamically-sized view into a contiguous sequence, `[T]`. /// @@ -600,6 +603,9 @@ mod prim_slice { } mod prim_str { } #[doc(primitive = "tuple")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] // /// A finite heterogeneous sequence, `(T, U, ..)`. /// @@ -822,6 +828,7 @@ mod prim_isize { } mod prim_usize { } #[doc(primitive = "reference")] +#[doc(alias = "&")] // /// References, both shared and mutable. /// -- cgit 1.4.1-3-g733a5 From e513c1bd314bbeb6295a7a759de8833b52ff854d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 20 Apr 2018 21:05:13 -0700 Subject: Replace GlobalAlloc::oom with a lang item --- src/liballoc/alloc.rs | 35 ++++++++++++++++---------------- src/liballoc/arc.rs | 4 ++-- src/liballoc/rc.rs | 4 ++-- src/liballoc_jemalloc/lib.rs | 5 ++--- src/liballoc_system/lib.rs | 2 +- src/libcore/alloc.rs | 11 ---------- src/librustc/middle/lang_items.rs | 3 ++- src/librustc/middle/weak_lang_items.rs | 1 + src/librustc_allocator/lib.rs | 5 ----- src/libstd/alloc.rs | 13 ++++++++++-- src/libstd/collections/hash/map.rs | 4 ++-- src/libstd/collections/hash/table.rs | 6 +++--- src/libstd/lib.rs | 3 ++- src/test/run-pass/allocator-alloc-one.rs | 6 ++---- src/test/run-pass/realloc-16687.rs | 6 +++--- src/test/run-pass/regions-mock-trans.rs | 4 ++-- 16 files changed, 53 insertions(+), 59 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 68a617e0ffe..a9c06523718 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -48,9 +48,6 @@ extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom() -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] @@ -107,16 +104,6 @@ unsafe impl GlobalAlloc for Global { let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); ptr as *mut Opaque } - - #[inline] - fn oom(&self) -> ! { - unsafe { - #[cfg(not(stage0))] - __rust_oom(); - #[cfg(stage0)] - __rust_oom(&mut 0); - } - } } unsafe impl Alloc for Global { @@ -147,7 +134,7 @@ unsafe impl Alloc for Global { #[inline] fn oom(&mut self) -> ! { - GlobalAlloc::oom(self) + oom() } } @@ -165,7 +152,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if !ptr.is_null() { ptr as *mut u8 } else { - Global.oom() + oom() } } } @@ -182,19 +169,33 @@ pub(crate) unsafe fn box_free(ptr: *mut T) { } } +#[cfg(stage0)] +pub fn oom() -> ! { + unsafe { ::core::intrinsics::abort() } +} + +#[cfg(not(stage0))] +pub fn oom() -> ! { + extern { + #[lang = "oom"] + fn oom_impl() -> !; + } + unsafe { oom_impl() } +} + #[cfg(test)] mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use alloc::{Global, Alloc, Layout}; + use alloc::{Global, Alloc, Layout, oom}; #[test] fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); let mut i = ptr.cast::().as_ptr(); let end = i.offset(layout.size() as isize); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 225b055d8ee..f5980f4599e 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -31,7 +31,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free}; +use alloc::{Global, Alloc, Layout, box_free, oom}; use boxed::Box; use string::String; use vec::Vec; @@ -553,7 +553,7 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index de0422d82bb..8fb8e111754 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, Opaque, box_free}; +use alloc::{Global, Alloc, Layout, Opaque, box_free, oom}; use string::String; use vec::Vec; @@ -668,7 +668,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 2b66c293f21..8b118a2cabb 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -30,8 +30,6 @@ extern crate libc; pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { - use core::alloc::GlobalAlloc; - use alloc_system::System; use libc::{c_int, c_void, size_t}; // Note that the symbols here are prefixed by default on macOS and Windows (we @@ -100,10 +98,11 @@ mod contents { ptr } + #[cfg(stage0)] #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_oom() -> ! { - System.oom() + ::alloc_system::oom() } #[no_mangle] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index fd8109e2a4a..aff98ae2f10 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -368,7 +368,7 @@ mod platform { } #[inline] -fn oom() -> ! { +pub fn oom() -> ! { write_to_stderr("fatal runtime error: memory allocation failed"); unsafe { ::core::intrinsics::abort(); diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 54440eaa40f..7d893676a6c 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -451,17 +451,6 @@ pub unsafe trait GlobalAlloc { } new_ptr } - - /// Aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request, and wish to abandon - /// computation rather than attempt to recover locally. - fn oom(&self) -> ! { - unsafe { ::intrinsics::abort() } - } } /// An implementation of `Alloc` can allocate, reallocate, and diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index c7412dbeeb3..95e92e21b09 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -303,7 +303,8 @@ language_item_table! { ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; BoxFreeFnLangItem, "box_free", box_free_fn; - DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; + DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; + OomLangItem, "oom", oom; StartFnLangItem, "start", start_fn; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index e19f4483f65..a2bceb19102 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -151,4 +151,5 @@ weak_lang_items! { panic_fmt, PanicFmtLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; + oom, OomLangItem, rust_oom; } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 706eab72d44..f3103e21606 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -23,11 +23,6 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, - AllocatorMethod { - name: "oom", - inputs: &[], - output: AllocatorTy::Bang, - }, AllocatorMethod { name: "dealloc", inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index ff578ec42d2..a8578404467 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -13,10 +13,18 @@ #![unstable(issue = "32838", feature = "allocator_api")] #[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; -#[doc(inline)] pub use alloc_crate::alloc::Global; +#[doc(inline)] pub use alloc_crate::alloc::{Global, oom}; #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; +#[cfg(not(stage0))] +#[cfg(not(test))] +#[doc(hidden)] +#[lang = "oom"] +pub extern fn rust_oom() -> ! { + rtabort!("memory allocation failed"); +} + #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] @@ -35,10 +43,11 @@ pub mod __default_lib_allocator { System.alloc(layout) as *mut u8 } + #[cfg(stage0)] #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_oom() -> ! { - System.oom() + super::oom() } #[no_mangle] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4fe5c11beb4..a8c70489f44 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,7 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::{Global, Alloc, CollectionAllocErr}; +use alloc::{CollectionAllocErr, oom}; use cell::Cell; use borrow::Borrow; use cmp::max; @@ -784,7 +784,7 @@ impl HashMap pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(()) => { /* yay */ } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 115f9628a23..52c53dc3b12 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, CollectionAllocErr}; +use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom}; use cmp; use hash::{BuildHasher, Hash, Hasher}; use marker; @@ -770,7 +770,7 @@ impl RawTable { unsafe fn new_uninitialized(capacity: usize) -> RawTable { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(table) => { table } } } @@ -809,7 +809,7 @@ impl RawTable { pub fn new(capacity: usize) -> RawTable { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(table) => { table } } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 43a8d4446fa..1df7bc777d1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -482,7 +482,6 @@ pub mod path; pub mod process; pub mod sync; pub mod time; -pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] @@ -496,6 +495,8 @@ pub mod heap { mod sys_common; mod sys; +pub mod alloc; + // Private support modules mod panicking; mod memchr; diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index d4fcdcf743b..12b115d0938 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -10,13 +10,11 @@ #![feature(allocator_api, nonnull)] -use std::alloc::{Alloc, Global}; +use std::alloc::{Alloc, Global, oom}; fn main() { unsafe { - let ptr = Global.alloc_one::().unwrap_or_else(|_| { - Global.oom() - }); + let ptr = Global.alloc_one::().unwrap_or_else(|_| oom()); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); Global.dealloc_one(ptr); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index afa3494c389..308792e5d89 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -15,7 +15,7 @@ #![feature(heap_api, allocator_api)] -use std::alloc::{Global, Alloc, Layout}; +use std::alloc::{Global, Alloc, Layout, oom}; use std::ptr::{self, NonNull}; fn main() { @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom()); + let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -73,7 +73,7 @@ unsafe fn test_triangle() -> bool { } let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 44be59f5c5b..60a7f70931d 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -12,7 +12,7 @@ #![feature(allocator_api)] -use std::alloc::{Alloc, Global, Layout}; +use std::alloc::{Alloc, Global, Layout, oom}; use std::ptr::NonNull; struct arena(()); @@ -33,7 +33,7 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Global.alloc(Layout::new::()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); &*(ptr.as_ptr() as *const _) } } -- cgit 1.4.1-3-g733a5 From 1133a149f1bd89bbc9303e3514a6bc20c3a5fc8b Mon Sep 17 00:00:00 2001 From: George Burton Date: Sun, 22 Apr 2018 22:57:52 +0100 Subject: Implement From for more types on Cow --- src/liballoc/string.rs | 8 ++++++++ src/liballoc/vec.rs | 7 +++++++ src/libstd/ffi/c_str.rs | 24 ++++++++++++++++++++++++ src/libstd/ffi/os_str.rs | 24 ++++++++++++++++++++++++ src/libstd/path.rs | 8 ++++++++ 5 files changed, 71 insertions(+) (limited to 'src/libstd') diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 2f84d5f7f86..5f684361fdc 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2239,6 +2239,14 @@ impl<'a> From for Cow<'a, str> { } } +#[stable(feature = "cow_from_string_ref", since = "1.28.0")] +impl<'a> From<&'a String> for Cow<'a, str> { + #[inline] + fn from(s: &'a String) -> Cow<'a, str> { + Cow::Borrowed(s.as_str()) + } +} + #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a> FromIterator for Cow<'a, str> { fn from_iter>(it: I) -> Cow<'a, str> { diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b184404c15b..be4c80c85d9 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2285,6 +2285,13 @@ impl<'a, T: Clone> From> for Cow<'a, [T]> { } } +#[stable(feature = "cow_from_vec_ref", since = "1.28.0")] +impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { + fn from(v: &'a Vec) -> Cow<'a, [T]> { + Cow::Borrowed(v.as_slice()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { fn from_iter>(it: I) -> Cow<'a, [T]> { diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index c88c2bc9137..08a1596ef25 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -706,6 +706,30 @@ impl From for Box { } } +#[stable(feature = "cow_from_cstr", since = "1.28.0")] +impl<'a> From for Cow<'a, CStr> { + #[inline] + fn from(s: CString) -> Cow<'a, CStr> { + Cow::Owned(s) + } +} + +#[stable(feature = "cow_from_cstr", since = "1.28.0")] +impl<'a> From<&'a CStr> for Cow<'a, CStr> { + #[inline] + fn from(s: &'a CStr) -> Cow<'a, CStr> { + Cow::Borrowed(s) + } +} + +#[stable(feature = "cow_from_cstr", since = "1.28.0")] +impl<'a> From<&'a CString> for Cow<'a, CStr> { + #[inline] + fn from(s: &'a CString) -> Cow<'a, CStr> { + Cow::Borrowed(s.as_c_str()) + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { #[inline] diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 4850ed0c5be..e42a28ed88f 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -664,6 +664,30 @@ impl<'a> From<&'a OsStr> for Rc { } } +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From for Cow<'a, OsStr> { + #[inline] + fn from(s: OsString) -> Cow<'a, OsStr> { + Cow::Owned(s) + } +} + +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { + #[inline] + fn from(s: &'a OsStr) -> Cow<'a, OsStr> { + Cow::Borrowed(s) + } +} + +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From<&'a OsString> for Cow<'a, OsStr> { + #[inline] + fn from(s: &'a OsString) -> Cow<'a, OsStr> { + Cow::Borrowed(s.as_os_str()) + } +} + #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ec961575473..19f38e4d6d9 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1532,6 +1532,14 @@ impl<'a> From for Cow<'a, Path> { } } +#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")] +impl<'a> From<&'a PathBuf> for Cow<'a, Path> { + #[inline] + fn from(p: &'a PathBuf) -> Cow<'a, Path> { + Cow::Borrowed(p.as_path()) + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { #[inline] -- cgit 1.4.1-3-g733a5 From a5655b81a3bad56beaa161662177192681832532 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 31 Mar 2018 12:09:10 +0200 Subject: Move description of the Error trait to its own doc-comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … rather than the module’s. Remove code definition of the Error trait from its doc-comment It was out of date, and rustdoc already shows the same information. Add a default impl for Error::description and document it as deprecated. It is redundant with Display while being much less flexible for implementors. This is only a "soft" deprecation: it is not worth the hassle of a warning to existing users. Tweak Error trait docs to reflect actual requirements --- src/libstd/error.rs | 63 ++++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 39 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 749b8ccc13d..0954649653c 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -9,34 +9,6 @@ // except according to those terms. //! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in [`Result`]. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail (via -//! [`Display`]) and cause chain information: -//! -//! ``` -//! use std::fmt::Display; -//! -//! trait Error: Display { -//! fn description(&self) -> &str; -//! -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The [`cause`] method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via [`cause`] chains. -//! -//! [`Result`]: ../result/enum.Result.html -//! [`Display`]: ../fmt/trait.Display.html -//! [`cause`]: trait.Error.html#method.cause #![stable(feature = "rust1", since = "1.0.0")] @@ -63,33 +35,46 @@ use num; use str; use string; -/// Base functionality for all errors in Rust. +/// `Error` is a trait representing the basic expectations for error values, +/// i.e. values of type `E` in [`Result`]. Errors must describe +/// themselves through the [`Display`] and [`Debug`] traits, and may provide +/// cause chain information: +/// +/// The [`cause`] method is generally used when errors cross "abstraction +/// boundaries", i.e. when a one module must report an error that is "caused" +/// by an error from a lower-level module. This setup makes it possible for the +/// high-level module to provide its own errors that do not commit to any +/// particular implementation, but also reveal some of its implementation for +/// debugging via [`cause`] chains. +/// +/// [`Result`]: ../result/enum.Result.html +/// [`Display`]: ../fmt/trait.Display.html +/// [`cause`]: trait.Error.html#method.cause #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { - /// A short description of the error. + /// **This method is soft-deprecated.** /// - /// The description should only be used for a simple message. - /// It should not contain newlines or sentence-ending punctuation, - /// to facilitate embedding in larger user-facing strings. - /// For showing formatted error messages with more information see - /// [`Display`]. + /// Although using it won’t cause compilation warning, + /// new code should use [`Display`] instead + /// and new `impl`s can omit it. /// /// [`Display`]: ../fmt/trait.Display.html /// /// # Examples /// /// ``` - /// use std::error::Error; - /// /// match "xc".parse::() { /// Err(e) => { - /// println!("Error: {}", e.description()); + /// // Print `e` itself, not `e.description()`. + /// println!("Error: {}", e); /// } /// _ => println!("No error"), /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn description(&self) -> &str; + fn description(&self) -> &str { + "" + } /// The lower-level cause of this error, if any. /// -- cgit 1.4.1-3-g733a5 From f6a833a99a76e015cae0410f20af9f3767a14911 Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 22 Apr 2018 19:17:08 +0100 Subject: Suggest alternatives to Error::description() --- src/libstd/error.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 0954649653c..817eea5eaf1 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -58,6 +58,8 @@ pub trait Error: Debug + Display { /// new code should use [`Display`] instead /// and new `impl`s can omit it. /// + /// To obtain error description as a string, use `to_string()`. + /// /// [`Display`]: ../fmt/trait.Display.html /// /// # Examples @@ -73,7 +75,7 @@ pub trait Error: Debug + Display { /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn description(&self) -> &str { - "" + "description() is deprecated; use Display" } /// The lower-level cause of this error, if any. -- cgit 1.4.1-3-g733a5 From ea8131de53a7aa587938106cfb5b0ec77b127bca Mon Sep 17 00:00:00 2001 From: George Burton Date: Fri, 27 Apr 2018 20:27:38 +0100 Subject: Add cstring_from_cow_cstr and osstring_from_cow_osstr --- src/libstd/ffi/c_str.rs | 8 ++++++++ src/libstd/ffi/os_str.rs | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 08a1596ef25..7f38cadfb22 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -682,6 +682,14 @@ impl Borrow for CString { fn borrow(&self) -> &CStr { self } } +#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")] +impl<'a> From> for CString { + #[inline] + fn from(s: Cow<'a, CStr>) -> Self { + s.into_owned() + } +} + #[stable(feature = "box_from_c_str", since = "1.17.0")] impl<'a> From<&'a CStr> for Box { fn from(s: &'a CStr) -> Box { diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index e42a28ed88f..0a3148029d0 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -688,6 +688,14 @@ impl<'a> From<&'a OsString> for Cow<'a, OsStr> { } } +#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] +impl<'a> From> for OsString { + #[inline] + fn from(s: Cow<'a, OsStr>) -> Self { + s.into_owned() + } +} + #[stable(feature = "box_default_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { -- cgit 1.4.1-3-g733a5 From d87b039ea61b5be401f855b6ab788ddd6e04c847 Mon Sep 17 00:00:00 2001 From: George Burton Date: Fri, 27 Apr 2018 20:41:00 +0100 Subject: Add pathbuf_from_cow_path --- src/libstd/path.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 19f38e4d6d9..b7ab14b29ca 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1540,6 +1540,14 @@ impl<'a> From<&'a PathBuf> for Cow<'a, Path> { } } +#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")] +impl<'a> From> for PathBuf { + #[inline] + fn from(p: Cow<'a, Path>) -> Self { + p.into_owned() + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { #[inline] -- cgit 1.4.1-3-g733a5 From f3e858aae761b30a56e8b03f510f360edeb3a2f1 Mon Sep 17 00:00:00 2001 From: George Burton Date: Fri, 27 Apr 2018 20:46:06 +0100 Subject: Update the stable attributes to use the current nightly version number --- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 2 +- src/libstd/ffi/c_str.rs | 8 ++++---- src/libstd/ffi/os_str.rs | 8 ++++---- src/libstd/path.rs | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 5f684361fdc..61a207fc5b3 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2239,7 +2239,7 @@ impl<'a> From for Cow<'a, str> { } } -#[stable(feature = "cow_from_string_ref", since = "1.28.0")] +#[stable(feature = "cow_from_string_ref", since = "1.27.0")] impl<'a> From<&'a String> for Cow<'a, str> { #[inline] fn from(s: &'a String) -> Cow<'a, str> { diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index be4c80c85d9..315a8a0aad0 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2285,7 +2285,7 @@ impl<'a, T: Clone> From> for Cow<'a, [T]> { } } -#[stable(feature = "cow_from_vec_ref", since = "1.28.0")] +#[stable(feature = "cow_from_vec_ref", since = "1.27.0")] impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { fn from(v: &'a Vec) -> Cow<'a, [T]> { Cow::Borrowed(v.as_slice()) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 7f38cadfb22..10f59b0a3cc 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -682,7 +682,7 @@ impl Borrow for CString { fn borrow(&self) -> &CStr { self } } -#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")] +#[stable(feature = "cstring_from_cow_cstr", since = "1.27.0")] impl<'a> From> for CString { #[inline] fn from(s: Cow<'a, CStr>) -> Self { @@ -714,7 +714,7 @@ impl From for Box { } } -#[stable(feature = "cow_from_cstr", since = "1.28.0")] +#[stable(feature = "cow_from_cstr", since = "1.27.0")] impl<'a> From for Cow<'a, CStr> { #[inline] fn from(s: CString) -> Cow<'a, CStr> { @@ -722,7 +722,7 @@ impl<'a> From for Cow<'a, CStr> { } } -#[stable(feature = "cow_from_cstr", since = "1.28.0")] +#[stable(feature = "cow_from_cstr", since = "1.27.0")] impl<'a> From<&'a CStr> for Cow<'a, CStr> { #[inline] fn from(s: &'a CStr) -> Cow<'a, CStr> { @@ -730,7 +730,7 @@ impl<'a> From<&'a CStr> for Cow<'a, CStr> { } } -#[stable(feature = "cow_from_cstr", since = "1.28.0")] +#[stable(feature = "cow_from_cstr", since = "1.27.0")] impl<'a> From<&'a CString> for Cow<'a, CStr> { #[inline] fn from(s: &'a CString) -> Cow<'a, CStr> { diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 0a3148029d0..d865ffa8e2f 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -664,7 +664,7 @@ impl<'a> From<&'a OsStr> for Rc { } } -#[stable(feature = "cow_from_osstr", since = "1.28.0")] +#[stable(feature = "cow_from_osstr", since = "1.27.0")] impl<'a> From for Cow<'a, OsStr> { #[inline] fn from(s: OsString) -> Cow<'a, OsStr> { @@ -672,7 +672,7 @@ impl<'a> From for Cow<'a, OsStr> { } } -#[stable(feature = "cow_from_osstr", since = "1.28.0")] +#[stable(feature = "cow_from_osstr", since = "1.27.0")] impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { #[inline] fn from(s: &'a OsStr) -> Cow<'a, OsStr> { @@ -680,7 +680,7 @@ impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { } } -#[stable(feature = "cow_from_osstr", since = "1.28.0")] +#[stable(feature = "cow_from_osstr", since = "1.27.0")] impl<'a> From<&'a OsString> for Cow<'a, OsStr> { #[inline] fn from(s: &'a OsString) -> Cow<'a, OsStr> { @@ -688,7 +688,7 @@ impl<'a> From<&'a OsString> for Cow<'a, OsStr> { } } -#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] +#[stable(feature = "osstring_from_cow_osstr", since = "1.27.0")] impl<'a> From> for OsString { #[inline] fn from(s: Cow<'a, OsStr>) -> Self { diff --git a/src/libstd/path.rs b/src/libstd/path.rs index b7ab14b29ca..83633210ff2 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1532,7 +1532,7 @@ impl<'a> From for Cow<'a, Path> { } } -#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")] +#[stable(feature = "cow_from_pathbuf_ref", since = "1.27.0")] impl<'a> From<&'a PathBuf> for Cow<'a, Path> { #[inline] fn from(p: &'a PathBuf) -> Cow<'a, Path> { @@ -1540,7 +1540,7 @@ impl<'a> From<&'a PathBuf> for Cow<'a, Path> { } } -#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")] +#[stable(feature = "pathbuf_from_cow_path", since = "1.27.0")] impl<'a> From> for PathBuf { #[inline] fn from(p: Cow<'a, Path>) -> Self { -- cgit 1.4.1-3-g733a5 From c1bb1caa11ba30b42f62b58f74e530288779eb85 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 28 Apr 2018 14:14:21 -0700 Subject: std: Inline `DefaultResizePolicy::new` This should allow us to tighten up the [codegen][example] a bit more, avoiding a function call across object boundaries in the default optimized case. [example]: https://play.rust-lang.org/?gist=c1179088b0f8a4dcd93a9906463f993d&version=stable&mode=release --- src/libstd/collections/hash/map.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a8c70489f44..a7eb002d5a1 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -33,6 +33,7 @@ const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two struct DefaultResizePolicy; impl DefaultResizePolicy { + #[inline] fn new() -> DefaultResizePolicy { DefaultResizePolicy } -- cgit 1.4.1-3-g733a5 From 3dbdccc6a9c1ead58325d415381b25c676386c34 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Sat, 10 Mar 2018 16:23:28 -0800 Subject: stabilize `#[must_use]` for functions and must-use operators This is in the matter of RFC 1940 and tracking issue #43302. --- .../src/language-features/fn-must-use.md | 30 ---- src/liballoc/lib.rs | 2 +- src/liballoc/tests/slice.rs | 1 + src/libcore/lib.rs | 2 +- src/librustc_lint/unused.rs | 104 +++++++------- src/libstd/ffi/c_str.rs | 2 + src/libstd/sync/mpsc/select.rs | 2 + src/libsyntax/feature_gate.rs | 22 +-- .../ui/feature-gate-fn_must_use-cap-lints-allow.rs | 22 --- ...feature-gate-fn_must_use-cap-lints-allow.stderr | 8 -- src/test/ui/feature-gate-fn_must_use.rs | 31 ----- src/test/ui/feature-gate-fn_must_use.stderr | 24 ---- .../issue-43106-gating-of-builtin-attrs.rs | 1 - .../issue-43106-gating-of-builtin-attrs.stderr | 154 ++++++++++----------- src/test/ui/fn_must_use.rs | 78 +++++++++++ src/test/ui/fn_must_use.stderr | 48 +++++++ src/test/ui/lint/must-use-ops.rs | 1 - src/test/ui/lint/must-use-ops.stderr | 44 +++--- .../rfc_1940-must_use_on_functions/fn_must_use.rs | 79 ----------- .../fn_must_use.stderr | 48 ------- src/test/ui/span/gated-features-attr-spans.rs | 23 --- src/test/ui/span/gated-features-attr-spans.stderr | 18 +-- 22 files changed, 284 insertions(+), 460 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/fn-must-use.md delete mode 100644 src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs delete mode 100644 src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr delete mode 100644 src/test/ui/feature-gate-fn_must_use.rs delete mode 100644 src/test/ui/feature-gate-fn_must_use.stderr create mode 100644 src/test/ui/fn_must_use.rs create mode 100644 src/test/ui/fn_must_use.stderr delete mode 100644 src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs delete mode 100644 src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr (limited to 'src/libstd') diff --git a/src/doc/unstable-book/src/language-features/fn-must-use.md b/src/doc/unstable-book/src/language-features/fn-must-use.md deleted file mode 100644 index 71b6cd663a0..00000000000 --- a/src/doc/unstable-book/src/language-features/fn-must-use.md +++ /dev/null @@ -1,30 +0,0 @@ -# `fn_must_use` - -The tracking issue for this feature is [#43302]. - -[#43302]: https://github.com/rust-lang/rust/issues/43302 - ------------------------- - -The `fn_must_use` feature allows functions and methods to be annotated with -`#[must_use]`, indicating that the `unused_must_use` lint should require their -return values to be used (similarly to how types annotated with `must_use`, -most notably `Result`, are linted if not used). - -## Examples - -```rust -#![feature(fn_must_use)] - -#[must_use] -fn double(x: i32) -> i32 { - 2 * x -} - -fn main() { - double(4); // warning: unused return value of `double` which must be used - - let _ = double(4); // (no warning) -} - -``` diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 021395d0c82..fa74352c23c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -96,7 +96,7 @@ #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] -#![feature(fn_must_use)] +#![cfg_attr(stage0, feature(fn_must_use))] #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 99d9c51efc7..6fd0b33f02a 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -1282,6 +1282,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)] fn test_box_slice_clone_panics() { use std::sync::Arc; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0e21a3327fd..f4ed24cc3a3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -76,7 +76,6 @@ #![feature(doc_cfg)] #![feature(doc_spotlight)] #![feature(extern_types)] -#![feature(fn_must_use)] #![feature(fundamental)] #![feature(intrinsics)] #![feature(iterator_flatten)] @@ -114,6 +113,7 @@ #![cfg_attr(stage0, feature(target_feature))] #![cfg_attr(stage0, feature(cfg_target_feature))] +#![cfg_attr(stage0, feature(fn_must_use))] #[prelude_import] #[allow(unused)] diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index c32e9cdce0e..9e1b75ba336 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -73,59 +73,59 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let mut fn_warned = false; let mut op_warned = false; - if cx.tcx.features().fn_must_use { - let maybe_def = match expr.node { - hir::ExprCall(ref callee, _) => { - match callee.node { - hir::ExprPath(ref qpath) => { - let def = cx.tables.qpath_def(qpath, callee.hir_id); - if let Def::Fn(_) = def { - Some(def) - } else { // `Def::Local` if it was a closure, for which we - None // do not currently support must-use linting - } - }, - _ => None - } - }, - hir::ExprMethodCall(..) => { - cx.tables.type_dependent_defs().get(expr.hir_id).cloned() - }, - _ => None - }; - if let Some(def) = maybe_def { - let def_id = def.def_id(); - fn_warned = check_must_use(cx, def_id, s.span, "return value of "); - } - let must_use_op = match expr.node { - // Hardcoding operators here seemed more expedient than the - // refactoring that would be needed to look up the `#[must_use]` - // attribute which does exist on the comparison trait methods - hir::ExprBinary(bin_op, ..) => { - match bin_op.node { - hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { - Some("comparison") - }, - hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => { - Some("arithmetic operation") - }, - hir::BiAnd | hir::BiOr => { - Some("logical operation") - }, - hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => { - Some("bitwise operation") - }, - } - }, - hir::ExprUnary(..) => Some("unary operation"), - _ => None - }; - if let Some(must_use_op) = must_use_op { - cx.span_lint(UNUSED_MUST_USE, expr.span, - &format!("unused {} which must be used", must_use_op)); - op_warned = true; - } + let maybe_def = match expr.node { + hir::ExprCall(ref callee, _) => { + match callee.node { + hir::ExprPath(ref qpath) => { + let def = cx.tables.qpath_def(qpath, callee.hir_id); + if let Def::Fn(_) = def { + Some(def) + } else { // `Def::Local` if it was a closure, for which we + None // do not currently support must-use linting + } + }, + _ => None + } + }, + hir::ExprMethodCall(..) => { + cx.tables.type_dependent_defs().get(expr.hir_id).cloned() + }, + _ => None + }; + if let Some(def) = maybe_def { + let def_id = def.def_id(); + fn_warned = check_must_use(cx, def_id, s.span, "return value of "); } + let must_use_op = match expr.node { + // Hardcoding operators here seemed more expedient than the + // refactoring that would be needed to look up the `#[must_use]` + // attribute which does exist on the comparison trait methods + hir::ExprBinary(bin_op, ..) => { + match bin_op.node { + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { + Some("comparison") + }, + hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => { + Some("arithmetic operation") + }, + hir::BiAnd | hir::BiOr => { + Some("logical operation") + }, + hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => { + Some("bitwise operation") + }, + } + }, + hir::ExprUnary(..) => Some("unary operation"), + _ => None + }; + + if let Some(must_use_op) = must_use_op { + cx.span_lint(UNUSED_MUST_USE, expr.span, + &format!("unused {} which must be used", must_use_op)); + op_warned = true; + } + if !(ty_warned || fn_warned || op_warned) { cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index c88c2bc9137..d4937c00012 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -988,6 +988,7 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let ptr = CString::new("Hello").unwrap().as_ptr(); @@ -1003,6 +1004,7 @@ impl CStr { /// To fix the problem, bind the `CString` to a local variable: /// /// ```no_run + /// # #![allow(unused_must_use)] /// use std::ffi::{CString}; /// /// let hello = CString::new("Hello").unwrap(); diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index a9f3cea243f..9310dad9172 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -518,6 +518,7 @@ mod tests { } } + #[allow(unused_must_use)] #[test] fn cloning() { let (tx1, rx1) = channel::(); @@ -540,6 +541,7 @@ mod tests { tx3.send(()).unwrap(); } + #[allow(unused_must_use)] #[test] fn cloning2() { let (tx1, rx1) = channel::(); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a4a83712a08..f16b1ba440a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -369,9 +369,6 @@ declare_features! ( // #[doc(include="some-file")] (active, external_doc, "1.22.0", Some(44732), None), - // allow `#[must_use]` on functions and comparison operators (RFC 1940) - (active, fn_must_use, "1.21.0", Some(43302), None), - // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008) (active, non_exhaustive, "1.22.0", Some(44109), None), @@ -591,6 +588,8 @@ declare_features! ( (accepted, target_feature, "1.27.0", None, None), // Trait object syntax with `dyn` prefix (accepted, dyn_trait, "1.27.0", Some(44662), None), + // allow `#[must_use]` on functions; and, must-use operators (RFC 1940) + (accepted, fn_must_use, "1.27.0", Some(43302), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1545,11 +1544,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { function may change over time, for now \ a top-level `fn main()` is required"); } - if let Some(attr) = attr::find_by_name(&i.attrs[..], "must_use") { - gate_feature_post!(&self, fn_must_use, attr.span, - "`#[must_use]` on functions is experimental", - GateStrength::Soft); - } } ast::ItemKind::Struct(..) => { @@ -1581,7 +1575,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "trait aliases are not yet fully implemented"); } - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { if polarity == ast::ImplPolarity::Negative { gate_feature_post!(&self, optin_builtin_traits, i.span, @@ -1594,16 +1588,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { i.span, "specialization is unstable"); } - - for impl_item in impl_items { - if let ast::ImplItemKind::Method(..) = impl_item.node { - if let Some(attr) = attr::find_by_name(&impl_item.attrs[..], "must_use") { - gate_feature_post!(&self, fn_must_use, attr.span, - "`#[must_use]` on methods is experimental", - GateStrength::Soft); - } - } - } } ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { diff --git a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs b/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs deleted file mode 100644 index 1c04199c05f..00000000000 --- a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: --cap-lints allow - -// This tests that the fn_must_use feature-gate warning respects the lint -// cap. (See discussion in Issue #44213.) - -#![feature(rustc_attrs)] - -#[must_use] // (no feature-gate warning because of the lint cap!) -fn need_to_use_it() -> bool { true } - -#[rustc_error] -fn main() {} //~ ERROR compilation successful diff --git a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr b/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr deleted file mode 100644 index a2c1dedff38..00000000000 --- a/src/test/ui/feature-gate-fn_must_use-cap-lints-allow.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: compilation successful - --> $DIR/feature-gate-fn_must_use-cap-lints-allow.rs:22:1 - | -LL | fn main() {} //~ ERROR compilation successful - | ^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate-fn_must_use.rs b/src/test/ui/feature-gate-fn_must_use.rs deleted file mode 100644 index 72fdcc76cf4..00000000000 --- a/src/test/ui/feature-gate-fn_must_use.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_attrs)] - -struct MyStruct; - -impl MyStruct { - #[must_use] //~ WARN `#[must_use]` on methods is experimental - fn need_to_use_method() -> bool { true } -} - -#[must_use] //~ WARN `#[must_use]` on functions is experimental -fn need_to_use_it() -> bool { true } - - -// Feature gates are tidy-required to have a specially named (or -// comment-annotated) compile-fail test (which MUST fail), but for -// backwards-compatibility reasons, we want `#[must_use]` on functions to be -// compilable even if the `fn_must_use` feature is absent, thus necessitating -// the usage of `#[rustc_error]` here, pragmatically if awkwardly solving this -// dilemma until a superior solution can be devised. -#[rustc_error] -fn main() {} //~ ERROR compilation successful diff --git a/src/test/ui/feature-gate-fn_must_use.stderr b/src/test/ui/feature-gate-fn_must_use.stderr deleted file mode 100644 index 431c57abd26..00000000000 --- a/src/test/ui/feature-gate-fn_must_use.stderr +++ /dev/null @@ -1,24 +0,0 @@ -warning: `#[must_use]` on methods is experimental (see issue #43302) - --> $DIR/feature-gate-fn_must_use.rs:16:5 - | -LL | #[must_use] //~ WARN `#[must_use]` on methods is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/feature-gate-fn_must_use.rs:20:1 - | -LL | #[must_use] //~ WARN `#[must_use]` on functions is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -error: compilation successful - --> $DIR/feature-gate-fn_must_use.rs:31:1 - | -LL | fn main() {} //~ ERROR compilation successful - | ^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 21950402c8c..7b0c81dbab6 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -661,7 +661,6 @@ mod must_use { mod inner { #![must_use="1400"] } #[must_use = "1400"] fn f() { } - //~^ WARN `#[must_use]` on functions is experimental #[must_use = "1400"] struct S; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 0beed627987..76ab50c9089 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -12,14 +12,6 @@ LL | mod inner { #![macro_escape] } | = help: consider an outer attribute, #[macro_use] mod ... -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 - | -LL | #[must_use = "1400"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - warning: unknown lint: `x5400` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:33 | @@ -799,433 +791,433 @@ LL | #[no_std = "2600"] | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:772:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:835:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1309,7 +1301,7 @@ LL | #![proc_macro_derive = "2500"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compilation successful - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:858:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:857:1 | LL | / fn main() { //~ ERROR compilation successful LL | | println!("Hello World"); diff --git a/src/test/ui/fn_must_use.rs b/src/test/ui/fn_must_use.rs new file mode 100644 index 00000000000..def23046db2 --- /dev/null +++ b/src/test/ui/fn_must_use.rs @@ -0,0 +1,78 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![warn(unused_must_use)] + +#[derive(PartialEq, Eq)] +struct MyStruct { + n: usize, +} + +impl MyStruct { + #[must_use] + fn need_to_use_this_method_value(&self) -> usize { + self.n + } +} + +trait EvenNature { + #[must_use = "no side effects"] + fn is_even(&self) -> bool; +} + +impl EvenNature for MyStruct { + fn is_even(&self) -> bool { + self.n % 2 == 0 + } +} + +trait Replaceable { + fn replace(&mut self, substitute: usize) -> usize; +} + +impl Replaceable for MyStruct { + // ↓ N.b.: `#[must_use]` attribute on a particular trait implementation + // method won't work; the attribute should be on the method signature in + // the trait's definition. + #[must_use] + fn replace(&mut self, substitute: usize) -> usize { + let previously = self.n; + self.n = substitute; + previously + } +} + +#[must_use = "it's important"] +fn need_to_use_this_value() -> bool { + false +} + +fn main() { + need_to_use_this_value(); //~ WARN unused return value + + let mut m = MyStruct { n: 2 }; + let n = MyStruct { n: 3 }; + + m.need_to_use_this_method_value(); //~ WARN unused return value + m.is_even(); // trait method! + //~^ WARN unused return value + + m.replace(3); // won't warn (annotation needs to be in trait definition) + + // comparison methods are `must_use` + 2.eq(&3); //~ WARN unused return value + m.eq(&n); //~ WARN unused return value + + // lint includes comparison operators + 2 == 3; //~ WARN unused comparison + m == n; //~ WARN unused comparison +} diff --git a/src/test/ui/fn_must_use.stderr b/src/test/ui/fn_must_use.stderr new file mode 100644 index 00000000000..5026dac0a94 --- /dev/null +++ b/src/test/ui/fn_must_use.stderr @@ -0,0 +1,48 @@ +warning: unused return value of `need_to_use_this_value` which must be used: it's important + --> $DIR/fn_must_use.rs:60:5 + | +LL | need_to_use_this_value(); //~ WARN unused return value + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/fn_must_use.rs:13:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used + --> $DIR/fn_must_use.rs:65:5 + | +LL | m.need_to_use_this_method_value(); //~ WARN unused return value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused return value of `EvenNature::is_even` which must be used: no side effects + --> $DIR/fn_must_use.rs:66:5 + | +LL | m.is_even(); // trait method! + | ^^^^^^^^^^^^ + +warning: unused return value of `std::cmp::PartialEq::eq` which must be used + --> $DIR/fn_must_use.rs:72:5 + | +LL | 2.eq(&3); //~ WARN unused return value + | ^^^^^^^^^ + +warning: unused return value of `std::cmp::PartialEq::eq` which must be used + --> $DIR/fn_must_use.rs:73:5 + | +LL | m.eq(&n); //~ WARN unused return value + | ^^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/fn_must_use.rs:76:5 + | +LL | 2 == 3; //~ WARN unused comparison + | ^^^^^^ + +warning: unused comparison which must be used + --> $DIR/fn_must_use.rs:77:5 + | +LL | m == n; //~ WARN unused comparison + | ^^^^^^ + diff --git a/src/test/ui/lint/must-use-ops.rs b/src/test/ui/lint/must-use-ops.rs index 4ed82ab3b40..c0575f817c8 100644 --- a/src/test/ui/lint/must-use-ops.rs +++ b/src/test/ui/lint/must-use-ops.rs @@ -12,7 +12,6 @@ // compile-pass -#![feature(fn_must_use)] #![warn(unused_must_use)] fn main() { diff --git a/src/test/ui/lint/must-use-ops.stderr b/src/test/ui/lint/must-use-ops.stderr index f444ef09075..5703536ef48 100644 --- a/src/test/ui/lint/must-use-ops.stderr +++ b/src/test/ui/lint/must-use-ops.stderr @@ -1,131 +1,131 @@ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:23:5 + --> $DIR/must-use-ops.rs:22:5 | LL | val == 1; | ^^^^^^^^ | note: lint level defined here - --> $DIR/must-use-ops.rs:16:9 + --> $DIR/must-use-ops.rs:15:9 | LL | #![warn(unused_must_use)] | ^^^^^^^^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:24:5 + --> $DIR/must-use-ops.rs:23:5 | LL | val < 1; | ^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:25:5 + --> $DIR/must-use-ops.rs:24:5 | LL | val <= 1; | ^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:26:5 + --> $DIR/must-use-ops.rs:25:5 | LL | val != 1; | ^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:27:5 + --> $DIR/must-use-ops.rs:26:5 | LL | val >= 1; | ^^^^^^^^ warning: unused comparison which must be used - --> $DIR/must-use-ops.rs:28:5 + --> $DIR/must-use-ops.rs:27:5 | LL | val > 1; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:31:5 + --> $DIR/must-use-ops.rs:30:5 | LL | val + 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:32:5 + --> $DIR/must-use-ops.rs:31:5 | LL | val - 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:33:5 + --> $DIR/must-use-ops.rs:32:5 | LL | val / 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:34:5 + --> $DIR/must-use-ops.rs:33:5 | LL | val * 2; | ^^^^^^^ warning: unused arithmetic operation which must be used - --> $DIR/must-use-ops.rs:35:5 + --> $DIR/must-use-ops.rs:34:5 | LL | val % 2; | ^^^^^^^ warning: unused logical operation which must be used - --> $DIR/must-use-ops.rs:38:5 + --> $DIR/must-use-ops.rs:37:5 | LL | true && true; | ^^^^^^^^^^^^ warning: unused logical operation which must be used - --> $DIR/must-use-ops.rs:39:5 + --> $DIR/must-use-ops.rs:38:5 | LL | false || true; | ^^^^^^^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:42:5 + --> $DIR/must-use-ops.rs:41:5 | LL | 5 ^ val; | ^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:43:5 + --> $DIR/must-use-ops.rs:42:5 | LL | 5 & val; | ^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:44:5 + --> $DIR/must-use-ops.rs:43:5 | LL | 5 | val; | ^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:45:5 + --> $DIR/must-use-ops.rs:44:5 | LL | 5 << val; | ^^^^^^^^ warning: unused bitwise operation which must be used - --> $DIR/must-use-ops.rs:46:5 + --> $DIR/must-use-ops.rs:45:5 | LL | 5 >> val; | ^^^^^^^^ warning: unused unary operation which must be used - --> $DIR/must-use-ops.rs:49:5 + --> $DIR/must-use-ops.rs:48:5 | LL | !val; | ^^^^ warning: unused unary operation which must be used - --> $DIR/must-use-ops.rs:50:5 + --> $DIR/must-use-ops.rs:49:5 | LL | -val; | ^^^^ warning: unused unary operation which must be used - --> $DIR/must-use-ops.rs:51:5 + --> $DIR/must-use-ops.rs:50:5 | LL | *val_pointer; | ^^^^^^^^^^^^ diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs deleted file mode 100644 index d20ebf0b740..00000000000 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-pass - -#![feature(fn_must_use)] -#![warn(unused_must_use)] - -#[derive(PartialEq, Eq)] -struct MyStruct { - n: usize, -} - -impl MyStruct { - #[must_use] - fn need_to_use_this_method_value(&self) -> usize { - self.n - } -} - -trait EvenNature { - #[must_use = "no side effects"] - fn is_even(&self) -> bool; -} - -impl EvenNature for MyStruct { - fn is_even(&self) -> bool { - self.n % 2 == 0 - } -} - -trait Replaceable { - fn replace(&mut self, substitute: usize) -> usize; -} - -impl Replaceable for MyStruct { - // ↓ N.b.: `#[must_use]` attribute on a particular trait implementation - // method won't work; the attribute should be on the method signature in - // the trait's definition. - #[must_use] - fn replace(&mut self, substitute: usize) -> usize { - let previously = self.n; - self.n = substitute; - previously - } -} - -#[must_use = "it's important"] -fn need_to_use_this_value() -> bool { - false -} - -fn main() { - need_to_use_this_value(); //~ WARN unused return value - - let mut m = MyStruct { n: 2 }; - let n = MyStruct { n: 3 }; - - m.need_to_use_this_method_value(); //~ WARN unused return value - m.is_even(); // trait method! - //~^ WARN unused return value - - m.replace(3); // won't warn (annotation needs to be in trait definition) - - // comparison methods are `must_use` - 2.eq(&3); //~ WARN unused return value - m.eq(&n); //~ WARN unused return value - - // lint includes comparison operators - 2 == 3; //~ WARN unused comparison - m == n; //~ WARN unused comparison -} diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr deleted file mode 100644 index d0a8bb525b6..00000000000 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr +++ /dev/null @@ -1,48 +0,0 @@ -warning: unused return value of `need_to_use_this_value` which must be used: it's important - --> $DIR/fn_must_use.rs:61:5 - | -LL | need_to_use_this_value(); //~ WARN unused return value - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/fn_must_use.rs:14:9 - | -LL | #![warn(unused_must_use)] - | ^^^^^^^^^^^^^^^ - -warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used - --> $DIR/fn_must_use.rs:66:5 - | -LL | m.need_to_use_this_method_value(); //~ WARN unused return value - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused return value of `EvenNature::is_even` which must be used: no side effects - --> $DIR/fn_must_use.rs:67:5 - | -LL | m.is_even(); // trait method! - | ^^^^^^^^^^^^ - -warning: unused return value of `std::cmp::PartialEq::eq` which must be used - --> $DIR/fn_must_use.rs:73:5 - | -LL | 2.eq(&3); //~ WARN unused return value - | ^^^^^^^^^ - -warning: unused return value of `std::cmp::PartialEq::eq` which must be used - --> $DIR/fn_must_use.rs:74:5 - | -LL | m.eq(&n); //~ WARN unused return value - | ^^^^^^^^^ - -warning: unused comparison which must be used - --> $DIR/fn_must_use.rs:77:5 - | -LL | 2 == 3; //~ WARN unused comparison - | ^^^^^^ - -warning: unused comparison which must be used - --> $DIR/fn_must_use.rs:78:5 - | -LL | m == n; //~ WARN unused comparison - | ^^^^^^ - diff --git a/src/test/ui/span/gated-features-attr-spans.rs b/src/test/ui/span/gated-features-attr-spans.rs index 83a4c5d5dd2..eff1f98eb71 100644 --- a/src/test/ui/span/gated-features-attr-spans.rs +++ b/src/test/ui/span/gated-features-attr-spans.rs @@ -8,33 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(attr_literals)] - -#[repr(align(16))] -struct Gem { - mohs_hardness: u8, - poofed: bool, - weapon: Weapon, -} - #[repr(simd)] //~ ERROR are experimental struct Weapon { name: String, damage: u32 } -impl Gem { - #[must_use] fn summon_weapon(&self) -> Weapon { self.weapon } - //~^ WARN is experimental -} - -#[must_use] //~ WARN is experimental -fn bubble(gem: Gem) -> Result { - if gem.poofed { - Ok(gem) - } else { - Err(()) - } -} - fn main() {} diff --git a/src/test/ui/span/gated-features-attr-spans.stderr b/src/test/ui/span/gated-features-attr-spans.stderr index 179daf83c3c..a99530529fc 100644 --- a/src/test/ui/span/gated-features-attr-spans.stderr +++ b/src/test/ui/span/gated-features-attr-spans.stderr @@ -1,27 +1,11 @@ error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) - --> $DIR/gated-features-attr-spans.rs:20:1 + --> $DIR/gated-features-attr-spans.rs:11:1 | LL | #[repr(simd)] //~ ERROR are experimental | ^^^^^^^^^^^^^ | = help: add #![feature(repr_simd)] to the crate attributes to enable -warning: `#[must_use]` on methods is experimental (see issue #43302) - --> $DIR/gated-features-attr-spans.rs:27:5 - | -LL | #[must_use] fn summon_weapon(&self) -> Weapon { self.weapon } - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/gated-features-attr-spans.rs:31:1 - | -LL | #[must_use] //~ WARN is experimental - | ^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. -- cgit 1.4.1-3-g733a5 From 368fe37c226c6e067ba4fa93cab0bbd5b1c09e6c Mon Sep 17 00:00:00 2001 From: Pazzaz Date: Sun, 29 Apr 2018 13:45:33 +0200 Subject: Add more links in panic docs --- src/libstd/panic.rs | 51 ++++++++++++++++++++++++++++++++----------------- src/libstd/panicking.rs | 8 +++++++- 2 files changed, 40 insertions(+), 19 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 28c178307a5..229034eb779 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -31,10 +31,14 @@ pub use core::panic::{PanicInfo, Location}; /// A marker trait which represents "panic safe" types in Rust. /// /// This trait is implemented by default for many types and behaves similarly in -/// terms of inference of implementation to the `Send` and `Sync` traits. The -/// purpose of this trait is to encode what types are safe to cross a `catch_unwind` +/// terms of inference of implementation to the [`Send`] and [`Sync`] traits. The +/// purpose of this trait is to encode what types are safe to cross a [`catch_unwind`] /// boundary with no fear of unwind safety. /// +/// [`Send`]: ../marker/trait.Send.html +/// [`Sync`]: ../marker/trait.Sync.html +/// [`catch_unwind`]: ./fn.catch_unwind.html +/// /// ## What is unwind safety? /// /// In Rust a function can "return" early if it either panics or calls a @@ -95,12 +99,13 @@ pub use core::panic::{PanicInfo, Location}; /// /// ## When should `UnwindSafe` be used? /// -/// Is not intended that most types or functions need to worry about this trait. -/// It is only used as a bound on the `catch_unwind` function and as mentioned above, -/// the lack of `unsafe` means it is mostly an advisory. The `AssertUnwindSafe` -/// wrapper struct in this module can be used to force this trait to be -/// implemented for any closed over variables passed to the `catch_unwind` function -/// (more on this below). +/// It is not intended that most types or functions need to worry about this trait. +/// It is only used as a bound on the `catch_unwind` function and as mentioned +/// above, the lack of `unsafe` means it is mostly an advisory. The +/// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be +/// implemented for any closed over variables passed to `catch_unwind`. +/// +/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ across an unwind boundary"] @@ -109,11 +114,14 @@ pub auto trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered /// unwind safe. /// -/// This trait is namely not implemented by `UnsafeCell`, the root of all +/// This trait is namely not implemented by [`UnsafeCell`], the root of all /// interior mutability. /// /// This is a "helper marker trait" used to provide impl blocks for the -/// `UnwindSafe` trait, for more information see that documentation. +/// [`UnwindSafe`] trait, for more information see that documentation. +/// +/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html +/// [`UnwindSafe`]: ./trait.UnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ and a reference may not be safely transferrable \ @@ -122,14 +130,15 @@ pub auto trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. /// -/// When using `catch_unwind` it may be the case that some of the closed over +/// When using [`catch_unwind`] it may be the case that some of the closed over /// variables are not unwind safe. For example if `&mut T` is captured the /// compiler will generate a warning indicating that it is not unwind safe. It /// may not be the case, however, that this is actually a problem due to the -/// specific usage of `catch_unwind` if unwind safety is specifically taken into +/// specific usage of [`catch_unwind`] if unwind safety is specifically taken into /// account. This wrapper struct is useful for a quick and lightweight /// annotation that a variable is indeed unwind safe. /// +/// [`catch_unwind`]: ./fn.catch_unwind.html /// # Examples /// /// One way to use `AssertUnwindSafe` is to assert that the entire closure @@ -318,18 +327,22 @@ impl fmt::Debug for AssertUnwindSafe { /// panic and allowing a graceful handling of the error. /// /// It is **not** recommended to use this function for a general try/catch -/// mechanism. The `Result` type is more appropriate to use for functions that +/// mechanism. The [`Result`] type is more appropriate to use for functions that /// can fail on a regular basis. Additionally, this function is not guaranteed /// to catch all panics, see the "Notes" section below. /// -/// The closure provided is required to adhere to the `UnwindSafe` trait to ensure +/// [`Result`]: ../result/enum.Result.html +/// +/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure /// that all captured variables are safe to cross this boundary. The purpose of /// this bound is to encode the concept of [exception safety][rfc] in the type /// system. Most usage of this function should not need to worry about this /// bound as programs are naturally unwind safe without `unsafe` code. If it -/// becomes a problem the associated `AssertUnwindSafe` wrapper type in this -/// module can be used to quickly assert that the usage here is indeed unwind -/// safe. +/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly +/// assert that the usage here is indeed unwind safe. +/// +/// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html +/// [`UnwindSafe`]: ./trait.UnwindSafe.html /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md /// @@ -364,9 +377,11 @@ pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { /// Triggers a panic without invoking the panic hook. /// -/// This is designed to be used in conjunction with `catch_unwind` to, for +/// This is designed to be used in conjunction with [`catch_unwind`] to, for /// example, carry a panic across a layer of C code. /// +/// [`catch_unwind`]: ./fn.catch_unwind.html +/// /// # Notes /// /// Note that panics in Rust are not always implemented via unwinding, but they diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 24eae6a4c82..403056240bf 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -76,7 +76,9 @@ static mut HOOK: Hook = Hook::Default; /// is invoked. As such, the hook will run with both the aborting and unwinding /// runtimes. The default hook prints a message to standard error and generates /// a backtrace if requested, but this behavior can be customized with the -/// `set_hook` and `take_hook` functions. +/// `set_hook` and [`take_hook`] functions. +/// +/// [`take_hook`]: ./fn.take_hook.html /// /// The hook is provided with a `PanicInfo` struct which contains information /// about the origin of the panic, including the payload passed to `panic!` and @@ -121,6 +123,10 @@ pub fn set_hook(hook: Box) { /// Unregisters the current panic hook, returning it. /// +/// *See also the function [`set_hook`].* +/// +/// [`set_hook`]: ./fn.set_hook.html +/// /// If no custom hook is registered, the default hook will be returned. /// /// # Panics -- cgit 1.4.1-3-g733a5 From 269d2790946858dd1b504c21c54a267ac63dc15a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 29 Apr 2018 10:15:40 -0700 Subject: Fix some broken links in docs. --- src/libcore/iter/iterator.rs | 2 ++ src/libcore/marker.rs | 2 ++ src/libstd/collections/hash/table.rs | 2 +- src/libstd/ffi/c_str.rs | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6a77de2c986..b27bd3142e1 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1094,6 +1094,8 @@ pub trait Iterator { /// `flatten()` a three-dimensional array the result will be /// two-dimensional and not one-dimensional. To get a one-dimensional /// structure, you have to `flatten()` again. + /// + /// [`flat_map()`]: #method.flat_map #[inline] #[unstable(feature = "iterator_flatten", issue = "48213")] fn flatten(self) -> Flatten diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index feb689dbc1f..c074adfd570 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -602,6 +602,8 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} /// `Pin` pointer. /// /// This trait is automatically implemented for almost every type. +/// +/// [`Pin`]: ../mem/struct.Pin.html #[unstable(feature = "pin", issue = "49150")] pub unsafe auto trait Unpin {} diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 52c53dc3b12..b50652ed6b5 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -79,7 +79,7 @@ impl TaggedHashUintPtr { /// /// Essential invariants of this structure: /// -/// - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw` +/// - if `t.hashes[i] == EMPTY_BUCKET`, then `Bucket::at_index(&t, i).raw` /// points to 'undefined' contents. Don't read from it. This invariant is /// enforced outside this module with the `EmptyBucket`, `FullBucket`, /// and `SafeHash` types. diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index c88c2bc9137..8164f52d3c3 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -1118,6 +1118,7 @@ impl CStr { /// /// [`Cow`]: ../borrow/enum.Cow.html /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed + /// [`Owned`]: ../borrow/enum.Cow.html#variant.Owned /// [`str`]: ../primitive.str.html /// [`String`]: ../string/struct.String.html /// -- cgit 1.4.1-3-g733a5 From 7c2304ddc6d716883415ac883f02256db6318644 Mon Sep 17 00:00:00 2001 From: Martin Husemann Date: Mon, 30 Apr 2018 08:04:53 +0200 Subject: Map the stack guard page with max protection on NetBSD On NetBSD the initial mmap() protection of a mapping can not be made less restrictive with mprotect(). So when mapping a stack guard page, use the maximum protection we ever want to use, then mprotect() it to the permission we want it to have initially. --- src/libstd/sys/unix/thread.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 9e388808030..f32016ce1d6 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -326,11 +326,23 @@ pub mod guard { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if cfg!(target_os = "netbsd") { + let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if result != stackaddr || result == MAP_FAILED { + panic!("failed to allocate a guard page"); + } + let result = mprotect(stackaddr, PAGE_SIZE, 0); - if result != stackaddr || result == MAP_FAILED { - panic!("failed to allocate a guard page"); + if result != 0 { + panic!("unable to protect the guard page"); + } + } else { + let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if result != stackaddr || result == MAP_FAILED { + panic!("failed to allocate a guard page"); + } } let guardaddr = stackaddr as usize; -- cgit 1.4.1-3-g733a5 From 300b6bb41784d63b04bf621a3290fe1c247f873f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 15 Apr 2018 16:59:00 +0300 Subject: Remove `macro_reexport` It's subsumed by `feature(use_extern_macros)` and `pub use` --- src/librustc_resolve/build_reduced_graph.rs | 29 +- src/librustc_resolve/diagnostics.rs | 73 +--- src/librustdoc/visit_ast.rs | 15 +- src/libstd/lib.rs | 16 +- src/libsyntax/feature_gate.rs | 11 +- .../compile-fail-fulldeps/gated-macro-reexports.rs | 21 - .../compile-fail/auxiliary/macro_non_reexport_2.rs | 19 - .../compile-fail/auxiliary/macro_reexport_1.rs | 15 - .../compile-fail/macro-no-implicit-reexport.rs | 20 - .../compile-fail/macro-reexport-malformed-1.rs | 16 - .../compile-fail/macro-reexport-malformed-2.rs | 16 - .../compile-fail/macro-reexport-malformed-3.rs | 16 - .../macro-reexport-not-locally-visible.rs | 22 - src/test/compile-fail/macro-reexport-undef.rs | 21 - .../proc-macro/auxiliary/derive-reexport.rs | 16 - .../run-pass-fulldeps/proc-macro/use-reexport.rs | 21 - src/test/run-pass/auxiliary/macro_reexport_1.rs | 15 - src/test/run-pass/auxiliary/macro_reexport_2.rs | 16 - .../run-pass/auxiliary/macro_reexport_2_no_use.rs | 16 - .../run-pass/macro-reexport-no-intermediate-use.rs | 19 - src/test/run-pass/macro-reexport.rs | 19 - src/test/rustdoc/pub-use-extern-macros.rs | 11 +- .../issue-43106-gating-of-builtin-attrs.rs | 20 - .../issue-43106-gating-of-builtin-attrs.stderr | 460 ++++++++++----------- src/test/ui/macro-reexport-removed.rs | 18 + src/test/ui/macro-reexport-removed.stderr | 18 + 26 files changed, 267 insertions(+), 692 deletions(-) delete mode 100644 src/test/compile-fail-fulldeps/gated-macro-reexports.rs delete mode 100644 src/test/compile-fail/auxiliary/macro_non_reexport_2.rs delete mode 100644 src/test/compile-fail/auxiliary/macro_reexport_1.rs delete mode 100644 src/test/compile-fail/macro-no-implicit-reexport.rs delete mode 100644 src/test/compile-fail/macro-reexport-malformed-1.rs delete mode 100644 src/test/compile-fail/macro-reexport-malformed-2.rs delete mode 100644 src/test/compile-fail/macro-reexport-malformed-3.rs delete mode 100644 src/test/compile-fail/macro-reexport-not-locally-visible.rs delete mode 100644 src/test/compile-fail/macro-reexport-undef.rs delete mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs delete mode 100644 src/test/run-pass-fulldeps/proc-macro/use-reexport.rs delete mode 100644 src/test/run-pass/auxiliary/macro_reexport_1.rs delete mode 100644 src/test/run-pass/auxiliary/macro_reexport_2.rs delete mode 100644 src/test/run-pass/auxiliary/macro_reexport_2_no_use.rs delete mode 100644 src/test/run-pass/macro-reexport-no-intermediate-use.rs delete mode 100644 src/test/run-pass/macro-reexport.rs create mode 100644 src/test/ui/macro-reexport-removed.rs create mode 100644 src/test/ui/macro-reexport-removed.stderr (limited to 'src/libstd') diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 14ceb5f59a3..e5e6c22c7a2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -71,7 +71,6 @@ impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) { struct LegacyMacroImports { import_all: Option, imports: Vec<(Name, Span)>, - reexports: Vec<(Name, Span)>, } impl<'a> Resolver<'a> { @@ -621,7 +620,7 @@ impl<'a> Resolver<'a> { let legacy_imports = self.legacy_macro_imports(&item.attrs); let mut used = legacy_imports != LegacyMacroImports::default(); - // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root. + // `#[macro_use]` is only allowed at the crate root. if self.current_module.parent.is_some() && used { span_err!(self.session, item.span, E0468, "an `extern crate` loading macros must be at the crate root"); @@ -669,17 +668,6 @@ impl<'a> Resolver<'a> { } } } - for (name, span) in legacy_imports.reexports { - self.cstore.export_macros_untracked(module.def_id().unwrap().krate); - let ident = Ident::with_empty_ctxt(name); - let result = self.resolve_ident_in_module(module, ident, MacroNS, false, false, span); - if let Ok(binding) = result { - let (def, vis) = (binding.def(), binding.vis); - self.macro_exports.push(Export { ident, def, vis, span, is_import: true }); - } else { - span_err!(self.session, span, E0470, "re-exported macro not found"); - } - } used } @@ -721,21 +709,6 @@ impl<'a> Resolver<'a> { }, None => imports.import_all = Some(attr.span), } - } else if attr.check_name("macro_reexport") { - let bad_macro_reexport = |this: &mut Self, span| { - span_err!(this.session, span, E0467, "bad macro re-export"); - }; - if let Some(names) = attr.meta_item_list() { - for attr in names { - if let Some(word) = attr.word() { - imports.reexports.push((word.ident.name, attr.span())); - } else { - bad_macro_reexport(self, attr.span()); - } - } - } else { - bad_macro_reexport(self, attr.span()); - } } } imports diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a0fc5533f8e..232a32deb86 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1395,35 +1395,6 @@ If you would like to import all exported macros, write `macro_use` with no arguments. "##, -E0467: r##" -Macro re-export declarations were empty or malformed. - -Erroneous code examples: - -```compile_fail,E0467 -#[macro_reexport] // error: no macros listed for export -extern crate core as macros_for_good; - -#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier -extern crate core as other_macros_for_good; -``` - -This is a syntax error at the level of attribute declarations. - -Currently, `macro_reexport` requires at least one macro name to be listed. -Unlike `macro_use`, listing no names does not re-export all macros from the -given crate. - -Decide which macros you would like to export and list them properly. - -These are proper re-export declarations: - -```ignore (cannot-doctest-multicrate-project) -#[macro_reexport(some_macro, another_macro)] -extern crate macros_for_good; -``` -"##, - E0468: r##" A non-root module attempts to import macros from another crate. @@ -1496,48 +1467,6 @@ extern crate some_crate; //ok! ``` "##, -E0470: r##" -A macro listed for re-export was not found. - -Erroneous code example: - -```compile_fail,E0470 -#[macro_reexport(drink, be_merry)] -extern crate alloc; - -fn main() { - // ... -} -``` - -Either the listed macro is not contained in the imported crate, or it is not -exported from the given crate. - -This could be caused by a typo. Did you misspell the macro's name? - -Double-check the names of the macros listed for re-export, and that the crate -in question exports them. - -A working version: - -```ignore (cannot-doctest-multicrate-project) -// In some_crate crate: -#[macro_export] -macro_rules! eat { - ... -} - -#[macro_export] -macro_rules! drink { - ... -} - -// In your_crate: -#[macro_reexport(eat, drink)] -extern crate some_crate; -``` -"##, - E0530: r##" A binding shadowed something it shouldn't. @@ -1715,6 +1644,8 @@ register_diagnostics! { // E0421, merged into 531 E0531, // unresolved pattern path kind `name` // E0427, merged into 530 +// E0467, removed +// E0470, removed E0573, E0574, E0575, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 967c50e62db..6db02cc6cc1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -49,7 +49,6 @@ pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { inlining: bool, /// Is the current module and all of its parents public? inside_public_path: bool, - reexported_macros: FxHashSet, exact_paths: Option>>, } @@ -66,7 +65,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { view_item_stack: stack, inlining: false, inside_public_path: true, - reexported_macros: FxHashSet(), exact_paths: Some(FxHashMap()), cstore, } @@ -221,7 +219,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { if let Some(exports) = self.cx.tcx.module_exports(def_id) { for export in exports.iter().filter(|e| e.vis == Visibility::Public) { if let Def::Macro(def_id, ..) = export.def { - if def_id.krate == LOCAL_CRATE || self.reexported_macros.contains(&def_id) { + if def_id.krate == LOCAL_CRATE { continue // These are `krate.exported_macros`, handled in `self.visit()`. } @@ -298,17 +296,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || use_attrs.lists("doc").has_word("hidden"); - // Memoize the non-inlined `pub use`'d macros so we don't push an extra - // declaration in `visit_mod_contents()` - if !def_did.is_local() { - if let Def::Macro(did, _) = def { - if please_inline { return true } - debug!("memoizing non-inlined macro export: {:?}", def); - self.reexported_macros.insert(did); - return false; - } - } - // For cross-crate impl inlining we need to know whether items are // reachable in documentation - a previously nonreachable item can be // made reachable by cross-crate inlining which we're checking here. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 41992193135..c6ee5b57be2 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -273,7 +273,6 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(never_type)] @@ -313,6 +312,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(use_extern_macros)] #![feature(vec_push_all)] #![feature(doc_cfg)] #![feature(doc_masked)] @@ -347,15 +347,13 @@ use prelude::v1::*; #[cfg(test)] extern crate test; #[cfg(test)] extern crate rand; -// We want to re-export a few macros from core but libcore has already been -// imported by the compiler (via our #[no_std] attribute) In this case we just -// add a new crate name so we can attach the re-exports to it. -#[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq, - debug_assert_ne, unreachable, unimplemented, write, writeln, try)] -extern crate core as __core; +// Re-export a few macros from core +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::{unreachable, unimplemented, write, writeln, try}; #[macro_use] -#[macro_reexport(vec, format)] extern crate alloc as alloc_crate; extern crate alloc_system; #[doc(masked)] @@ -450,6 +448,8 @@ pub use alloc_crate::borrow; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::fmt; #[stable(feature = "rust1", since = "1.0.0")] +pub use alloc_crate::format; +#[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::slice; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::str; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f16b1ba440a..e373013b3f9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -162,9 +162,6 @@ declare_features! ( // OIBIT specific features (active, optin_builtin_traits, "1.0.0", Some(13231), None), - // macro re-export needs more discussion and stabilization - (active, macro_reexport, "1.0.0", Some(29638), None), - // Allows use of #[staged_api] // rustc internal (active, staged_api, "1.0.0", None, None), @@ -484,6 +481,8 @@ declare_features! ( (removed, simd, "1.0.0", Some(27731), None), // Merged into `slice_patterns` (removed, advanced_slice_patterns, "1.0.0", Some(23121), None), + // Subsumed by `use` + (removed, macro_reexport, "1.0.0", Some(29638), None), ); declare_features! ( @@ -673,7 +672,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("forbid", Normal, Ungated), ("deny", Normal, Ungated), - ("macro_reexport", Normal, Ungated), ("macro_use", Normal, Ungated), ("macro_export", Normal, Ungated), ("plugin_registrar", Normal, Ungated), @@ -1516,11 +1514,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, underscore_imports, i.span, "renaming extern crates with `_` is unstable"); } - if let Some(attr) = attr::find_by_name(&i.attrs[..], "macro_reexport") { - gate_feature_post!(&self, macro_reexport, attr.span, - "macros re-exports are experimental \ - and possibly buggy"); - } } ast::ItemKind::ForeignMod(ref foreign_module) => { diff --git a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs deleted file mode 100644 index 8b448e401bd..00000000000 --- a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that macro re-exports item are gated by `macro_reexport` feature gate. - -// aux-build:macro_reexport_1.rs -// gate-test-macro_reexport - -#![crate_type = "dylib"] - -#[macro_reexport(reexported)] -//~^ ERROR macros re-exports are experimental and possibly buggy -#[macro_use] #[no_link] -extern crate macro_reexport_1; diff --git a/src/test/compile-fail/auxiliary/macro_non_reexport_2.rs b/src/test/compile-fail/auxiliary/macro_non_reexport_2.rs deleted file mode 100644 index 910fcd2e367..00000000000 --- a/src/test/compile-fail/auxiliary/macro_non_reexport_2.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "dylib"] - -// Since we load a serialized macro with all its attributes, accidentally -// re-exporting a `#[macro_export] macro_rules!` is something of a concern! -// -// We avoid it at the moment only because of the order in which we do things. - -#[macro_use] #[no_link] -extern crate macro_reexport_1; diff --git a/src/test/compile-fail/auxiliary/macro_reexport_1.rs b/src/test/compile-fail/auxiliary/macro_reexport_1.rs deleted file mode 100644 index aaeccc6e898..00000000000 --- a/src/test/compile-fail/auxiliary/macro_reexport_1.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "dylib"] -#[macro_export] -macro_rules! reexported { - () => ( 3 ) -} diff --git a/src/test/compile-fail/macro-no-implicit-reexport.rs b/src/test/compile-fail/macro-no-implicit-reexport.rs deleted file mode 100644 index 07467e06eb2..00000000000 --- a/src/test/compile-fail/macro-no-implicit-reexport.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:macro_reexport_1.rs -// aux-build:macro_non_reexport_2.rs - -#[macro_use] #[no_link] -extern crate macro_non_reexport_2; - -fn main() { - assert_eq!(reexported!(), 3); - //~^ ERROR cannot find macro `reexported!` in this scope -} diff --git a/src/test/compile-fail/macro-reexport-malformed-1.rs b/src/test/compile-fail/macro-reexport-malformed-1.rs deleted file mode 100644 index 36a6fce00a1..00000000000 --- a/src/test/compile-fail/macro-reexport-malformed-1.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![no_std] -#![feature(macro_reexport)] - -#[allow(unused_extern_crates)] -#[macro_reexport] //~ ERROR bad macro re-export -extern crate std; diff --git a/src/test/compile-fail/macro-reexport-malformed-2.rs b/src/test/compile-fail/macro-reexport-malformed-2.rs deleted file mode 100644 index 5f741d010de..00000000000 --- a/src/test/compile-fail/macro-reexport-malformed-2.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![no_std] -#![feature(macro_reexport)] - -#[allow(unused_extern_crates)] -#[macro_reexport="foo"] //~ ERROR bad macro re-export -extern crate std; diff --git a/src/test/compile-fail/macro-reexport-malformed-3.rs b/src/test/compile-fail/macro-reexport-malformed-3.rs deleted file mode 100644 index 1a7e3b918cd..00000000000 --- a/src/test/compile-fail/macro-reexport-malformed-3.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![no_std] -#![feature(macro_reexport)] - -#[allow(unused_extern_crates)] -#[macro_reexport(foo="bar")] //~ ERROR bad macro re-export -extern crate std; diff --git a/src/test/compile-fail/macro-reexport-not-locally-visible.rs b/src/test/compile-fail/macro-reexport-not-locally-visible.rs deleted file mode 100644 index 54a74b0e134..00000000000 --- a/src/test/compile-fail/macro-reexport-not-locally-visible.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:macro_reexport_1.rs - -#![feature(macro_reexport)] - -#[macro_reexport(reexported)] -#[no_link] -extern crate macro_reexport_1; - -fn main() { - assert_eq!(reexported!(), 3); - //~^ ERROR cannot find macro -} diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/compile-fail/macro-reexport-undef.rs deleted file mode 100644 index 50ac89e49e0..00000000000 --- a/src/test/compile-fail/macro-reexport-undef.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:two_macros.rs - -#![feature(macro_reexport)] - -#[macro_use(macro_two)] -#[macro_reexport(no_way)] //~ ERROR re-exported macro not found -extern crate two_macros; - -pub fn main() { - macro_two!(); -} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs deleted file mode 100644 index cfaf913216a..00000000000 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-test not a test, auxiliary - -#![feature(macro_reexport)] - -#[macro_reexport(A)] -extern crate derive_a; diff --git a/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs b/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs deleted file mode 100644 index 03dfeb1f5c9..00000000000 --- a/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:derive-a.rs -// aux-build:derive-reexport.rs -// ignore-stage1 - -#[macro_use] -extern crate derive_reexport; - -#[derive(Debug, PartialEq, A, Eq, Copy, Clone)] -struct A; - -fn main() {} diff --git a/src/test/run-pass/auxiliary/macro_reexport_1.rs b/src/test/run-pass/auxiliary/macro_reexport_1.rs deleted file mode 100644 index aaeccc6e898..00000000000 --- a/src/test/run-pass/auxiliary/macro_reexport_1.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "dylib"] -#[macro_export] -macro_rules! reexported { - () => ( 3 ) -} diff --git a/src/test/run-pass/auxiliary/macro_reexport_2.rs b/src/test/run-pass/auxiliary/macro_reexport_2.rs deleted file mode 100644 index 3918be88d86..00000000000 --- a/src/test/run-pass/auxiliary/macro_reexport_2.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "dylib"] -#![feature(macro_reexport)] - -#[macro_reexport(reexported)] -#[macro_use] #[no_link] -extern crate macro_reexport_1; diff --git a/src/test/run-pass/auxiliary/macro_reexport_2_no_use.rs b/src/test/run-pass/auxiliary/macro_reexport_2_no_use.rs deleted file mode 100644 index 1d3dc26b0b4..00000000000 --- a/src/test/run-pass/auxiliary/macro_reexport_2_no_use.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "dylib"] -#![feature(macro_reexport)] - -#[macro_reexport(reexported)] -#[no_link] -extern crate macro_reexport_1; diff --git a/src/test/run-pass/macro-reexport-no-intermediate-use.rs b/src/test/run-pass/macro-reexport-no-intermediate-use.rs deleted file mode 100644 index de7df1ec021..00000000000 --- a/src/test/run-pass/macro-reexport-no-intermediate-use.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:macro_reexport_1.rs -// aux-build:macro_reexport_2_no_use.rs - -#[macro_use] #[no_link] -extern crate macro_reexport_2_no_use; - -fn main() { - assert_eq!(reexported!(), 3_usize); -} diff --git a/src/test/run-pass/macro-reexport.rs b/src/test/run-pass/macro-reexport.rs deleted file mode 100644 index b8926eca9e9..00000000000 --- a/src/test/run-pass/macro-reexport.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:macro_reexport_1.rs -// aux-build:macro_reexport_2.rs - -#[macro_use] #[no_link] -extern crate macro_reexport_2; - -fn main() { - assert_eq!(reexported!(), 3_usize); -} diff --git a/src/test/rustdoc/pub-use-extern-macros.rs b/src/test/rustdoc/pub-use-extern-macros.rs index 3f8f6f9544e..57d54585d84 100644 --- a/src/test/rustdoc/pub-use-extern-macros.rs +++ b/src/test/rustdoc/pub-use-extern-macros.rs @@ -10,14 +10,11 @@ // aux-build:pub-use-extern-macros.rs -#![feature(use_extern_macros, macro_reexport)] +#![feature(use_extern_macros)] -// @has pub_use_extern_macros/macro.foo.html -// @!has pub_use_extern_macros/index.html 'pub use macros::foo;' -#[macro_reexport(foo)] extern crate macros; +extern crate macros; -// @has pub_use_extern_macros/index.html 'pub use macros::bar;' -// @!has pub_use_extern_macros/macro.bar.html +// @has pub_use_extern_macros/macro.bar.html pub use macros::bar; // @has pub_use_extern_macros/macro.baz.html @@ -25,7 +22,7 @@ pub use macros::bar; #[doc(inline)] pub use macros::baz; -// @!has pub_use_extern_macros/macro.quux.html +// @has pub_use_extern_macros/macro.quux.html // @!has pub_use_extern_macros/index.html 'pub use macros::quux;' #[doc(hidden)] pub use macros::quux; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index 7b0c81dbab6..76fb09f27be 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -50,7 +50,6 @@ #![allow (x5300)] //~ WARN unknown lint: `x5300` #![forbid (x5200)] //~ WARN unknown lint: `x5200` #![deny (x5100)] //~ WARN unknown lint: `x5100` -#![macro_reexport = "5000"] //~ WARN unused attribute #![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs) #![macro_export = "4800"] //~ WARN unused attribute #![plugin_registrar = "4700"] //~ WARN unused attribute @@ -186,25 +185,6 @@ mod deny { //~^ WARN unknown lint: `x5100` } -#[macro_reexport = "5000"] -//~^ WARN unused attribute -mod macro_reexport { - mod inner { #![macro_reexport="5000"] } - //~^ WARN unused attribute - - #[macro_reexport = "5000"] fn f() { } - //~^ WARN unused attribute - - #[macro_reexport = "5000"] struct S; - //~^ WARN unused attribute - - #[macro_reexport = "5000"] type T = S; - //~^ WARN unused attribute - - #[macro_reexport = "5000"] impl S { } - //~^ WARN unused attribute -} - #[macro_use] mod macro_use { mod inner { #![macro_use] } diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 76ab50c9089..7a94c1f0351 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1,17 +1,25 @@ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: macro_escape is a deprecated synonym for macro_use - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ | = help: consider an outer attribute, #[macro_use] mod ... +warning: `#[must_use]` on functions is experimental (see issue #43302) + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5 + | +LL | #[must_use = "1400"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(fn_must_use)] to the crate attributes to enable + warning: unknown lint: `x5400` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:33 | @@ -43,154 +51,154 @@ LL | #![deny (x5100)] //~ WARN unknown lint: `x5100` | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:121:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:140:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:159:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:172:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:175:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:178:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:181:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:192:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:192:5 | -LL | mod inner { #![macro_reexport="5000"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[macro_use] fn f() { } + | ^^^^^^^^^^^^ | note: lint level defined here --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:9 @@ -201,311 +209,275 @@ LL | #![warn(unused_attributes, unknown_lints)] warning: unused attribute --> $DIR/issue-43106-gating-of-builtin-attrs.rs:195:5 | -LL | #[macro_reexport = "5000"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5 - | -LL | #[macro_reexport = "5000"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5 - | -LL | #[macro_reexport = "5000"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5 - | -LL | #[macro_reexport = "5000"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:1 - | -LL | #[macro_reexport = "5000"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:5 - | -LL | #[macro_use] fn f() { } - | ^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:5 - | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:218:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:208:17 | LL | mod inner { #![macro_export="4800"] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:211:5 | LL | #[macro_export = "4800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:214:5 | LL | #[macro_export = "4800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:237:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:5 | LL | #[macro_export = "4800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:220:5 | LL | #[macro_export = "4800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:225:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:1 | LL | #[macro_export = "4800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:247:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:17 | LL | mod inner { #![plugin_registrar="4700"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:232:5 | LL | #[plugin_registrar = "4700"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 | LL | #[plugin_registrar = "4700"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:238:5 | LL | #[plugin_registrar = "4700"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:244:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:1 | LL | #[plugin_registrar = "4700"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:17 | LL | mod inner { #![main="4300"] } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:270:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:250:5 | LL | #[main = "4400"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:273:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:253:5 | LL | #[main = "4400"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:276:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5 | LL | #[main = "4400"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:242:1 | LL | #[main = "4400"] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:17 | LL | mod inner { #![start="4300"] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:288:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5 | LL | #[start = "4300"] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:291:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5 | LL | #[start = "4300"] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:294:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5 | LL | #[start = "4300"] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:1 | LL | #[start = "4300"] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:313:17 | LL | mod inner { #![repr="3900"] } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:316:5 | LL | #[repr = "3900"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:5 | LL | #[repr = "3900"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:5 | LL | #[repr = "3900"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:1 | LL | #[repr = "3900"] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:352:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:17 | LL | mod inner { #![abi="3700"] } | ^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 | LL | #[abi = "3700"] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:354:5 | LL | #[abi = "3700"] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:357:5 | LL | #[abi = "3700"] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:360:5 | LL | #[abi = "3700"] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:1 | LL | #[abi = "3700"] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:17 | LL | mod inner { #![automatically_derived="3600"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[automatically_derived = "3600"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:393:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5 | LL | #[automatically_derived = "3600"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 | LL | #[automatically_derived = "3600"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 | LL | #[automatically_derived = "3600"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:384:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:1 | LL | #[automatically_derived = "3600"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: function is marked #[no_mangle], but not exported - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:27 | LL | #[no_mangle = "3500"] fn f() { } | -^^^^^^^^^ @@ -515,793 +487,787 @@ LL | #[no_mangle = "3500"] fn f() { } = note: #[warn(private_no_mangle_fns)] on by default warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:400:17 | LL | mod inner { #![no_link="3400"] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:403:5 | LL | #[no_link = "3400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:5 | LL | #[no_link = "3400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:409:5 | LL | #[no_link = "3400"]type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:5 | LL | #[no_link = "3400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:1 | LL | #[no_link = "3400"] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:419:17 | LL | mod inner { #![should_panic="3200"] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:422:5 | LL | #[should_panic = "3200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:5 | LL | #[should_panic = "3200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:5 | LL | #[should_panic = "3200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5 | LL | #[should_panic = "3200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:416:1 | LL | #[should_panic = "3200"] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:438:17 | LL | mod inner { #![ignore="3100"] } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:441:5 | LL | #[ignore = "3100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:444:5 | LL | #[ignore = "3100"] struct S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:467:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:447:5 | LL | #[ignore = "3100"] type T = S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:5 | LL | #[ignore = "3100"] impl S { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:435:1 | LL | #[ignore = "3100"] | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:477:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:17 | LL | mod inner { #![no_implicit_prelude="3000"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:460:5 | LL | #[no_implicit_prelude = "3000"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5 | LL | #[no_implicit_prelude = "3000"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5 | LL | #[no_implicit_prelude = "3000"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5 | LL | #[no_implicit_prelude = "3000"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:454:1 | LL | #[no_implicit_prelude = "3000"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:522:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:17 | LL | mod inner { #![no_std="2600"] } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:17 | LL | mod inner { #![no_std="2600"] } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:5 | LL | #[no_std = "2600"] fn f() { } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:5 | LL | #[no_std = "2600"] fn f() { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:5 | LL | #[no_std = "2600"] struct S; | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:5 | LL | #[no_std = "2600"] struct S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:548:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 | LL | #[no_std = "2600"] type T = S; | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:548:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 | LL | #[no_std = "2600"] type T = S; | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:552:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5 | LL | #[no_std = "2600"] impl S { } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:552:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5 | LL | #[no_std = "2600"] impl S { } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:1 | LL | #[no_std = "2600"] | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:1 | LL | #[no_std = "2600"] | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:809:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:813:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:821:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:842:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:846:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 - | -LL | #![macro_reexport = "5000"] //~ WARN unused attribute - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 | LL | #![macro_export = "4800"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 | LL | #![plugin_registrar = "4700"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 | LL | #![main = "x4400"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 | LL | #![start = "x4300"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | LL | #![repr = "3900"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1 | LL | #![path = "3800"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | LL | #![abi = "3700"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 | LL | #![automatically_derived = "3600"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1 | LL | #![no_link = "3400"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 | LL | #![should_panic = "3200"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 | LL | #![ignore = "3100"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:77:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:76:1 | LL | #![proc_macro_derive = "2500"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compilation successful - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:857:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:1 | LL | / fn main() { //~ ERROR compilation successful LL | | println!("Hello World"); diff --git a/src/test/ui/macro-reexport-removed.rs b/src/test/ui/macro-reexport-removed.rs new file mode 100644 index 00000000000..bab583da37b --- /dev/null +++ b/src/test/ui/macro-reexport-removed.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs + +#![feature(macro_reexport)] //~ ERROR feature has been removed + +#[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown +extern crate two_macros; + +fn main() {} diff --git a/src/test/ui/macro-reexport-removed.stderr b/src/test/ui/macro-reexport-removed.stderr new file mode 100644 index 00000000000..4d262e96081 --- /dev/null +++ b/src/test/ui/macro-reexport-removed.stderr @@ -0,0 +1,18 @@ +error[E0557]: feature has been removed + --> $DIR/macro-reexport-removed.rs:13:12 + | +LL | #![feature(macro_reexport)] //~ ERROR feature has been removed + | ^^^^^^^^^^^^^^ + +error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) + --> $DIR/macro-reexport-removed.rs:15:1 + | +LL | #[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors occurred: E0557, E0658. +For more information about an error, try `rustc --explain E0557`. -- cgit 1.4.1-3-g733a5 From 730c7222ee85bbea677f08447ca83bf539a1bdf8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 30 Apr 2018 14:06:24 +0300 Subject: Fix an error from "unused" lint + Fix rebase --- src/libstd/lib.rs | 1 + src/test/rustdoc/cross-crate-links.rs | 2 +- .../issue-43106-gating-of-builtin-attrs.stderr | 154 ++++++++++----------- 3 files changed, 75 insertions(+), 82 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c6ee5b57be2..fc05833e285 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -353,6 +353,7 @@ pub use core::{assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert #[stable(feature = "rust1", since = "1.0.0")] pub use core::{unreachable, unimplemented, write, writeln, try}; +#[allow(unused_imports)] // macros from `alloc` are not used on all platforms #[macro_use] extern crate alloc as alloc_crate; extern crate alloc_system; diff --git a/src/test/rustdoc/cross-crate-links.rs b/src/test/rustdoc/cross-crate-links.rs index 15a774dc935..6078352fc0e 100644 --- a/src/test/rustdoc/cross-crate-links.rs +++ b/src/test/rustdoc/cross-crate-links.rs @@ -66,6 +66,6 @@ pub use all_item_types::FOO_STATIC; #[doc(no_inline)] pub use all_item_types::FOO_CONSTANT; -// @has 'foo/index.html' '//a[@href="../all_item_types/macro.foo_macro.html"]' 'foo_macro' +// @has 'foo/index.html' '//a[@href="../foo/macro.foo_macro.html"]' 'foo_macro' #[doc(no_inline)] pub use all_item_types::foo_macro; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 7a94c1f0351..f8e5f58ca0e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -12,14 +12,6 @@ LL | mod inner { #![macro_escape] } | = help: consider an outer attribute, #[macro_use] mod ... -warning: `#[must_use]` on functions is experimental (see issue #43302) - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5 - | -LL | #[must_use = "1400"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(fn_must_use)] to the crate attributes to enable - warning: unknown lint: `x5400` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:33 | @@ -763,433 +755,433 @@ LL | #[no_std = "2600"] | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:680:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:683:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:738:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:17 | LL | mod inner { #![no_main="0400"] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 | LL | #[no_main = "0400"] fn f() { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 | LL | #[no_main = "0400"] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 | LL | #[no_main = "0400"] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:763:5 | LL | #[no_main = "0400"] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:744:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:1 | LL | #[no_main = "0400"] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:794:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:802:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: #![foo] - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:807:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:806:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1267,7 +1259,7 @@ LL | #![proc_macro_derive = "2500"] //~ WARN unused attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compilation successful - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:838:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:837:1 | LL | / fn main() { //~ ERROR compilation successful LL | | println!("Hello World"); -- cgit 1.4.1-3-g733a5 From 244e24a312925779f6c62ce7d6b315fa2c120a7c Mon Sep 17 00:00:00 2001 From: Martin Husemann Date: Wed, 2 May 2018 10:00:33 +0200 Subject: Add comments and unify guard page setup. While currently only NetBSD seems to be affected, all systems implementing PAX MPROTECT in strict mode need this treatment, and it does not hurt others. --- src/libstd/sys/unix/thread.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index f32016ce1d6..7fdecc9c0c0 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -326,23 +326,20 @@ pub mod guard { // Reallocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - if cfg!(target_os = "netbsd") { - let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); - if result != stackaddr || result == MAP_FAILED { - panic!("failed to allocate a guard page"); - } - let result = mprotect(stackaddr, PAGE_SIZE, 0); + // Systems which enforce strict PAX MPROTECT do not allow + // to mprotect() a mapping with less restrictive permissions + // than the initial mmap() used, so we mmap() here with + // read/write permissions and only then mprotect() it to + // no permissions at all. See issue #50313. + let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + if result != stackaddr || result == MAP_FAILED { + panic!("failed to allocate a guard page"); + } - if result != 0 { - panic!("unable to protect the guard page"); - } - } else { - let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); - if result != stackaddr || result == MAP_FAILED { - panic!("failed to allocate a guard page"); - } + let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE); + if result != 0 { + panic!("failed to protect the guard page"); } let guardaddr = stackaddr as usize; -- cgit 1.4.1-3-g733a5 From f6841470f1beb007052b12a090c1eb109c7259e8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 2 May 2018 16:39:54 -0700 Subject: Revert "Implement FromStr for PathBuf" This reverts commit 05a9acc3b844ff284a3e3d85dde2d9798abfb215. --- src/libstd/path.rs | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 955a6af1ae6..696711a70d4 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -87,7 +87,6 @@ use io; use iter::{self, FusedIterator}; use ops::{self, Deref}; use rc::Rc; -use str::FromStr; use sync::Arc; use ffi::{OsStr, OsString}; @@ -1441,32 +1440,6 @@ impl From for PathBuf { } } -/// Error returned from [`PathBuf::from_str`][`from_str`]. -/// -/// Note that parsing a path will never fail. This error is just a placeholder -/// for implementing `FromStr` for `PathBuf`. -/// -/// [`from_str`]: struct.PathBuf.html#method.from_str -#[derive(Debug, Clone, PartialEq, Eq)] -#[stable(feature = "path_from_str", since = "1.26.0")] -pub enum ParsePathError {} - -#[stable(feature = "path_from_str", since = "1.26.0")] -impl fmt::Display for ParsePathError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - match *self {} - } -} - -#[stable(feature = "path_from_str", since = "1.26.0")] -impl FromStr for PathBuf { - type Err = ParsePathError; - - fn from_str(s: &str) -> Result { - Ok(PathBuf::from(s)) - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl> iter::FromIterator

for PathBuf { fn from_iter>(iter: I) -> PathBuf { -- cgit 1.4.1-3-g733a5 From 8e38d02d986a5fa5ef51b6995058d7327aa0da4b Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Thu, 3 May 2018 06:49:30 -0400 Subject: update concat_idents doc stubs --- src/libcore/macros.rs | 4 ++-- src/libstd/macros.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f9371ed0575..c830c22ee5f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -606,8 +606,8 @@ mod builtin { #[macro_export] #[cfg(dox)] macro_rules! concat_idents { - ($($e:ident),*) => ({ /* compiler built-in */ }); - ($($e:ident,)*) => ({ /* compiler built-in */ }); + ($($e:ident),+) => ({ /* compiler built-in */ }); + ($($e:ident,)+) => ({ /* compiler built-in */ }); } /// Concatenates literals into a static string slice. diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6902ec82047..d1274a40900 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -450,8 +450,8 @@ pub mod builtin { #[unstable(feature = "concat_idents_macro", issue = "29599")] #[macro_export] macro_rules! concat_idents { - ($($e:ident),*) => ({ /* compiler built-in */ }); - ($($e:ident,)*) => ({ /* compiler built-in */ }); + ($($e:ident),+) => ({ /* compiler built-in */ }); + ($($e:ident,)+) => ({ /* compiler built-in */ }); } /// Concatenates literals into a static string slice. -- cgit 1.4.1-3-g733a5 From b53993684549a76a4223bed15e4f04754e20c242 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 3 May 2018 16:24:21 -0700 Subject: Remove the deprecated std::net::{lookup_host,LookupHost} These are unstable, and were deprecated by #47510, since Rust 1.25. The internal `sys` implementations are still kept to support the call in the common `resolve_socket_addr`. --- src/libstd/net/addr.rs | 4 +-- src/libstd/net/mod.rs | 65 ----------------------------------- src/test/run-pass/sync-send-in-std.rs | 6 ++-- 3 files changed, 3 insertions(+), 72 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index bc2c9f522d3..e80c3eeb876 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -13,11 +13,10 @@ use hash; use io; use mem; use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr}; -#[allow(deprecated)] -use net::lookup_host; use option; use sys::net::netc as c; use sys_common::{FromInner, AsInner, IntoInner}; +use sys_common::net::lookup_host; use vec; use iter; use slice; @@ -856,7 +855,6 @@ impl ToSocketAddrs for (Ipv6Addr, u16) { } } -#[allow(deprecated)] fn resolve_socket_addr(s: &str, p: u16) -> io::Result> { let ips = lookup_host(s)?; let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect(); diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index b0d5e563cb9..be4bcee8a68 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -38,9 +38,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; use io::{self, Error, ErrorKind}; -use sys_common::net as net_imp; #[stable(feature = "rust1", since = "1.0.0")] pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; @@ -128,66 +126,3 @@ fn each_addr(addr: A, mut f: F) -> io::Result "could not resolve to any addresses") })) } - -/// An iterator over `SocketAddr` values returned from a host lookup operation. -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -pub struct LookupHost(net_imp::LookupHost); - -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -#[allow(deprecated)] -impl Iterator for LookupHost { - type Item = SocketAddr; - fn next(&mut self) -> Option { self.0.next() } -} - -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -#[allow(deprecated)] -impl fmt::Debug for LookupHost { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("LookupHost { .. }") - } -} - -/// Resolve the host specified by `host` as a number of `SocketAddr` instances. -/// -/// This method may perform a DNS query to resolve `host` and may also inspect -/// system configuration to resolve the specified hostname. -/// -/// The returned iterator will skip over any unknown addresses returned by the -/// operating system. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(lookup_host)] -/// -/// use std::net; -/// -/// fn main() -> std::io::Result<()> { -/// for host in net::lookup_host("rust-lang.org")? { -/// println!("found address: {}", host); -/// } -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "lookup_host", reason = "unsure about the returned \ - iterator and returning socket \ - addresses", - issue = "27705")] -#[rustc_deprecated(since = "1.25.0", reason = "Use the ToSocketAddrs trait instead")] -#[allow(deprecated)] -pub fn lookup_host(host: &str) -> io::Result { - net_imp::lookup_host(host).map(LookupHost) -} diff --git a/src/test/run-pass/sync-send-in-std.rs b/src/test/run-pass/sync-send-in-std.rs index f03387957bc..335a9c0d8be 100644 --- a/src/test/run-pass/sync-send-in-std.rs +++ b/src/test/run-pass/sync-send-in-std.rs @@ -11,9 +11,7 @@ // ignore-cloudabi networking not available // ignore-wasm32-bare networking not available -#![feature(lookup_host)] - -use std::net::lookup_host; +use std::net::ToSocketAddrs; fn is_sync(_: T) where T: Sync {} fn is_send(_: T) where T: Send {} @@ -30,5 +28,5 @@ macro_rules! all_sync_send { } fn main() { - all_sync_send!(lookup_host("localhost").unwrap(), next); + all_sync_send!("localhost:80".to_socket_addrs().unwrap(), next); } -- cgit 1.4.1-3-g733a5 From fc6d6c98dedca297c09016615011bee448e5e468 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Fri, 4 May 2018 21:37:28 -0400 Subject: Fixed typos --- src/libstd/primitive_docs.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 8905f7c9e16..49344cab1dd 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -112,7 +112,7 @@ mod prim_bool { } /// /// # `!` and generics /// -/// ## Infalliable errors +/// ## Infallible errors /// /// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] /// trait: @@ -144,7 +144,7 @@ mod prim_bool { } /// /// ## Infinite loops /// -/// While [`Result`] is very useful for removing errors, `!` can also be used to removed +/// While [`Result`] is very useful for removing errors, `!` can also be used to remove /// successes as well. If we think of [`Result`] as "if this function returns, it has not /// errored," we get a very intuitive idea of [`Result`] as well: if the function returns, it /// *has* errored. @@ -175,21 +175,22 @@ mod prim_bool { } /// ``` /// /// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it -/// might be intuitive to simply return the error, we might want to wrap it in a [`Result`] +/// might be intuitive to simply return the error, we might want to wrap it in a [`Result`] /// instead: /// /// ```ignore (hypothetical-example) /// fn server_loop() -> Result { -/// Ok(loop { +/// loop { /// let (client, request) = get_request()?; /// let response = request.process(); /// response.send(client); -/// }) +/// } /// } /// ``` /// /// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop -/// ever stops, it means that an error occurred. +/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok` +/// because `!` coerces to `Result` automatically. /// /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str /// [`Result`]: result/enum.Result.html -- cgit 1.4.1-3-g733a5 From 02f6a0335f99378b2e7d630e00aabdeb57a5bd25 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 6 May 2018 01:02:05 +0800 Subject: Some final touches to ensure `./x.py test --stage 0 src/lib*` works --- src/libcore/lib.rs | 1 + src/libcore/tests/lib.rs | 1 + src/libcore/tests/num/uint_macros.rs | 1 + src/libstd/lib.rs | 4 ++-- 4 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 04dd42583d4..37f9dcc7e32 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -50,6 +50,7 @@ // Since libcore defines many fundamental lang items, all tests live in a // separate crate, libcoretest, to avoid bizarre issues. +#![cfg(not(test))] #![stable(feature = "core", since = "1.6.0")] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 340879c6b85..5e98e40e0d5 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(reverse_bits)] #![feature(inclusive_range_methods)] #![feature(iterator_find_map)] +#![feature(slice_internals)] extern crate core; extern crate test; diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index ca6906f7310..257f6ea20d4 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -98,6 +98,7 @@ mod tests { } #[test] + #[cfg(not(stage0))] fn test_reverse_bits() { assert_eq!(A.reverse_bits().reverse_bits(), A); assert_eq!(B.reverse_bits().reverse_bits(), B); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fc05833e285..d41739ab02c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -330,10 +330,10 @@ // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic #![cfg_attr(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")), + any(all(stage0, not(test)), feature = "force_alloc_system")), feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), - any(stage0, feature = "force_alloc_system")))] + any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] static ALLOC: alloc_system::System = alloc_system::System; -- cgit 1.4.1-3-g733a5 From f8b774fbf1f57e520b58ae3828e4b3a1ddf1d97c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 7 May 2018 09:27:50 -0700 Subject: Add explanation for #[must_use] on mutex guards --- src/libstd/sync/mutex.rs | 2 +- src/libstd/sync/rwlock.rs | 4 ++-- src/libstd/sys_common/remutex.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 3b4904c98e8..f3503b0b3a6 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -150,7 +150,7 @@ unsafe impl Sync for Mutex { } /// [`lock`]: struct.Mutex.html#method.lock /// [`try_lock`]: struct.Mutex.html#method.try_lock /// [`Mutex`]: struct.Mutex.html -#[must_use] +#[must_use = "if unused the Mutex will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { // funny underscores due to how Deref/DerefMut currently work (they diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index f7fdedc0d21..e3db60cff84 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -94,7 +94,7 @@ unsafe impl Sync for RwLock {} /// [`read`]: struct.RwLock.html#method.read /// [`try_read`]: struct.RwLock.html#method.try_read /// [`RwLock`]: struct.RwLock.html -#[must_use] +#[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { __lock: &'a RwLock, @@ -115,7 +115,7 @@ unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockReadGuard<'a, T> {} /// [`write`]: struct.RwLock.html#method.write /// [`try_write`]: struct.RwLock.html#method.try_write /// [`RwLock`]: struct.RwLock.html -#[must_use] +#[must_use = "if unused the RwLock will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { __lock: &'a RwLock, diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs index ce43ec6d9ab..022056f8a8a 100644 --- a/src/libstd/sys_common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -41,7 +41,7 @@ unsafe impl Sync for ReentrantMutex {} /// because implementation of the trait would violate Rust’s reference aliasing /// rules. Use interior mutability (usually `RefCell`) in order to mutate the /// guarded data. -#[must_use] +#[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { // funny underscores due to how Deref currently works (it disregards field // privacy). -- cgit 1.4.1-3-g733a5 From e333725664c45874262ecb11e511c17cfd4672f0 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 9 May 2018 01:41:44 +0200 Subject: use fmt::Result where applicable --- src/librustc/ich/fingerprint.rs | 2 +- src/librustc_data_structures/control_flow_graph/dominators/mod.rs | 4 ++-- src/librustc_data_structures/owning_ref/mod.rs | 6 +++--- src/librustc_errors/lib.rs | 4 ++-- src/librustc_mir/borrow_check/nll/region_infer/mod.rs | 2 +- src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustdoc/html/render.rs | 4 ++-- src/libstd/path.rs | 2 +- src/libstd/sys/redox/syscall/error.rs | 4 ++-- src/libstd/sys_common/wtf8.rs | 4 ++-- src/libsyntax_ext/format_foreign.rs | 2 +- src/test/run-pass/atomic-print.rs | 2 +- src/test/run-pass/union/union-trait-impl.rs | 2 +- 13 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index a7adf28c481..f56f4e12e7a 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -67,7 +67,7 @@ impl Fingerprint { } impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(formatter, "{:x}-{:x}", self.0, self.1) } } diff --git a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs index dc487f1162c..54407658e6c 100644 --- a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs @@ -175,7 +175,7 @@ impl DominatorTree { } impl fmt::Debug for DominatorTree { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&DominatorTreeNode { tree: self, node: self.root, @@ -190,7 +190,7 @@ struct DominatorTreeNode<'tree, Node: Idx> { } impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let subtrees: Vec<_> = self.tree .children(self.node) .iter() diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index c466b8f8ad1..aa113fac9fb 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -1002,7 +1002,7 @@ impl Debug for OwningRef where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1014,7 +1014,7 @@ impl Debug for OwningRefMut where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OwningRefMut {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1047,7 +1047,7 @@ unsafe impl Sync for OwningRefMut where O: Sync, for<'a> (&'a mut T): Sync {} impl Debug for Erased { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "",) } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index c2b442e9497..fd90e1cbe08 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -232,7 +232,7 @@ impl FatalError { } impl fmt::Display for FatalError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "parser fatal error") } } @@ -249,7 +249,7 @@ impl error::Error for FatalError { pub struct ExplicitBug; impl fmt::Display for ExplicitBug { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "parser internal bug") } } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 4d1f3e2b430..57b8824191f 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1185,7 +1185,7 @@ impl<'tcx> RegionDefinition<'tcx> { } impl fmt::Debug for Constraint { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, "({:?}: {:?} @ {:?}) due to {:?}", diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 5397d18cdd7..79252e7654b 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -174,7 +174,7 @@ struct Elaborator<'a, 'b: 'a, 'tcx: 'b> { } impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> { - fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { Ok(()) } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 21de2db1dfe..fe9fc3ddd68 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2579,7 +2579,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter, - implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> Result<(), fmt::Error> { + implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result { write!(w, "

  • ")?; // If there's already another implementor that has the same abbridged name, use the // full path, for example in `std::iter::ExactSizeIterator` @@ -2612,7 +2612,7 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter, fn render_impls(cx: &Context, w: &mut fmt::Formatter, traits: &[&&Impl], - containing_item: &clean::Item) -> Result<(), fmt::Error> { + containing_item: &clean::Item) -> fmt::Result { for i in traits { let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 696711a70d4..5d35a786173 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1460,7 +1460,7 @@ impl> iter::Extend

    for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for PathBuf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } diff --git a/src/libstd/sys/redox/syscall/error.rs b/src/libstd/sys/redox/syscall/error.rs index d8d78d55016..1ef79547431 100644 --- a/src/libstd/sys/redox/syscall/error.rs +++ b/src/libstd/sys/redox/syscall/error.rs @@ -48,13 +48,13 @@ impl Error { } impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.text()) } } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.text()) } } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index fe7e058091e..14a2555adf9 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -56,7 +56,7 @@ pub struct CodePoint { /// Example: `U+1F4A9` impl fmt::Debug for CodePoint { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "U+{:04X}", self.value) } } @@ -144,7 +144,7 @@ impl ops::DerefMut for Wtf8Buf { /// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800] impl fmt::Debug for Wtf8Buf { #[inline] - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs index e95c6f2e124..2b8603c75a5 100644 --- a/src/libsyntax_ext/format_foreign.rs +++ b/src/libsyntax_ext/format_foreign.rs @@ -989,7 +989,7 @@ mod strcursor { } impl<'a> std::fmt::Debug for StrCursor<'a> { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) } } diff --git a/src/test/run-pass/atomic-print.rs b/src/test/run-pass/atomic-print.rs index 914b89dfb4d..2d478e954e7 100644 --- a/src/test/run-pass/atomic-print.rs +++ b/src/test/run-pass/atomic-print.rs @@ -15,7 +15,7 @@ use std::{env, fmt, process, sync, thread}; struct SlowFmt(u32); impl fmt::Debug for SlowFmt { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { thread::sleep_ms(3); self.0.fmt(f) } diff --git a/src/test/run-pass/union/union-trait-impl.rs b/src/test/run-pass/union/union-trait-impl.rs index 1cdaff2cab7..c1e408cc02a 100644 --- a/src/test/run-pass/union/union-trait-impl.rs +++ b/src/test/run-pass/union/union-trait-impl.rs @@ -15,7 +15,7 @@ union U { } impl fmt::Display for U { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { write!(f, "Oh hai {}", self.a) } } } -- cgit 1.4.1-3-g733a5 From 17e262880c13abdc4d7bf72eb7e87146f0f3b1f0 Mon Sep 17 00:00:00 2001 From: George Burton Date: Wed, 9 May 2018 07:23:02 +0100 Subject: Update features to 1.28.0 --- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 2 +- src/libstd/ffi/c_str.rs | 8 ++++---- src/libstd/ffi/os_str.rs | 8 ++++---- src/libstd/path.rs | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 61a207fc5b3..5f684361fdc 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2239,7 +2239,7 @@ impl<'a> From for Cow<'a, str> { } } -#[stable(feature = "cow_from_string_ref", since = "1.27.0")] +#[stable(feature = "cow_from_string_ref", since = "1.28.0")] impl<'a> From<&'a String> for Cow<'a, str> { #[inline] fn from(s: &'a String) -> Cow<'a, str> { diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 315a8a0aad0..be4c80c85d9 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2285,7 +2285,7 @@ impl<'a, T: Clone> From> for Cow<'a, [T]> { } } -#[stable(feature = "cow_from_vec_ref", since = "1.27.0")] +#[stable(feature = "cow_from_vec_ref", since = "1.28.0")] impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { fn from(v: &'a Vec) -> Cow<'a, [T]> { Cow::Borrowed(v.as_slice()) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 10f59b0a3cc..05ab4c3cecc 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -682,7 +682,7 @@ impl Borrow for CString { fn borrow(&self) -> &CStr { self } } -#[stable(feature = "cstring_from_cow_cstr", since = "1.27.0")] +#[stable(feature = "cstring_from_cow_cstr", since = "1.2780")] impl<'a> From> for CString { #[inline] fn from(s: Cow<'a, CStr>) -> Self { @@ -714,7 +714,7 @@ impl From for Box { } } -#[stable(feature = "cow_from_cstr", since = "1.27.0")] +#[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From for Cow<'a, CStr> { #[inline] fn from(s: CString) -> Cow<'a, CStr> { @@ -722,7 +722,7 @@ impl<'a> From for Cow<'a, CStr> { } } -#[stable(feature = "cow_from_cstr", since = "1.27.0")] +#[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From<&'a CStr> for Cow<'a, CStr> { #[inline] fn from(s: &'a CStr) -> Cow<'a, CStr> { @@ -730,7 +730,7 @@ impl<'a> From<&'a CStr> for Cow<'a, CStr> { } } -#[stable(feature = "cow_from_cstr", since = "1.27.0")] +#[stable(feature = "cow_from_cstr", since = "1.28.0")] impl<'a> From<&'a CString> for Cow<'a, CStr> { #[inline] fn from(s: &'a CString) -> Cow<'a, CStr> { diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index d865ffa8e2f..0a3148029d0 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -664,7 +664,7 @@ impl<'a> From<&'a OsStr> for Rc { } } -#[stable(feature = "cow_from_osstr", since = "1.27.0")] +#[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From for Cow<'a, OsStr> { #[inline] fn from(s: OsString) -> Cow<'a, OsStr> { @@ -672,7 +672,7 @@ impl<'a> From for Cow<'a, OsStr> { } } -#[stable(feature = "cow_from_osstr", since = "1.27.0")] +#[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { #[inline] fn from(s: &'a OsStr) -> Cow<'a, OsStr> { @@ -680,7 +680,7 @@ impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { } } -#[stable(feature = "cow_from_osstr", since = "1.27.0")] +#[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From<&'a OsString> for Cow<'a, OsStr> { #[inline] fn from(s: &'a OsString) -> Cow<'a, OsStr> { @@ -688,7 +688,7 @@ impl<'a> From<&'a OsString> for Cow<'a, OsStr> { } } -#[stable(feature = "osstring_from_cow_osstr", since = "1.27.0")] +#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] impl<'a> From> for OsString { #[inline] fn from(s: Cow<'a, OsStr>) -> Self { diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 83633210ff2..b7ab14b29ca 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1532,7 +1532,7 @@ impl<'a> From for Cow<'a, Path> { } } -#[stable(feature = "cow_from_pathbuf_ref", since = "1.27.0")] +#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")] impl<'a> From<&'a PathBuf> for Cow<'a, Path> { #[inline] fn from(p: &'a PathBuf) -> Cow<'a, Path> { @@ -1540,7 +1540,7 @@ impl<'a> From<&'a PathBuf> for Cow<'a, Path> { } } -#[stable(feature = "pathbuf_from_cow_path", since = "1.27.0")] +#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")] impl<'a> From> for PathBuf { #[inline] fn from(p: Cow<'a, Path>) -> Self { -- cgit 1.4.1-3-g733a5 From 7c0f664f153f4f41f820723c6b2c758ad5286531 Mon Sep 17 00:00:00 2001 From: George Burton Date: Wed, 9 May 2018 07:32:50 +0100 Subject: Fix typo --- src/libstd/ffi/c_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 05ab4c3cecc..7f38cadfb22 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -682,7 +682,7 @@ impl Borrow for CString { fn borrow(&self) -> &CStr { self } } -#[stable(feature = "cstring_from_cow_cstr", since = "1.2780")] +#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")] impl<'a> From> for CString { #[inline] fn from(s: Cow<'a, CStr>) -> Self { -- cgit 1.4.1-3-g733a5 From 0ba1c101dce22fbe30933a90efd237a09227e07d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 9 May 2018 06:47:37 -0700 Subject: Clarify in the docs that `mul_add` is not always faster. Fixes https://github.com/rust-lang/rust/issues/49842. Other resources: - https://users.rust-lang.org/t/why-does-the-mul-add-method-produce-a-more-accurate-result-with-better-performance/1626 - https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation --- src/libstd/f32.rs | 6 ++++-- src/libstd/f64.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 26644c76957..4f4baf1e8cd 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -195,8 +195,10 @@ impl f32 { } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error. This produces a more accurate result with better performance than - /// a separate multiplication operation followed by an add. + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. /// /// ``` /// use std::f32; diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a7e63f59b1c..e00ff60452d 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -173,8 +173,10 @@ impl f64 { } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error. This produces a more accurate result with better performance than - /// a separate multiplication operation followed by an add. + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. /// /// ``` /// let m = 10.0_f64; -- cgit 1.4.1-3-g733a5 From 8010604b2d888ac839147fe27de76cdcc713aa1b Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 9 May 2018 18:03:56 -0400 Subject: move See also links to top --- src/liballoc/slice.rs | 4 ++-- src/liballoc/str.rs | 4 ++-- src/libcore/num/f32.rs | 4 ++-- src/libcore/num/f64.rs | 4 ++-- src/libstd/f32.rs | 4 ++-- src/libstd/f64.rs | 4 ++-- src/libstd/primitive_docs.rs | 16 ++++++++-------- 7 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index d50a3458f20..6caf12aa7eb 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -10,6 +10,8 @@ //! A dynamically-sized view into a contiguous sequence, `[T]`. //! +//! *[See also the slice primitive type](../../std/primitive.slice.html).* +//! //! Slices are a view into a block of memory represented as a pointer and a //! length. //! @@ -78,8 +80,6 @@ //! * Further methods that return iterators are [`.split`], [`.splitn`], //! [`.chunks`], [`.windows`] and more. //! -//! *[See also the slice primitive type](../../std/primitive.slice.html).* -//! //! [`Clone`]: ../../std/clone/trait.Clone.html //! [`Eq`]: ../../std/cmp/trait.Eq.html //! [`Ord`]: ../../std/cmp/trait.Ord.html diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 9e693c89be9..42efdea74b1 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -10,6 +10,8 @@ //! Unicode string slices. //! +//! *[See also the `str` primitive type](../../std/primitive.str.html).* +//! //! The `&str` type is one of the two main string types, the other being `String`. //! Unlike its `String` counterpart, its contents are borrowed. //! @@ -29,8 +31,6 @@ //! ``` //! let hello_world: &'static str = "Hello, world!"; //! ``` -//! -//! *[See also the `str` primitive type](../../std/primitive.str.html).* #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 672119eba7f..4a7dc13f0f2 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 220b23a1e6a..801de5e87bd 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 26644c76957..f4d897b0111 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a7e63f59b1c..bd24e84dbed 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -11,9 +11,9 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 437d7d74cae..6e329d85539 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -370,6 +370,8 @@ mod prim_unit { } // /// Raw, unsafe pointers, `*const T`, and `*mut T`. /// +/// *[See also the `std::ptr` module](ptr/index.html).* +/// /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. /// @@ -444,8 +446,6 @@ mod prim_unit { } /// but C APIs hand out a lot of pointers generally, so are a common source /// of raw pointers in Rust. /// -/// *[See also the `std::ptr` module](ptr/index.html).* -/// /// [`null`]: ../std/ptr/fn.null.html /// [`null_mut`]: ../std/ptr/fn.null_mut.html /// [`is_null`]: ../std/primitive.pointer.html#method.is_null @@ -563,6 +563,8 @@ mod prim_array { } // /// A dynamically-sized view into a contiguous sequence, `[T]`. /// +/// *[See also the `std::slice` module](slice/index.html).* +/// /// Slices are a view into a block of memory represented as a pointer and a /// length. /// @@ -585,8 +587,6 @@ mod prim_array { } /// assert_eq!(x, &[1, 7, 3]); /// ``` /// -/// *[See also the `std::slice` module](slice/index.html).* -/// #[stable(feature = "rust1", since = "1.0.0")] mod prim_slice { } @@ -862,11 +862,11 @@ mod prim_u128 { } // /// The pointer-sized signed integer type. /// +/// *[See also the `std::isize` module](isize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::isize` module](isize/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_isize { } @@ -874,11 +874,11 @@ mod prim_isize { } // /// The pointer-sized unsigned integer type. /// +/// *[See also the `std::usize` module](usize/index.html).* +/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. -/// -/// *[See also the `std::usize` module](usize/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_usize { } -- cgit 1.4.1-3-g733a5 From b8eb91a5ade04804118d39a0f74ae908f33b6268 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 9 May 2018 18:05:36 -0400 Subject: make std::str link into See also link also make a drive-by typo fix --- src/libstd/primitive_docs.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 6e329d85539..7074928eaf6 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -594,15 +594,13 @@ mod prim_slice { } // /// String slices. /// +/// *[See also the `std::str` module](str/index.html).* +/// /// The `str` type, also called a 'string slice', is the most primitive string /// type. It is usually seen in its borrowed form, `&str`. It is also the type /// of string literals, `&'static str`. /// -/// Strings slices are always valid UTF-8. -/// -/// This documentation describes a number of methods and trait implementations -/// on the `str` type. For technical reasons, there is additional, separate -/// documentation in the [`std::str`](str/index.html) module as well. +/// String slices are always valid UTF-8. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 9d7eda96ee57ed951bd93a420814c6f8c65c1cf2 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 10 May 2018 18:05:29 +1000 Subject: Mention that fs::canonicalize makes paths absolute. --- src/libstd/fs.rs | 4 ++-- src/libstd/path.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 7bd1adc411a..f877c77ad7f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1699,8 +1699,8 @@ pub fn read_link>(path: P) -> io::Result { fs_imp::readlink(path.as_ref()) } -/// Returns the canonical form of a path with all intermediate components -/// normalized and symbolic links resolved. +/// Returns the canonical, absolute form of a path with all intermediate +/// components normalized and symbolic links resolved. /// /// # Platform-specific behavior /// diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 696711a70d4..b670ae597b2 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2284,8 +2284,8 @@ impl Path { fs::symlink_metadata(self) } - /// Returns the canonical form of the path with all intermediate components - /// normalized and symbolic links resolved. + /// Returns the canonical, absolute form of the path with all intermediate + /// components normalized and symbolic links resolved. /// /// This is an alias to [`fs::canonicalize`]. /// -- cgit 1.4.1-3-g733a5 From 8720314c025cd222fd04d07119e2cf180f53770a Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 10 May 2018 18:06:47 +1000 Subject: fs::canonicalize has some important portability concerns. --- src/libstd/fs.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index f877c77ad7f..732da79a4d4 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1708,7 +1708,14 @@ pub fn read_link>(path: P) -> io::Result { /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// Note that, this [may change in the future][changes]. /// +/// On Windows, this converts the path to use [extended length path][path] +/// syntax, which allows your program to use longer path names, but means you +/// can only join backslash-delimited paths to it, and it may be incompatible +/// with other applications (if passed to the application on the command-line, +/// or written to a file another application may read). +/// /// [changes]: ../io/index.html#platform-specific-behavior +/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath /// /// # Errors /// -- cgit 1.4.1-3-g733a5 From bf6804b79c9ecc30009a464b3342df04747381c8 Mon Sep 17 00:00:00 2001 From: Aaron DeVore Date: Thu, 10 May 2018 11:47:31 -0700 Subject: fs::write: Add example writing a &str --- src/libstd/fs.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 732da79a4d4..442a0873ae0 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -331,6 +331,7 @@ pub fn read_to_string>(path: P) -> io::Result { /// /// fn main() -> std::io::Result<()> { /// fs::write("foo.txt", b"Lorem ipsum")?; +/// fs::write("bar.txt", "dolor sit")?; /// Ok(()) /// } /// ``` -- cgit 1.4.1-3-g733a5 From 5d015e1366d4c54f86d02638e2de3c89c43af481 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sat, 12 May 2018 02:31:38 +0200 Subject: Do not silently truncate offsets for `read_at`/`write_at` on emscripten Generate an IO error if the offset is out of bounds for the system call. --- src/libstd/sys/unix/fd.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 5dafc3251e7..67546d06b4e 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -75,8 +75,15 @@ impl FileDesc { unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) -> io::Result { + use convert::TryInto; use libc::pread64; - cvt(pread64(fd, buf, count, offset as i32)) + // pread64 on emscripten actually takes a 32 bit offset + if let Ok(o) = offset.try_into() { + cvt(pread64(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pread >2GB")) + } } #[cfg(not(any(target_os = "android", target_os = "emscripten")))] @@ -116,8 +123,15 @@ impl FileDesc { unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) -> io::Result { + use convert::TryInto; use libc::pwrite64; - cvt(pwrite64(fd, buf, count, offset as i32)) + // pwrite64 on emscripten actually takes a 32 bit offset + if let Ok(o) = offset.try_into() { + cvt(pwrite64(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pwrite >2GB")) + } } #[cfg(not(any(target_os = "android", target_os = "emscripten")))] -- cgit 1.4.1-3-g733a5 From 2c4b152356fb95afb27a101d7df6c8a7ad6ebf5b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sun, 13 May 2018 15:54:40 -0400 Subject: Add “Examples” section header in f32/f64 doc comments. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is recommend by [RFC 0505] and as far as I know, the only primitive types without this heading. [RFC 0505]: https://github.com/rust-lang/rfcs/blob/c892139be692586e0846fbf934be6fceec17f329/text/0505-api-comment-conventions.md#using-markdown --- src/libstd/f32.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/f64.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index f849db4ec60..7314d32b020 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -49,6 +49,8 @@ impl f32 { /// Returns the largest integer less than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.99_f32; /// let g = 3.0_f32; @@ -80,6 +82,8 @@ impl f32 { /// Returns the smallest integer greater than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.01_f32; /// let g = 4.0_f32; @@ -100,6 +104,8 @@ impl f32 { /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. /// + /// # Examples + /// /// ``` /// let f = 3.3_f32; /// let g = -3.3_f32; @@ -115,6 +121,8 @@ impl f32 { /// Returns the integer part of a number. /// + /// # Examples + /// /// ``` /// let f = 3.3_f32; /// let g = -3.7_f32; @@ -130,6 +138,8 @@ impl f32 { /// Returns the fractional part of a number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -148,6 +158,8 @@ impl f32 { /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -174,6 +186,8 @@ impl f32 { /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is `NAN` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -200,6 +214,8 @@ impl f32 { /// Using `mul_add` can be more performant than an unfused multiply-add if /// the target architecture has a dedicated `fma` CPU instruction. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -225,6 +241,8 @@ impl f32 { /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f32 = 7.0; @@ -248,6 +266,8 @@ impl f32 { /// /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f32 = 7.0; @@ -273,6 +293,8 @@ impl f32 { /// /// Using this function is generally faster than using `powf` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -289,6 +311,8 @@ impl f32 { /// Raises a number to a floating point power. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -311,6 +335,8 @@ impl f32 { /// /// Returns NaN if `self` is a negative number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -334,6 +360,8 @@ impl f32 { /// Returns `e^(self)`, (the exponential function). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -358,6 +386,8 @@ impl f32 { /// Returns `2^(self)`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -376,6 +406,8 @@ impl f32 { /// Returns the natural logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -404,6 +436,8 @@ impl f32 { /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -420,6 +454,8 @@ impl f32 { /// Returns the base 2 logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -441,6 +477,8 @@ impl f32 { /// Returns the base 10 logarithm of the number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -466,6 +504,8 @@ impl f32 { /// * If `self <= other`: `0:0` /// * Else: `self - other` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -493,6 +533,8 @@ impl f32 { /// Takes the cubic root of a number. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -512,6 +554,8 @@ impl f32 { /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -531,6 +575,8 @@ impl f32 { /// Computes the sine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -552,6 +598,8 @@ impl f32 { /// Computes the cosine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -573,6 +621,8 @@ impl f32 { /// Computes the tangent of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -591,6 +641,8 @@ impl f32 { /// the range [-pi/2, pi/2] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -611,6 +663,8 @@ impl f32 { /// the range [0, pi] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -630,6 +684,8 @@ impl f32 { /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -653,6 +709,8 @@ impl f32 { /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -682,6 +740,8 @@ impl f32 { /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -703,6 +763,8 @@ impl f32 { /// Returns `e^(self) - 1` in a way that is accurate even if the /// number is close to zero. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -722,6 +784,8 @@ impl f32 { /// Returns `ln(1+n)` (natural logarithm) more accurately than if /// the operations were performed separately. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -740,6 +804,8 @@ impl f32 { /// Hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -761,6 +827,8 @@ impl f32 { /// Hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -782,6 +850,8 @@ impl f32 { /// Hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -803,6 +873,8 @@ impl f32 { /// Inverse hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -825,6 +897,8 @@ impl f32 { /// Inverse hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f32; /// @@ -846,6 +920,8 @@ impl f32 { /// Inverse hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f32; /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 40c3f4d0ef7..75edba8979f 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -49,6 +49,8 @@ impl f64 { /// Returns the largest integer less than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.99_f64; /// let g = 3.0_f64; @@ -64,6 +66,8 @@ impl f64 { /// Returns the smallest integer greater than or equal to a number. /// + /// # Examples + /// /// ``` /// let f = 3.01_f64; /// let g = 4.0_f64; @@ -80,6 +84,8 @@ impl f64 { /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. /// + /// # Examples + /// /// ``` /// let f = 3.3_f64; /// let g = -3.3_f64; @@ -95,6 +101,8 @@ impl f64 { /// Returns the integer part of a number. /// + /// # Examples + /// /// ``` /// let f = 3.3_f64; /// let g = -3.7_f64; @@ -110,6 +118,8 @@ impl f64 { /// Returns the fractional part of a number. /// + /// # Examples + /// /// ``` /// let x = 3.5_f64; /// let y = -3.5_f64; @@ -126,6 +136,8 @@ impl f64 { /// Computes the absolute value of `self`. Returns `NAN` if the /// number is `NAN`. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -152,6 +164,8 @@ impl f64 { /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `NAN` if the number is `NAN` /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -178,6 +192,8 @@ impl f64 { /// Using `mul_add` can be more performant than an unfused multiply-add if /// the target architecture has a dedicated `fma` CPU instruction. /// + /// # Examples + /// /// ``` /// let m = 10.0_f64; /// let x = 4.0_f64; @@ -201,6 +217,8 @@ impl f64 { /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f64 = 7.0; @@ -224,6 +242,8 @@ impl f64 { /// /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. /// + /// # Examples + /// /// ``` /// #![feature(euclidean_division)] /// let a: f64 = 7.0; @@ -248,6 +268,8 @@ impl f64 { /// /// Using this function is generally faster than using `powf` /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powi(2) - x*x).abs(); @@ -262,6 +284,8 @@ impl f64 { /// Raises a number to a floating point power. /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let abs_difference = (x.powf(2.0) - x*x).abs(); @@ -278,6 +302,8 @@ impl f64 { /// /// Returns NaN if `self` is a negative number. /// + /// # Examples + /// /// ``` /// let positive = 4.0_f64; /// let negative = -4.0_f64; @@ -299,6 +325,8 @@ impl f64 { /// Returns `e^(self)`, (the exponential function). /// + /// # Examples + /// /// ``` /// let one = 1.0_f64; /// // e^1 @@ -317,6 +345,8 @@ impl f64 { /// Returns `2^(self)`. /// + /// # Examples + /// /// ``` /// let f = 2.0_f64; /// @@ -333,6 +363,8 @@ impl f64 { /// Returns the natural logarithm of the number. /// + /// # Examples + /// /// ``` /// let one = 1.0_f64; /// // e^1 @@ -355,6 +387,8 @@ impl f64 { /// `self.log2()` can produce more accurate results for base 2, and /// `self.log10()` can produce more accurate results for base 10. /// + /// # Examples + /// /// ``` /// let five = 5.0_f64; /// @@ -369,6 +403,8 @@ impl f64 { /// Returns the base 2 logarithm of the number. /// + /// # Examples + /// /// ``` /// let two = 2.0_f64; /// @@ -390,6 +426,8 @@ impl f64 { /// Returns the base 10 logarithm of the number. /// + /// # Examples + /// /// ``` /// let ten = 10.0_f64; /// @@ -409,6 +447,8 @@ impl f64 { /// * If `self <= other`: `0:0` /// * Else: `self - other` /// + /// # Examples + /// /// ``` /// let x = 3.0_f64; /// let y = -3.0_f64; @@ -434,6 +474,8 @@ impl f64 { /// Takes the cubic root of a number. /// + /// # Examples + /// /// ``` /// let x = 8.0_f64; /// @@ -451,6 +493,8 @@ impl f64 { /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// + /// # Examples + /// /// ``` /// let x = 2.0_f64; /// let y = 3.0_f64; @@ -468,6 +512,8 @@ impl f64 { /// Computes the sine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -485,6 +531,8 @@ impl f64 { /// Computes the cosine of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -502,6 +550,8 @@ impl f64 { /// Computes the tangent of a number (in radians). /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -520,6 +570,8 @@ impl f64 { /// the range [-pi/2, pi/2] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -540,6 +592,8 @@ impl f64 { /// the range [0, pi] or NaN if the number is outside the range /// [-1, 1]. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -559,6 +613,8 @@ impl f64 { /// Computes the arctangent of a number. Return value is in radians in the /// range [-pi/2, pi/2]; /// + /// # Examples + /// /// ``` /// let f = 1.0_f64; /// @@ -580,6 +636,8 @@ impl f64 { /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -609,6 +667,8 @@ impl f64 { /// Simultaneously computes the sine and cosine of the number, `x`. Returns /// `(sin(x), cos(x))`. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -630,6 +690,8 @@ impl f64 { /// Returns `e^(self) - 1` in a way that is accurate even if the /// number is close to zero. /// + /// # Examples + /// /// ``` /// let x = 7.0_f64; /// @@ -647,6 +709,8 @@ impl f64 { /// Returns `ln(1+n)` (natural logarithm) more accurately than if /// the operations were performed separately. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -665,6 +729,8 @@ impl f64 { /// Hyperbolic sine function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -686,6 +752,8 @@ impl f64 { /// Hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -707,6 +775,8 @@ impl f64 { /// Hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f64; /// @@ -728,6 +798,8 @@ impl f64 { /// Inverse hyperbolic sine function. /// + /// # Examples + /// /// ``` /// let x = 1.0_f64; /// let f = x.sinh().asinh(); @@ -748,6 +820,8 @@ impl f64 { /// Inverse hyperbolic cosine function. /// + /// # Examples + /// /// ``` /// let x = 1.0_f64; /// let f = x.cosh().acosh(); @@ -767,6 +841,8 @@ impl f64 { /// Inverse hyperbolic tangent function. /// + /// # Examples + /// /// ``` /// use std::f64; /// -- cgit 1.4.1-3-g733a5 From 56f505e6c650106cb2328145f8f51ff4c9459124 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Mon, 14 May 2018 03:23:10 +0200 Subject: read2: Use inner function instead of closure --- src/libstd/sys/unix/pipe.rs | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index ec9b6f17dca..0a5dccdddda 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -100,24 +100,6 @@ pub fn read2(p1: AnonPipe, // wait for either pipe to become readable using `poll` cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - let read = |fd: &FileDesc, dst: &mut Vec| { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) || - e.raw_os_error() == Some(libc::EAGAIN) { - Ok(false) - } else { - Err(e) - } - } - } - }; if fds[0].revents != 0 && read(&p1, v1)? { p2.set_nonblocking(false)?; return p2.read_to_end(v2).map(|_| ()); @@ -127,4 +109,23 @@ pub fn read2(p1: AnonPipe, return p1.read_to_end(v1).map(|_| ()); } } + + // Read as much as we can from each pipe, ignoring EWOULDBLOCK or + // EAGAIN. If we hit EOF, then this will happen because the underlying + // reader will return Ok(0), in which case we'll see `Ok` ourselves. In + // this case we flip the other fd back into blocking mode and read + // whatever's leftover on that file descriptor. + fn read(fd: &FileDesc, dst: &mut Vec) -> Result { + match fd.read_to_end(dst) { + Ok(_) => Ok(true), + Err(e) => { + if e.raw_os_error() == Some(libc::EWOULDBLOCK) || + e.raw_os_error() == Some(libc::EAGAIN) { + Ok(false) + } else { + Err(e) + } + } + } + } } -- cgit 1.4.1-3-g733a5 From f73c4a47682870f7eabac63882da7255eca0b463 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Mon, 14 May 2018 04:32:27 +0200 Subject: env: remove unwrap in examples in favor of try op --- src/libstd/env.rs | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/env.rs b/src/libstd/env.rs index a103c0bdd59..91e417c64da 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -49,9 +49,11 @@ use sys::os as os_imp; /// ``` /// use std::env; /// -/// // We assume that we are in a valid directory. -/// let path = env::current_dir().unwrap(); -/// println!("The current directory is {}", path.display()); +/// fn main() -> std::io::Result<()> { +/// let path = env::current_dir()?; +/// println!("The current directory is {}", path.display()); +/// Ok(()) +/// } /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn current_dir() -> io::Result { @@ -441,15 +443,18 @@ pub struct JoinPathsError { /// Joining paths on a Unix-like platform: /// /// ``` -/// # if cfg!(unix) { /// use std::env; /// use std::ffi::OsString; /// use std::path::Path; /// -/// let paths = [Path::new("/bin"), Path::new("/usr/bin")]; -/// let path_os_string = env::join_paths(paths.iter()).unwrap(); -/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin")); +/// fn main() -> Result<(), env::JoinPathsError> { +/// # if cfg!(unix) { +/// let paths = [Path::new("/bin"), Path::new("/usr/bin")]; +/// let path_os_string = env::join_paths(paths.iter())?; +/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin")); /// # } +/// Ok(()) +/// } /// ``` /// /// Joining a path containing a colon on a Unix-like platform results in an error: @@ -471,11 +476,15 @@ pub struct JoinPathsError { /// use std::env; /// use std::path::PathBuf; /// -/// if let Some(path) = env::var_os("PATH") { -/// let mut paths = env::split_paths(&path).collect::>(); -/// paths.push(PathBuf::from("/home/xyz/bin")); -/// let new_path = env::join_paths(paths).unwrap(); -/// env::set_var("PATH", &new_path); +/// fn main() -> Result<(), env::JoinPathsError> { +/// if let Some(path) = env::var_os("PATH") { +/// let mut paths = env::split_paths(&path).collect::>(); +/// paths.push(PathBuf::from("/home/xyz/bin")); +/// let new_path = env::join_paths(paths)?; +/// env::set_var("PATH", &new_path); +/// } +/// +/// Ok(()) /// } /// ``` #[stable(feature = "env", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 6d1da8232997af4b785486329f01995440818920 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 14 May 2018 13:20:39 +0200 Subject: Don't unconditionally set CLOEXEC twice on every fd we open on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, every `open64` was accompanied by a `ioctl(…, FIOCLEX)`, because some old Linux version would ignore the `O_CLOEXEC` flag we pass to the `open64` function. Now, we check whether the `CLOEXEC` flag is set on the first file we open – if it is, we won't do extra syscalls for every opened file. If it is not set, we fall back to the old behavior of unconditionally calling `ioctl(…, FIOCLEX)` on newly opened files. On old Linuxes, this amounts to one extra syscall per process, namely the `fcntl(…, F_GETFD)` call to check the `CLOEXEC` flag. On new Linuxes, this reduces the number of syscalls per opened file by one, except for the first file, where it does the same number of syscalls as before (`fcntl(…, F_GETFD)` to check the flag instead of `ioctl(…, FIOCLEX)` to set it). --- src/libstd/sys/unix/fd.rs | 7 +++++++ src/libstd/sys/unix/fs.rs | 41 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 5dafc3251e7..72272d0581a 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -140,6 +140,13 @@ impl FileDesc { } } + #[cfg(target_os = "linux")] + pub fn get_cloexec(&self) -> io::Result { + unsafe { + Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) + } + } + #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten", diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index a1ca839dc18..77968ffdedf 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -441,15 +441,48 @@ impl File { // Currently the standard library supports Linux 2.6.18 which did not // have the O_CLOEXEC flag (passed above). If we're running on an older - // Linux kernel then the flag is just ignored by the OS, so we continue - // to explicitly ask for a CLOEXEC fd here. + // Linux kernel then the flag is just ignored by the OS. After we open + // the first file, we check whether it has CLOEXEC set. If it doesn't, + // we will explicitly ask for a CLOEXEC fd for every further file we + // open, if it does, we will skip that step. // // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc // that we support, so we only do this on Linux currently. - if cfg!(target_os = "linux") { - fd.set_cloexec()?; + #[cfg(target_os = "linux")] + fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> { + use sync::atomic::{AtomicUsize, Ordering}; + + const OPEN_CLOEXEC_UNKNOWN: usize = 0; + const OPEN_CLOEXEC_SUPPORTED: usize = 1; + const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2; + static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN); + + let need_to_set; + match OPEN_CLOEXEC.load(Ordering::Relaxed) { + OPEN_CLOEXEC_UNKNOWN => { + need_to_set = !fd.get_cloexec()?; + OPEN_CLOEXEC.store(if need_to_set { + OPEN_CLOEXEC_NOTSUPPORTED + } else { + OPEN_CLOEXEC_SUPPORTED + }, Ordering::Relaxed); + }, + OPEN_CLOEXEC_SUPPORTED => need_to_set = false, + OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true, + _ => unreachable!(), + } + if need_to_set { + fd.set_cloexec()?; + } + Ok(()) + } + + #[cfg(not(target_os = "linux"))] + fn ensure_cloexec(_: &FileDesc) -> io::Result<()> { + Ok(()) } + ensure_cloexec(&fd)?; Ok(File(fd)) } -- cgit 1.4.1-3-g733a5 From 834ef9f08ae3429a05dead80237bb4bd04769895 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Tue, 15 May 2018 15:25:09 +0200 Subject: fs: use copy_file_range on linux --- src/libstd/sys/unix/fs.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index a1ca839dc18..b9f0f39bbe2 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -761,6 +761,7 @@ pub fn canonicalize(p: &Path) -> io::Result { Ok(PathBuf::from(OsString::from_vec(buf))) } +#[cfg(not(target_os = "linux"))] pub fn copy(from: &Path, to: &Path) -> io::Result { use fs::{File, set_permissions}; if !from.is_file() { @@ -776,3 +777,69 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { set_permissions(to, perm)?; Ok(ret) } + +#[cfg(target_os = "linux")] +pub fn copy(from: &Path, to: &Path) -> io::Result { + use fs::{File, set_permissions}; + + unsafe fn copy_file_range( + fd_in: libc::c_int, + off_in: *mut libc::loff_t, + fd_out: libc::c_int, + off_out: *mut libc::loff_t, + len: libc::size_t, + flags: libc::c_uint, + ) -> libc::c_long { + libc::syscall( + libc::SYS_copy_file_range, + fd_in, + off_in, + fd_out, + off_out, + len, + flags, + ) + } + + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing regular file")) + } + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + let (perm, len) = { + let metadata = reader.metadata()?; + (metadata.permissions(), metadata.size()) + }; + + let mut written = 0u64; + while written < len { + let copy_result = unsafe { + cvt(copy_file_range(reader.as_raw_fd(), + ptr::null_mut(), + writer.as_raw_fd(), + ptr::null_mut(), + len as usize, + 0) + ) + }; + match copy_result { + Ok(ret) => written += ret as u64, + Err(err) => { + match err.raw_os_error() { + Some(os_err) if os_err == libc::ENOSYS || os_err == libc::EXDEV => { + // Either kernel is too old or the files are not mounted on the same fs. + // Try again with fallback method + let ret = io::copy(&mut reader, &mut writer)?; + set_permissions(to, perm)?; + return Ok(ret) + }, + _ => return Err(err), + } + } + } + } + set_permissions(to, perm)?; + Ok(written) +} -- cgit 1.4.1-3-g733a5 From 00ec3cf2a0449f41bd3cb873bc9b2cf1b6241095 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Wed, 16 May 2018 10:17:06 +0200 Subject: Use copy_file_range on android also --- src/libstd/sys/unix/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index b9f0f39bbe2..42dc7b83da9 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -761,7 +761,7 @@ pub fn canonicalize(p: &Path) -> io::Result { Ok(PathBuf::from(OsString::from_vec(buf))) } -#[cfg(not(target_os = "linux"))] +#[cfg(not(any(target_os = "linux", target_os = "android")))] pub fn copy(from: &Path, to: &Path) -> io::Result { use fs::{File, set_permissions}; if !from.is_file() { @@ -778,7 +778,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Ok(ret) } -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "android"))] pub fn copy(from: &Path, to: &Path) -> io::Result { use fs::{File, set_permissions}; @@ -812,7 +812,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let metadata = reader.metadata()?; (metadata.permissions(), metadata.size()) }; - + let mut written = 0u64; while written < len { let copy_result = unsafe { -- cgit 1.4.1-3-g733a5 From b605923cc83a444f6be52542b891d31b00c87662 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Wed, 16 May 2018 10:21:34 +0200 Subject: Add clarifying comment about offset argument --- src/libstd/sys/unix/fs.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 42dc7b83da9..0649a147ea3 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -816,6 +816,8 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let mut written = 0u64; while written < len { let copy_result = unsafe { + // We actually don't have to adjust the offsets, + // because copy_file_range adjusts the file offset automatically cvt(copy_file_range(reader.as_raw_fd(), ptr::null_mut(), writer.as_raw_fd(), -- cgit 1.4.1-3-g733a5 From f4c2825c8f80eae6ef18eb3fa30464a18a588e0f Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Wed, 16 May 2018 10:27:14 +0200 Subject: Adjust len in every iteration --- src/libstd/sys/unix/fs.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0649a147ea3..c9d187f2ff2 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -815,6 +815,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let mut written = 0u64; while written < len { + let bytes_to_copy = len - written; let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically @@ -822,7 +823,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { ptr::null_mut(), writer.as_raw_fd(), ptr::null_mut(), - len as usize, + bytes_to_copy as usize, 0) ) }; -- cgit 1.4.1-3-g733a5 From a5e2942861324493c2cc5a32cb1473e656857b98 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Wed, 16 May 2018 10:35:19 +0200 Subject: Fix large file copies on 32 bit platforms --- src/libstd/sys/unix/fs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index c9d187f2ff2..d8739d65326 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -815,7 +815,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let mut written = 0u64; while written < len { - let bytes_to_copy = len - written; + let bytes_to_copy = if len - written > usize::max_value() as u64 { + usize::max_value() + } else { + (len - written) as usize + }; let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically @@ -823,7 +827,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { ptr::null_mut(), writer.as_raw_fd(), ptr::null_mut(), - bytes_to_copy as usize, + bytes_to_copy, 0) ) }; -- cgit 1.4.1-3-g733a5 From c536639c1e1ce7e2b4816a40f2e954c581431456 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 24 Mar 2018 11:36:29 +0100 Subject: Remove unstable deprecated num::NonZeroI* types --- src/libcore/num/mod.rs | 18 +----------------- src/libstd/num.rs | 5 +---- 2 files changed, 2 insertions(+), 21 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ef914a0fc5c..342f57b50f0 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -24,7 +24,6 @@ macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( #[$stability] - #[allow(deprecated)] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -36,7 +35,7 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] #[$deprecation: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -48,7 +47,6 @@ macro_rules! nonzero_integers { /// assert_eq!(size_of::>(), size_of::()); /// ``` #[$stability] - #[$deprecation] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); @@ -94,7 +92,6 @@ macro_rules! nonzero_integers { nonzero_integers! { #[unstable(feature = "nonzero", issue = "49137")] - #[allow(deprecated)] // Redundant, works around "error: inconsistent lockstep iteration" NonZeroU8(u8); NonZeroU16(u16); NonZeroU32(u32); @@ -103,19 +100,6 @@ nonzero_integers! { NonZeroUsize(usize); } -nonzero_integers! { - #[unstable(feature = "nonzero", issue = "49137")] - #[rustc_deprecated(since = "1.26.0", reason = "\ - signed non-zero integers are considered for removal due to lack of known use cases. \ - If you’re using them, please comment on https://github.com/rust-lang/rust/issues/49137")] - NonZeroI8(i8); - NonZeroI16(i16); - NonZeroI32(i32); - NonZeroI64(i64); - NonZeroI128(i128); - NonZeroIsize(isize); -} - /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values is intended to never overflow, diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 4b975dd912a..aa806b947b0 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -23,10 +23,7 @@ pub use core::num::Wrapping; #[unstable(feature = "nonzero", issue = "49137")] #[allow(deprecated)] -pub use core::num::{ - NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, - NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize, -}; +pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; -- cgit 1.4.1-3-g733a5 From 89d9ca9b50e01cbc5dc78a26f15cc8c435bbc5a4 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 16 May 2018 18:07:35 +0200 Subject: Stabilize num::NonZeroU* Tracking issue: https://github.com/rust-lang/rust/issues/49137 --- src/liballoc/lib.rs | 1 - src/libcore/num/mod.rs | 16 +++++++--------- src/libcore/tests/lib.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_data_structures/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/libstd/lib.rs | 1 - src/libstd/num.rs | 3 +-- src/test/run-pass/ctfe/tuple-struct-constructors.rs | 1 - src/test/run-pass/enum-null-pointer-opt.rs | 2 -- src/test/ui/print_type_sizes/niche-filling.rs | 1 - 11 files changed, 8 insertions(+), 21 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index bb78c14b905..f7dd9d4f010 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -102,7 +102,6 @@ #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] -#![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 342f57b50f0..ae8b3087240 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -21,9 +21,9 @@ use ops; use str::FromStr; macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -35,7 +35,7 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// @@ -46,7 +46,7 @@ macro_rules! nonzero_integers { /// use std::mem::size_of; /// assert_eq!(size_of::>(), size_of::()); /// ``` - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct $Ty(NonZero<$Int>); @@ -56,14 +56,14 @@ macro_rules! nonzero_integers { /// # Safety /// /// The value must not be zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { $Ty(NonZero(n)) } /// Create a non-zero if the given value is not zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn new(n: $Int) -> Option { if n != 0 { @@ -74,7 +74,7 @@ macro_rules! nonzero_integers { } /// Returns the value as a primitive type. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn get(self) -> $Int { self.0 .0 @@ -83,7 +83,6 @@ macro_rules! nonzero_integers { } impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } )+ @@ -91,7 +90,6 @@ macro_rules! nonzero_integers { } nonzero_integers! { - #[unstable(feature = "nonzero", issue = "49137")] NonZeroU8(u8); NonZeroU16(u16); NonZeroU32(u32); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5e98e40e0d5..7fb4b503c01 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -26,7 +26,6 @@ #![feature(iterator_step_by)] #![feature(iterator_flatten)] #![feature(iterator_repeat_with)] -#![feature(nonzero)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 26ac9d6ee9e..ac6ff6831ad 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -56,7 +56,6 @@ #![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(non_exhaustive)] -#![feature(nonzero)] #![feature(proc_macro_internals)] #![feature(quote)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index b2e7450e76c..328ff76c1cd 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -21,7 +21,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(collections_range)] -#![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index fbc0facbc49..ecced1b8168 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -30,7 +30,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(nonzero)] #![feature(inclusive_range_methods)] #![feature(crate_visibility_modifier)] #![feature(never_type)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d41739ab02c..9cdc6a21622 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -277,7 +277,6 @@ #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(exhaustive_patterns)] -#![feature(nonzero)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index aa806b947b0..3f90c1fa3b1 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,8 +21,7 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; -#[unstable(feature = "nonzero", issue = "49137")] -#[allow(deprecated)] +#[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; #[cfg(test)] use fmt; diff --git a/src/test/run-pass/ctfe/tuple-struct-constructors.rs b/src/test/run-pass/ctfe/tuple-struct-constructors.rs index ee1ce192fe0..d5f3e88fd52 100644 --- a/src/test/run-pass/ctfe/tuple-struct-constructors.rs +++ b/src/test/run-pass/ctfe/tuple-struct-constructors.rs @@ -10,7 +10,6 @@ // https://github.com/rust-lang/rust/issues/41898 -#![feature(nonzero)] use std::num::NonZeroU64; fn main() { diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index 12f17a1575e..34ed589d418 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(nonzero, core)] - use std::mem::size_of; use std::num::NonZeroUsize; use std::ptr::NonNull; diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs index 1aad0b760b1..17e7a21cd02 100644 --- a/src/test/ui/print_type_sizes/niche-filling.rs +++ b/src/test/ui/print_type_sizes/niche-filling.rs @@ -22,7 +22,6 @@ // padding and overall computed sizes can be quite different. #![feature(start)] -#![feature(nonzero)] #![allow(dead_code)] use std::num::NonZeroU32; -- cgit 1.4.1-3-g733a5 From 09d03bc245b27728c9cdd4976114506ae20208a7 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Thu, 17 May 2018 14:10:14 +0200 Subject: Store ENOSYS in a global to avoid unnecessary system calls --- src/libstd/sys/unix/fs.rs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index d8739d65326..8412540934e 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -781,6 +781,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { #[cfg(any(target_os = "linux", target_os = "android"))] pub fn copy(from: &Path, to: &Path) -> io::Result { use fs::{File, set_permissions}; + use sync::atomic::{AtomicBool, Ordering}; + + // Kernel prior to 4.5 don't have copy_file_range + // We store the availability in a global to avoid unneccessary syscalls + static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); unsafe fn copy_file_range( fd_in: libc::c_int, @@ -820,16 +825,26 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } else { (len - written) as usize }; - let copy_result = unsafe { - // We actually don't have to adjust the offsets, - // because copy_file_range adjusts the file offset automatically - cvt(copy_file_range(reader.as_raw_fd(), - ptr::null_mut(), - writer.as_raw_fd(), - ptr::null_mut(), - bytes_to_copy, - 0) - ) + let copy_result = if HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) { + let copy_result = unsafe { + // We actually don't have to adjust the offsets, + // because copy_file_range adjusts the file offset automatically + cvt(copy_file_range(reader.as_raw_fd(), + ptr::null_mut(), + writer.as_raw_fd(), + ptr::null_mut(), + bytes_to_copy, + 0) + ) + }; + if let Err(ref copy_err) = copy_result { + if let Some(libc::ENOSYS) = copy_err.raw_os_error() { + HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); + } + } + copy_result + } else { + Err(io::Error::from_raw_os_error(libc::ENOSYS)) }; match copy_result { Ok(ret) => written += ret as u64, -- cgit 1.4.1-3-g733a5 From 9e3432447a9c6386443acdf731d488c159be3f66 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 10 May 2018 12:02:19 -0600 Subject: Switch to 1.26 bootstrap compiler --- src/bootstrap/channel.rs | 2 +- src/liballoc/Cargo.toml | 2 + src/liballoc/alloc.rs | 47 +- src/liballoc/lib.rs | 10 - src/liballoc/slice.rs | 13 +- src/liballoc/str.rs | 7 +- src/liballoc/vec.rs | 3 - src/liballoc_jemalloc/lib.rs | 7 - src/liballoc_system/lib.rs | 27 - src/libarena/lib.rs | 1 - src/libcore/Cargo.toml | 2 + src/libcore/clone.rs | 1 - src/libcore/internal_macros.rs | 14 - src/libcore/lib.rs | 19 +- src/libcore/marker.rs | 1 - src/libcore/num/f32.rs | 4 +- src/libcore/num/f64.rs | 4 +- src/libcore/num/mod.rs | 2 - src/libcore/ops/range.rs | 10 - src/libcore/prelude/v1.rs | 10 - src/libcore/slice/mod.rs | 987 ++++++++----------------------- src/libcore/str/mod.rs | 590 ++++-------------- src/libcore/tests/lib.rs | 1 - src/libcore/tests/num/uint_macros.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_mir/borrow_check/nll/mod.rs | 4 +- src/librustc_mir/lib.rs | 13 +- src/librustc_mir/util/pretty.rs | 8 +- src/librustc_typeck/lib.rs | 2 - src/librustdoc/lib.rs | 2 - src/libstd/alloc.rs | 61 -- src/libstd/f32.rs | 12 +- src/libstd/f64.rs | 12 +- src/libstd/lib.rs | 9 +- src/libsyntax_ext/asm.rs | 21 +- src/libsyntax_ext/lib.rs | 3 +- src/rtstartup/rsbegin.rs | 31 +- src/stage0.txt | 2 +- 38 files changed, 434 insertions(+), 1512 deletions(-) (limited to 'src/libstd') diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 3453933a965..a2495f68c1f 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -24,7 +24,7 @@ use Build; use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.27.0"; +pub const CFG_RELEASE_NUM: &str = "1.28.0"; pub struct GitInfo { inner: Option, diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 6383bd1e941..ada21e04b30 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -2,6 +2,8 @@ authors = ["The Rust Project Developers"] name = "alloc" version = "0.0.0" +autotests = false +autobenches = false [lib] name = "alloc" diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index f59c9f7fd61..b4b82e6ecff 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -22,28 +22,6 @@ use core::usize; #[doc(inline)] pub use core::alloc::*; -#[cfg(stage0)] -extern "Rust" { - #[allocator] - #[rustc_allocator_nounwind] - fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom(err: *const u8) -> !; - #[rustc_allocator_nounwind] - fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[rustc_allocator_nounwind] - fn __rust_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; -} - -#[cfg(not(stage0))] extern "Rust" { #[allocator] #[rustc_allocator_nounwind] @@ -74,10 +52,7 @@ pub const Heap: Global = Global; unsafe impl GlobalAlloc for Global { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - #[cfg(not(stage0))] let ptr = __rust_alloc(layout.size(), layout.align()); - #[cfg(stage0)] - let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0); ptr as *mut Opaque } @@ -88,20 +63,13 @@ unsafe impl GlobalAlloc for Global { #[inline] unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - #[cfg(not(stage0))] let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); - #[cfg(stage0)] - let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), - new_size, layout.align(), &mut 0); ptr as *mut Opaque } #[inline] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - #[cfg(not(stage0))] let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); - #[cfg(stage0)] - let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); ptr as *mut Opaque } } @@ -152,14 +120,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg(stage0)] -#[lang = "box_free"] -#[inline] -unsafe fn old_box_free(ptr: *mut T) { - box_free(Unique::new_unchecked(ptr)) -} - -#[cfg_attr(not(any(test, stage0)), lang = "box_free")] +#[cfg_attr(not(test), lang = "box_free")] #[inline] pub(crate) unsafe fn box_free(ptr: Unique) { let ptr = ptr.as_ptr(); @@ -172,12 +133,6 @@ pub(crate) unsafe fn box_free(ptr: Unique) { } } -#[cfg(stage0)] -pub fn oom() -> ! { - unsafe { ::core::intrinsics::abort() } -} - -#[cfg(not(stage0))] pub fn oom() -> ! { extern { #[lang = "oom"] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f7dd9d4f010..91de3ad0c39 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -75,7 +75,6 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(all(not(test), stage0), feature(float_internals))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] @@ -90,13 +89,10 @@ #![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(core_slice_ext))] -#![cfg_attr(stage0, feature(core_str_ext))] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] -#![cfg_attr(stage0, feature(fn_must_use))] #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] @@ -122,7 +118,6 @@ #![feature(exact_chunks)] #![feature(pointer_methods)] #![feature(inclusive_range_methods)] -#![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(rustc_const_unstable)] #![feature(const_vec_new)] @@ -157,15 +152,10 @@ pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] /// Use the `alloc` module instead. -#[cfg(not(stage0))] pub mod heap { pub use alloc::*; } -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -#[cfg(stage0)] -pub mod heap; // Primitive types using the heaps above diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 6caf12aa7eb..4427ac004f9 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -101,7 +101,6 @@ use core::cmp::Ordering::{self, Less}; use core::mem::size_of; use core::mem; use core::ptr; -#[cfg(stage0)] use core::slice::SliceExt; use core::{u8, u16, u32}; use borrow::{Borrow, BorrowMut, ToOwned}; @@ -171,13 +170,9 @@ mod hack { } } -#[cfg_attr(stage0, lang = "slice")] -#[cfg_attr(not(stage0), lang = "slice_alloc")] +#[lang = "slice_alloc"] #[cfg(not(test))] impl [T] { - #[cfg(stage0)] - slice_core_methods!(); - /// Sorts the slice. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. @@ -467,8 +462,7 @@ impl [T] { } } -#[cfg_attr(stage0, lang = "slice_u8")] -#[cfg_attr(not(stage0), lang = "slice_u8_alloc")] +#[lang = "slice_u8_alloc"] #[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte @@ -504,9 +498,6 @@ impl [u8] { me.make_ascii_lowercase(); me } - - #[cfg(stage0)] - slice_u8_core_methods!(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 42efdea74b1..c10c0a69433 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -40,7 +40,6 @@ use core::fmt; use core::str as core_str; -#[cfg(stage0)] use core::str::StrExt; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; @@ -158,13 +157,9 @@ impl ToOwned for str { } /// Methods for string slices. -#[cfg_attr(stage0, lang = "str")] -#[cfg_attr(not(stage0), lang = "str_alloc")] +#[lang = "str_alloc"] #[cfg(not(test))] impl str { - #[cfg(stage0)] - str_core_methods!(); - /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. /// /// # Examples diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index d30f8cd0fca..bf89b377b7e 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -73,9 +73,6 @@ use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; use core::mem; -#[cfg(not(test))] -#[cfg(stage0)] -use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds}; use core::ops; diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 4b8755877de..ce856eccd83 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -97,13 +97,6 @@ mod contents { ptr } - #[cfg(stage0)] - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_oom() -> ! { - ::core::intrinsics::abort(); - } - #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_dealloc(ptr: *mut u8, diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 7376ac0f15d..9490b54e675 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -73,33 +73,6 @@ unsafe impl Alloc for System { } } -#[cfg(stage0)] -#[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl<'a> Alloc for &'a System { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr) - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr) - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) - } - - #[inline] - unsafe fn realloc(&mut self, - ptr: NonNull, - layout: Layout, - new_size: usize) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) - } -} - #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] mod realloc_fallback { use core::alloc::{GlobalAlloc, Opaque, Layout}; diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index c79e0e14e3d..f7143a4f981 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -26,7 +26,6 @@ #![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![cfg_attr(stage0, feature(generic_param_attrs))] #![cfg_attr(test, feature(test))] #![allow(deprecated)] diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 24529f7a9d8..321ed892ea9 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -2,6 +2,8 @@ authors = ["The Rust Project Developers"] name = "core" version = "0.0.0" +autotests = false +autobenches = false [lib] name = "core" diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index f79f7351698..3b15ba2b4ab 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -153,7 +153,6 @@ pub struct AssertParamIsCopy { _field: ::marker::PhantomData { - $(#[$attr])* pub $($Item)* - } -} - -#[cfg(not(stage0))] -macro_rules! public_in_stage0 { - ( { $(#[$attr:meta])* } $($Item: tt)*) => { - $(#[$attr])* pub(crate) $($Item)* - } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 06fbfcecba8..77b5488084d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -112,18 +112,13 @@ #![feature(unwind_attributes)] #![feature(doc_alias)] #![feature(inclusive_range_methods)] - -#![cfg_attr(not(stage0), feature(mmx_target_feature))] -#![cfg_attr(not(stage0), feature(tbm_target_feature))] -#![cfg_attr(not(stage0), feature(sse4a_target_feature))] -#![cfg_attr(not(stage0), feature(arm_target_feature))] -#![cfg_attr(not(stage0), feature(powerpc_target_feature))] -#![cfg_attr(not(stage0), feature(mips_target_feature))] -#![cfg_attr(not(stage0), feature(aarch64_target_feature))] - -#![cfg_attr(stage0, feature(target_feature))] -#![cfg_attr(stage0, feature(cfg_target_feature))] -#![cfg_attr(stage0, feature(fn_must_use))] +#![feature(mmx_target_feature)] +#![feature(tbm_target_feature)] +#![feature(sse4a_target_feature)] +#![feature(arm_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(mips_target_feature)] +#![feature(aarch64_target_feature)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index db5f50a99ca..6c8ee0eda11 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -611,7 +611,6 @@ pub unsafe auto trait Unpin {} /// /// Implementations that cannot be described in Rust /// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. -#[cfg(not(stage0))] mod copy_impls { use super::Copy; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 4a7dc13f0f2..718dd42a615 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -19,7 +19,7 @@ use mem; use num::Float; -#[cfg(not(stage0))] use num::FpCategory; +use num::FpCategory; use num::FpCategory as Fp; /// The radix or base of the internal representation of `f32`. @@ -277,7 +277,6 @@ impl Float for f32 { // FIXME: remove (inline) this macro and the Float trait // when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] #[unstable(feature = "core_float", issue = "32110")] macro_rules! f32_core_methods { () => { /// Returns `true` if this value is `NaN` and false otherwise. @@ -553,7 +552,6 @@ macro_rules! f32_core_methods { () => { #[lang = "f32"] #[cfg(not(test))] -#[cfg(not(stage0))] impl f32 { f32_core_methods!(); } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 801de5e87bd..f128c55c78a 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -19,7 +19,7 @@ use mem; use num::Float; -#[cfg(not(stage0))] use num::FpCategory; +use num::FpCategory; use num::FpCategory as Fp; /// The radix or base of the internal representation of `f64`. @@ -276,7 +276,6 @@ impl Float for f64 { // FIXME: remove (inline) this macro and the Float trait // when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] #[unstable(feature = "core_float", issue = "32110")] macro_rules! f64_core_methods { () => { /// Returns `true` if this value is `NaN` and false otherwise. @@ -562,7 +561,6 @@ macro_rules! f64_core_methods { () => { #[lang = "f64"] #[cfg(not(test))] -#[cfg(not(stage0))] impl f64 { f64_core_methods!(); } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 6df8ca98ba9..58d45b107f1 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -422,7 +422,6 @@ $EndFeature, " /// assert_eq!(m, -22016); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { (self as $UnsignedT).reverse_bits() as Self @@ -2194,7 +2193,6 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 43520); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { unsafe { intrinsics::bitreverse(self as $ActualT) as Self } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 697e6a3efde..1f84631ada3 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -335,18 +335,8 @@ pub struct RangeInclusive { // but it is known that LLVM is not able to optimize loops following that RFC. // Consider adding an extra `bool` field to indicate emptiness of the range. // See #45222 for performance test cases. - #[cfg(not(stage0))] pub(crate) start: Idx, - #[cfg(not(stage0))] pub(crate) end: Idx, - /// The lower bound of the range (inclusive). - #[cfg(stage0)] - #[unstable(feature = "inclusive_range_fields", issue = "49022")] - pub start: Idx, - /// The upper bound of the range (inclusive). - #[cfg(stage0)] - #[unstable(feature = "inclusive_range_fields", issue = "49022")] - pub end: Idx, } impl RangeInclusive { diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 8212648f2d8..45f629a6442 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -54,13 +54,3 @@ pub use option::Option::{self, Some, None}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use result::Result::{self, Ok, Err}; - -// Re-exported extension traits for primitive types -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -#[cfg(stage0)] -pub use slice::SliceExt; -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -#[cfg(stage0)] -pub use str::StrExt; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 93ebc23ac0b..82891b691dc 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -68,181 +68,6 @@ struct Repr { // Extension traits // -public_in_stage0! { -{ -/// Extension methods for slices. -#[unstable(feature = "core_slice_ext", - reason = "stable interface provided by `impl [T]` in later crates", - issue = "32110")] -#[allow(missing_docs)] // documented elsewhere -} -trait SliceExt { - type Item; - - #[stable(feature = "core", since = "1.6.0")] - fn split_at(&self, mid: usize) -> (&[Self::Item], &[Self::Item]); - - #[stable(feature = "core", since = "1.6.0")] - fn iter(&self) -> Iter; - - #[stable(feature = "core", since = "1.6.0")] - fn split

    (&self, pred: P) -> Split - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "slice_rsplit", since = "1.27.0")] - fn rsplit

    (&self, pred: P) -> RSplit - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn splitn

    (&self, n: usize, pred: P) -> SplitN - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn

    (&self, n: usize, pred: P) -> RSplitN - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn windows(&self, size: usize) -> Windows; - - #[stable(feature = "core", since = "1.6.0")] - fn chunks(&self, size: usize) -> Chunks; - - #[unstable(feature = "exact_chunks", issue = "47115")] - fn exact_chunks(&self, size: usize) -> ExactChunks; - - #[stable(feature = "core", since = "1.6.0")] - fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn first(&self) -> Option<&Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_first(&self) -> Option<(&Self::Item, &[Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_last(&self) -> Option<(&Self::Item, &[Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn last(&self) -> Option<&Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn as_ptr(&self) -> *const Self::Item; - - #[stable(feature = "core", since = "1.6.0")] - fn binary_search(&self, x: &Self::Item) -> Result - where Self::Item: Ord; - - #[stable(feature = "core", since = "1.6.0")] - fn binary_search_by<'a, F>(&'a self, f: F) -> Result - where F: FnMut(&'a Self::Item) -> Ordering; - - #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] - fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result - where F: FnMut(&'a Self::Item) -> B, - B: Ord; - - #[stable(feature = "core", since = "1.6.0")] - fn len(&self) -> usize; - - #[stable(feature = "core", since = "1.6.0")] - fn is_empty(&self) -> bool { self.len() == 0 } - - #[stable(feature = "core", since = "1.6.0")] - fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn iter_mut(&mut self) -> IterMut; - - #[stable(feature = "core", since = "1.6.0")] - fn first_mut(&mut self) -> Option<&mut Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_first_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_last_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn last_mut(&mut self) -> Option<&mut Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_mut

    (&mut self, pred: P) -> SplitMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "slice_rsplit", since = "1.27.0")] - fn rsplit_mut

    (&mut self, pred: P) -> RSplitMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn splitn_mut

    (&mut self, n: usize, pred: P) -> SplitNMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn_mut

    (&mut self, n: usize, pred: P) -> RSplitNMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut; - - #[unstable(feature = "exact_chunks", issue = "47115")] - fn exact_chunks_mut(&mut self, size: usize) -> ExactChunksMut; - - #[stable(feature = "core", since = "1.6.0")] - fn swap(&mut self, a: usize, b: usize); - - #[stable(feature = "core", since = "1.6.0")] - fn split_at_mut(&mut self, mid: usize) -> (&mut [Self::Item], &mut [Self::Item]); - - #[stable(feature = "core", since = "1.6.0")] - fn reverse(&mut self); - - #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn as_mut_ptr(&mut self) -> *mut Self::Item; - - #[stable(feature = "core", since = "1.6.0")] - fn contains(&self, x: &Self::Item) -> bool where Self::Item: PartialEq; - - #[stable(feature = "core", since = "1.6.0")] - fn starts_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - #[stable(feature = "core", since = "1.6.0")] - fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - #[stable(feature = "slice_rotate", since = "1.26.0")] - fn rotate_left(&mut self, mid: usize); - - #[stable(feature = "slice_rotate", since = "1.26.0")] - fn rotate_right(&mut self, k: usize); - - #[stable(feature = "clone_from_slice", since = "1.7.0")] - fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone; - - #[stable(feature = "copy_from_slice", since = "1.9.0")] - fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; - - #[stable(feature = "swap_with_slice", since = "1.27.0")] - fn swap_with_slice(&mut self, src: &mut [Self::Item]); - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable(&mut self) - where Self::Item: Ord; - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable_by(&mut self, compare: F) - where F: FnMut(&Self::Item, &Self::Item) -> Ordering; - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable_by_key(&mut self, f: F) - where F: FnMut(&Self::Item) -> B, - B: Ord; -}} - // Use macros to be generic over const/mut macro_rules! slice_offset { ($ptr:expr, $by:expr) => {{ @@ -281,488 +106,9 @@ macro_rules! make_ref_mut { }}; } -#[unstable(feature = "core_slice_ext", - reason = "stable interface provided by `impl [T]` in later crates", - issue = "32110")] -impl SliceExt for [T] { - type Item = T; - - #[inline] - fn split_at(&self, mid: usize) -> (&[T], &[T]) { - (&self[..mid], &self[mid..]) - } - - #[inline] - fn iter(&self) -> Iter { - unsafe { - let p = if mem::size_of::() == 0 { - 1 as *const _ - } else { - let p = self.as_ptr(); - assume(!p.is_null()); - p - }; - - Iter { - ptr: p, - end: slice_offset!(p, self.len() as isize), - _marker: marker::PhantomData - } - } - } - - #[inline] - fn split

    (&self, pred: P) -> Split - where P: FnMut(&T) -> bool - { - Split { - v: self, - pred, - finished: false - } - } - - #[inline] - fn rsplit

    (&self, pred: P) -> RSplit - where P: FnMut(&T) -> bool - { - RSplit { inner: self.split(pred) } - } - - #[inline] - fn splitn

    (&self, n: usize, pred: P) -> SplitN - where P: FnMut(&T) -> bool - { - SplitN { - inner: GenericSplitN { - iter: self.split(pred), - count: n - } - } - } - - #[inline] - fn rsplitn

    (&self, n: usize, pred: P) -> RSplitN - where P: FnMut(&T) -> bool - { - RSplitN { - inner: GenericSplitN { - iter: self.rsplit(pred), - count: n - } - } - } - - #[inline] - fn windows(&self, size: usize) -> Windows { - assert!(size != 0); - Windows { v: self, size: size } - } - - #[inline] - fn chunks(&self, chunk_size: usize) -> Chunks { - assert!(chunk_size != 0); - Chunks { v: self, chunk_size: chunk_size } - } - - #[inline] - fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - ExactChunks { v: &self[..len], chunk_size: chunk_size} - } - - #[inline] - fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex<[T]> - { - index.get(self) - } - - #[inline] - fn first(&self) -> Option<&T> { - if self.is_empty() { None } else { Some(&self[0]) } - } - - #[inline] - fn split_first(&self) -> Option<(&T, &[T])> { - if self.is_empty() { None } else { Some((&self[0], &self[1..])) } - } - - #[inline] - fn split_last(&self) -> Option<(&T, &[T])> { - let len = self.len(); - if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } - } - - #[inline] - fn last(&self) -> Option<&T> { - if self.is_empty() { None } else { Some(&self[self.len() - 1]) } - } - - #[inline] - unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex<[T]> - { - index.get_unchecked(self) - } - - #[inline] - fn as_ptr(&self) -> *const T { - self as *const [T] as *const T - } - - fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result - where F: FnMut(&'a T) -> Ordering - { - let s = self; - let mut size = s.len(); - if size == 0 { - return Err(0); - } - let mut base = 0usize; - while size > 1 { - let half = size / 2; - let mid = base + half; - // mid is always in [0, size), that means mid is >= 0 and < size. - // mid >= 0: by definition - // mid < size: mid = size / 2 + size / 4 + size / 8 ... - let cmp = f(unsafe { s.get_unchecked(mid) }); - base = if cmp == Greater { base } else { mid }; - size -= half; - } - // base is always in [0, size) because base <= mid. - let cmp = f(unsafe { s.get_unchecked(base) }); - if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) } - } - - #[inline] - fn len(&self) -> usize { - unsafe { - mem::transmute::<&[T], Repr>(self).len - } - } - - #[inline] - fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex<[T]> - { - index.get_mut(self) - } - - #[inline] - fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - let len = self.len(); - let ptr = self.as_mut_ptr(); - - unsafe { - assert!(mid <= len); - - (from_raw_parts_mut(ptr, mid), - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - } - } - - #[inline] - fn iter_mut(&mut self) -> IterMut { - unsafe { - let p = if mem::size_of::() == 0 { - 1 as *mut _ - } else { - let p = self.as_mut_ptr(); - assume(!p.is_null()); - p - }; - - IterMut { - ptr: p, - end: slice_offset!(p, self.len() as isize), - _marker: marker::PhantomData - } - } - } - - #[inline] - fn last_mut(&mut self) -> Option<&mut T> { - let len = self.len(); - if len == 0 { return None; } - Some(&mut self[len - 1]) - } - - #[inline] - fn first_mut(&mut self) -> Option<&mut T> { - if self.is_empty() { None } else { Some(&mut self[0]) } - } - - #[inline] - fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - if self.is_empty() { None } else { - let split = self.split_at_mut(1); - Some((&mut split.0[0], split.1)) - } - } - - #[inline] - fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - let len = self.len(); - if len == 0 { None } else { - let split = self.split_at_mut(len - 1); - Some((&mut split.1[0], split.0)) - } - } - - #[inline] - fn split_mut

    (&mut self, pred: P) -> SplitMut - where P: FnMut(&T) -> bool - { - SplitMut { v: self, pred: pred, finished: false } - } - - #[inline] - fn rsplit_mut

    (&mut self, pred: P) -> RSplitMut - where P: FnMut(&T) -> bool - { - RSplitMut { inner: self.split_mut(pred) } - } - - #[inline] - fn splitn_mut

    (&mut self, n: usize, pred: P) -> SplitNMut - where P: FnMut(&T) -> bool - { - SplitNMut { - inner: GenericSplitN { - iter: self.split_mut(pred), - count: n - } - } - } - - #[inline] - fn rsplitn_mut

    (&mut self, n: usize, pred: P) -> RSplitNMut where - P: FnMut(&T) -> bool, - { - RSplitNMut { - inner: GenericSplitN { - iter: self.rsplit_mut(pred), - count: n - } - } - } - - #[inline] - fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { - assert!(chunk_size != 0); - ChunksMut { v: self, chunk_size: chunk_size } - } - - #[inline] - fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { - assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size} - } - - #[inline] - fn swap(&mut self, a: usize, b: usize) { - unsafe { - // Can't take two mutable loans from one vector, so instead just cast - // them to their raw pointers to do the swap - let pa: *mut T = &mut self[a]; - let pb: *mut T = &mut self[b]; - ptr::swap(pa, pb); - } - } - - fn reverse(&mut self) { - let mut i: usize = 0; - let ln = self.len(); - - // For very small types, all the individual reads in the normal - // path perform poorly. We can do better, given efficient unaligned - // load/store, by loading a larger chunk and reversing a register. - - // Ideally LLVM would do this for us, as it knows better than we do - // whether unaligned reads are efficient (since that changes between - // different ARM versions, for example) and what the best chunk size - // would be. Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls - // the loop, so we need to do this ourselves. (Hypothesis: reverse - // is troublesome because the sides can be aligned differently -- - // will be, when the length is odd -- so there's no way of emitting - // pre- and postludes to use fully-aligned SIMD in the middle.) - - let fast_unaligned = - cfg!(any(target_arch = "x86", target_arch = "x86_64")); - - if fast_unaligned && mem::size_of::() == 1 { - // Use the llvm.bswap intrinsic to reverse u8s in a usize - let chunk = mem::size_of::(); - while i + chunk - 1 < ln / 2 { - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); - let va = ptr::read_unaligned(pa as *mut usize); - let vb = ptr::read_unaligned(pb as *mut usize); - ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); - ptr::write_unaligned(pb as *mut usize, va.swap_bytes()); - } - i += chunk; - } - } - - if fast_unaligned && mem::size_of::() == 2 { - // Use rotate-by-16 to reverse u16s in a u32 - let chunk = mem::size_of::() / 2; - while i + chunk - 1 < ln / 2 { - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); - let va = ptr::read_unaligned(pa as *mut u32); - let vb = ptr::read_unaligned(pb as *mut u32); - ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); - ptr::write_unaligned(pb as *mut u32, va.rotate_left(16)); - } - i += chunk; - } - } - - while i < ln / 2 { - // Unsafe swap to avoid the bounds check in safe swap. - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - 1); - ptr::swap(pa, pb); - } - i += 1; - } - } - - #[inline] - unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex<[T]> - { - index.get_unchecked_mut(self) - } - - #[inline] - fn as_mut_ptr(&mut self) -> *mut T { - self as *mut [T] as *mut T - } - - #[inline] - fn contains(&self, x: &T) -> bool where T: PartialEq { - x.slice_contains(self) - } - - #[inline] - fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq { - let n = needle.len(); - self.len() >= n && needle == &self[..n] - } - - #[inline] - fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq { - let (m, n) = (self.len(), needle.len()); - m >= n && needle == &self[m-n..] - } - - fn binary_search(&self, x: &T) -> Result - where T: Ord - { - self.binary_search_by(|p| p.cmp(x)) - } - - fn rotate_left(&mut self, mid: usize) { - assert!(mid <= self.len()); - let k = self.len() - mid; - - unsafe { - let p = self.as_mut_ptr(); - rotate::ptr_rotate(mid, p.offset(mid as isize), k); - } - } - - fn rotate_right(&mut self, k: usize) { - assert!(k <= self.len()); - let mid = self.len() - k; - - unsafe { - let p = self.as_mut_ptr(); - rotate::ptr_rotate(mid, p.offset(mid as isize), k); - } - } - - #[inline] - fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - // NOTE: We need to explicitly slice them to the same length - // for bounds checking to be elided, and the optimizer will - // generate memcpy for simple cases (for example T = u8). - let len = self.len(); - let src = &src[..len]; - for i in 0..len { - self[i].clone_from(&src[i]); - } - } - - #[inline] - fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - unsafe { - ptr::copy_nonoverlapping( - src.as_ptr(), self.as_mut_ptr(), self.len()); - } - } - - #[inline] - fn swap_with_slice(&mut self, src: &mut [T]) { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - unsafe { - ptr::swap_nonoverlapping( - self.as_mut_ptr(), src.as_mut_ptr(), self.len()); - } - } - - #[inline] - fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result - where F: FnMut(&'a Self::Item) -> B, - B: Ord - { - self.binary_search_by(|k| f(k).cmp(b)) - } - - #[inline] - fn sort_unstable(&mut self) - where Self::Item: Ord - { - sort::quicksort(self, |a, b| a.lt(b)); - } - - #[inline] - fn sort_unstable_by(&mut self, mut compare: F) - where F: FnMut(&Self::Item, &Self::Item) -> Ordering - { - sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); - } - - #[inline] - fn sort_unstable_by_key(&mut self, mut f: F) - where F: FnMut(&Self::Item) -> B, - B: Ord - { - sort::quicksort(self, |a, b| f(a).lt(&f(b))); - } -} - -// FIXME: remove (inline) this macro and the SliceExt trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_slice_ext", issue = "32110")] -macro_rules! slice_core_methods { () => { +#[lang = "slice"] +#[cfg(not(test))] +impl [T] { /// Returns the number of elements in the slice. /// /// # Examples @@ -774,7 +120,9 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len(&self) -> usize { - SliceExt::len(self) + unsafe { + mem::transmute::<&[T], Repr>(self).len + } } /// Returns `true` if the slice has a length of 0. @@ -788,7 +136,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_empty(&self) -> bool { - SliceExt::is_empty(self) + self.len() == 0 } /// Returns the first element of the slice, or `None` if it is empty. @@ -805,7 +153,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn first(&self) -> Option<&T> { - SliceExt::first(self) + if self.is_empty() { None } else { Some(&self[0]) } } /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. @@ -823,7 +171,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn first_mut(&mut self) -> Option<&mut T> { - SliceExt::first_mut(self) + if self.is_empty() { None } else { Some(&mut self[0]) } } /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. @@ -841,7 +189,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first(&self) -> Option<(&T, &[T])> { - SliceExt::split_first(self) + if self.is_empty() { None } else { Some((&self[0], &self[1..])) } } /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. @@ -861,7 +209,10 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - SliceExt::split_first_mut(self) + if self.is_empty() { None } else { + let split = self.split_at_mut(1); + Some((&mut split.0[0], split.1)) + } } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. @@ -879,7 +230,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last(&self) -> Option<(&T, &[T])> { - SliceExt::split_last(self) + let len = self.len(); + if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. @@ -899,7 +251,12 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - SliceExt::split_last_mut(self) + let len = self.len(); + if len == 0 { None } else { + let split = self.split_at_mut(len - 1); + Some((&mut split.1[0], split.0)) + } + } /// Returns the last element of the slice, or `None` if it is empty. @@ -916,7 +273,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn last(&self) -> Option<&T> { - SliceExt::last(self) + if self.is_empty() { None } else { Some(&self[self.len() - 1]) } } /// Returns a mutable pointer to the last item in the slice. @@ -934,7 +291,9 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn last_mut(&mut self) -> Option<&mut T> { - SliceExt::last_mut(self) + let len = self.len(); + if len == 0 { return None; } + Some(&mut self[len - 1]) } /// Returns a reference to an element or subslice depending on the type of @@ -959,7 +318,7 @@ macro_rules! slice_core_methods { () => { pub fn get(&self, index: I) -> Option<&I::Output> where I: SliceIndex { - SliceExt::get(self, index) + index.get(self) } /// Returns a mutable reference to an element or subslice depending on the @@ -982,7 +341,7 @@ macro_rules! slice_core_methods { () => { pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where I: SliceIndex { - SliceExt::get_mut(self, index) + index.get_mut(self) } /// Returns a reference to an element or subslice, without doing bounds @@ -1007,7 +366,7 @@ macro_rules! slice_core_methods { () => { pub unsafe fn get_unchecked(&self, index: I) -> &I::Output where I: SliceIndex { - SliceExt::get_unchecked(self, index) + index.get_unchecked(self) } /// Returns a mutable reference to an element or subslice, without doing @@ -1034,7 +393,7 @@ macro_rules! slice_core_methods { () => { pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where I: SliceIndex { - SliceExt::get_unchecked_mut(self, index) + index.get_unchecked_mut(self) } /// Returns a raw pointer to the slice's buffer. @@ -1060,7 +419,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn as_ptr(&self) -> *const T { - SliceExt::as_ptr(self) + self as *const [T] as *const T } /// Returns an unsafe mutable pointer to the slice's buffer. @@ -1087,7 +446,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn as_mut_ptr(&mut self) -> *mut T { - SliceExt::as_mut_ptr(self) + self as *mut [T] as *mut T } /// Swaps two elements in the slice. @@ -1111,7 +470,13 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap(&mut self, a: usize, b: usize) { - SliceExt::swap(self, a, b) + unsafe { + // Can't take two mutable loans from one vector, so instead just cast + // them to their raw pointers to do the swap + let pa: *mut T = &mut self[a]; + let pb: *mut T = &mut self[b]; + ptr::swap(pa, pb); + } } /// Reverses the order of elements in the slice, in place. @@ -1126,7 +491,66 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn reverse(&mut self) { - SliceExt::reverse(self) + let mut i: usize = 0; + let ln = self.len(); + + // For very small types, all the individual reads in the normal + // path perform poorly. We can do better, given efficient unaligned + // load/store, by loading a larger chunk and reversing a register. + + // Ideally LLVM would do this for us, as it knows better than we do + // whether unaligned reads are efficient (since that changes between + // different ARM versions, for example) and what the best chunk size + // would be. Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls + // the loop, so we need to do this ourselves. (Hypothesis: reverse + // is troublesome because the sides can be aligned differently -- + // will be, when the length is odd -- so there's no way of emitting + // pre- and postludes to use fully-aligned SIMD in the middle.) + + let fast_unaligned = + cfg!(any(target_arch = "x86", target_arch = "x86_64")); + + if fast_unaligned && mem::size_of::() == 1 { + // Use the llvm.bswap intrinsic to reverse u8s in a usize + let chunk = mem::size_of::(); + while i + chunk - 1 < ln / 2 { + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let va = ptr::read_unaligned(pa as *mut usize); + let vb = ptr::read_unaligned(pb as *mut usize); + ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); + ptr::write_unaligned(pb as *mut usize, va.swap_bytes()); + } + i += chunk; + } + } + + if fast_unaligned && mem::size_of::() == 2 { + // Use rotate-by-16 to reverse u16s in a u32 + let chunk = mem::size_of::() / 2; + while i + chunk - 1 < ln / 2 { + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let va = ptr::read_unaligned(pa as *mut u32); + let vb = ptr::read_unaligned(pb as *mut u32); + ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); + ptr::write_unaligned(pb as *mut u32, va.rotate_left(16)); + } + i += chunk; + } + } + + while i < ln / 2 { + // Unsafe swap to avoid the bounds check in safe swap. + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - 1); + ptr::swap(pa, pb); + } + i += 1; + } } /// Returns an iterator over the slice. @@ -1145,7 +569,21 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter(&self) -> Iter { - SliceExt::iter(self) + unsafe { + let p = if mem::size_of::() == 0 { + 1 as *const _ + } else { + let p = self.as_ptr(); + assume(!p.is_null()); + p + }; + + Iter { + ptr: p, + end: slice_offset!(p, self.len() as isize), + _marker: marker::PhantomData + } + } } /// Returns an iterator that allows modifying each value. @@ -1162,7 +600,21 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter_mut(&mut self) -> IterMut { - SliceExt::iter_mut(self) + unsafe { + let p = if mem::size_of::() == 0 { + 1 as *mut _ + } else { + let p = self.as_mut_ptr(); + assume(!p.is_null()); + p + }; + + IterMut { + ptr: p, + end: slice_offset!(p, self.len() as isize), + _marker: marker::PhantomData + } + } } /// Returns an iterator over all contiguous windows of length @@ -1194,7 +646,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn windows(&self, size: usize) -> Windows { - SliceExt::windows(self, size) + assert!(size != 0); + Windows { v: self, size: size } } /// Returns an iterator over `chunk_size` elements of the slice at a @@ -1224,7 +677,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks(&self, chunk_size: usize) -> Chunks { - SliceExt::chunks(self, chunk_size) + assert!(chunk_size != 0); + Chunks { v: self, chunk_size: chunk_size } } /// Returns an iterator over `chunk_size` elements of the slice at a @@ -1256,7 +710,10 @@ macro_rules! slice_core_methods { () => { #[unstable(feature = "exact_chunks", issue = "47115")] #[inline] pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - SliceExt::exact_chunks(self, chunk_size) + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let len = self.len() - rem; + ExactChunks { v: &self[..len], chunk_size: chunk_size} } /// Returns an iterator over `chunk_size` elements of the slice at a time. @@ -1290,7 +747,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { - SliceExt::chunks_mut(self, chunk_size) + assert!(chunk_size != 0); + ChunksMut { v: self, chunk_size: chunk_size } } /// Returns an iterator over `chunk_size` elements of the slice at a time. @@ -1328,7 +786,10 @@ macro_rules! slice_core_methods { () => { #[unstable(feature = "exact_chunks", issue = "47115")] #[inline] pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { - SliceExt::exact_chunks_mut(self, chunk_size) + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let len = self.len() - rem; + ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size} } /// Divides one slice into two at an index. @@ -1367,7 +828,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { - SliceExt::split_at(self, mid) + (&self[..mid], &self[mid..]) } /// Divides one mutable slice into two at an index. @@ -1397,7 +858,15 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - SliceExt::split_at_mut(self, mid) + let len = self.len(); + let ptr = self.as_mut_ptr(); + + unsafe { + assert!(mid <= len); + + (from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + } } /// Returns an iterator over subslices separated by elements that match @@ -1445,7 +914,11 @@ macro_rules! slice_core_methods { () => { pub fn split(&self, pred: F) -> Split where F: FnMut(&T) -> bool { - SliceExt::split(self, pred) + Split { + v: self, + pred, + finished: false + } } /// Returns an iterator over mutable subslices separated by elements that @@ -1466,7 +939,7 @@ macro_rules! slice_core_methods { () => { pub fn split_mut(&mut self, pred: F) -> SplitMut where F: FnMut(&T) -> bool { - SliceExt::split_mut(self, pred) + SplitMut { v: self, pred: pred, finished: false } } /// Returns an iterator over subslices separated by elements that match @@ -1501,7 +974,7 @@ macro_rules! slice_core_methods { () => { pub fn rsplit(&self, pred: F) -> RSplit where F: FnMut(&T) -> bool { - SliceExt::rsplit(self, pred) + RSplit { inner: self.split(pred) } } /// Returns an iterator over mutable subslices separated by elements that @@ -1526,7 +999,7 @@ macro_rules! slice_core_methods { () => { pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut where F: FnMut(&T) -> bool { - SliceExt::rsplit_mut(self, pred) + RSplitMut { inner: self.split_mut(pred) } } /// Returns an iterator over subslices separated by elements that match @@ -1553,7 +1026,12 @@ macro_rules! slice_core_methods { () => { pub fn splitn(&self, n: usize, pred: F) -> SplitN where F: FnMut(&T) -> bool { - SliceExt::splitn(self, n, pred) + SplitN { + inner: GenericSplitN { + iter: self.split(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1578,7 +1056,12 @@ macro_rules! slice_core_methods { () => { pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut where F: FnMut(&T) -> bool { - SliceExt::splitn_mut(self, n, pred) + SplitNMut { + inner: GenericSplitN { + iter: self.split_mut(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1606,7 +1089,12 @@ macro_rules! slice_core_methods { () => { pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN where F: FnMut(&T) -> bool { - SliceExt::rsplitn(self, n, pred) + RSplitN { + inner: GenericSplitN { + iter: self.rsplit(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1632,7 +1120,12 @@ macro_rules! slice_core_methods { () => { pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut where F: FnMut(&T) -> bool { - SliceExt::rsplitn_mut(self, n, pred) + RSplitNMut { + inner: GenericSplitN { + iter: self.rsplit_mut(pred), + count: n + } + } } /// Returns `true` if the slice contains an element with the given value. @@ -1648,7 +1141,7 @@ macro_rules! slice_core_methods { () => { pub fn contains(&self, x: &T) -> bool where T: PartialEq { - SliceExt::contains(self, x) + x.slice_contains(self) } /// Returns `true` if `needle` is a prefix of the slice. @@ -1675,7 +1168,8 @@ macro_rules! slice_core_methods { () => { pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq { - SliceExt::starts_with(self, needle) + let n = needle.len(); + self.len() >= n && needle == &self[..n] } /// Returns `true` if `needle` is a suffix of the slice. @@ -1702,7 +1196,8 @@ macro_rules! slice_core_methods { () => { pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq { - SliceExt::ends_with(self, needle) + let (m, n) = (self.len(), needle.len()); + m >= n && needle == &self[m-n..] } /// Binary searches this sorted slice for a given element. @@ -1731,7 +1226,7 @@ macro_rules! slice_core_methods { () => { pub fn binary_search(&self, x: &T) -> Result where T: Ord { - SliceExt::binary_search(self, x) + self.binary_search_by(|p| p.cmp(x)) } /// Binary searches this sorted slice with a comparator function. @@ -1767,10 +1262,29 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result where F: FnMut(&'a T) -> Ordering { - SliceExt::binary_search_by(self, f) + let s = self; + let mut size = s.len(); + if size == 0 { + return Err(0); + } + let mut base = 0usize; + while size > 1 { + let half = size / 2; + let mid = base + half; + // mid is always in [0, size), that means mid is >= 0 and < size. + // mid >= 0: by definition + // mid < size: mid = size / 2 + size / 4 + size / 8 ... + let cmp = f(unsafe { s.get_unchecked(mid) }); + base = if cmp == Greater { base } else { mid }; + size -= half; + } + // base is always in [0, size) because base <= mid. + let cmp = f(unsafe { s.get_unchecked(base) }); + if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) } + } /// Binary searches this sorted slice with a key extraction function. @@ -1805,11 +1319,11 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] - pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result where F: FnMut(&'a T) -> B, B: Ord { - SliceExt::binary_search_by_key(self, b, f) + self.binary_search_by(|k| f(k).cmp(b)) } /// Sorts the slice, but may not preserve the order of equal elements. @@ -1843,7 +1357,7 @@ macro_rules! slice_core_methods { () => { pub fn sort_unstable(&mut self) where T: Ord { - SliceExt::sort_unstable(self); + sort::quicksort(self, |a, b| a.lt(b)); } /// Sorts the slice with a comparator function, but may not preserve the order of equal @@ -1878,10 +1392,10 @@ macro_rules! slice_core_methods { () => { /// [pdqsort]: https://github.com/orlp/pdqsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] - pub fn sort_unstable_by(&mut self, compare: F) + pub fn sort_unstable_by(&mut self, mut compare: F) where F: FnMut(&T, &T) -> Ordering { - SliceExt::sort_unstable_by(self, compare); + sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); } /// Sorts the slice with a key extraction function, but may not preserve the order of equal @@ -1910,10 +1424,10 @@ macro_rules! slice_core_methods { () => { /// [pdqsort]: https://github.com/orlp/pdqsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] - pub fn sort_unstable_by_key(&mut self, f: F) + pub fn sort_unstable_by_key(&mut self, mut f: F) where F: FnMut(&T) -> K, K: Ord { - SliceExt::sort_unstable_by_key(self, f); + sort::quicksort(self, |a, b| f(a).lt(&f(b))); } /// Rotates the slice in-place such that the first `mid` elements of the @@ -1948,7 +1462,13 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_left(&mut self, mid: usize) { - SliceExt::rotate_left(self, mid); + assert!(mid <= self.len()); + let k = self.len() - mid; + + unsafe { + let p = self.as_mut_ptr(); + rotate::ptr_rotate(mid, p.offset(mid as isize), k); + } } /// Rotates the slice in-place such that the first `self.len() - k` @@ -1983,7 +1503,13 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_right(&mut self, k: usize) { - SliceExt::rotate_right(self, k); + assert!(k <= self.len()); + let mid = self.len() - k; + + unsafe { + let p = self.as_mut_ptr(); + rotate::ptr_rotate(mid, p.offset(mid as isize), k); + } } /// Copies the elements from `src` into `self`. @@ -2040,7 +1566,17 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "clone_from_slice", since = "1.7.0")] pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - SliceExt::clone_from_slice(self, src) + assert!(self.len() == src.len(), + "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // for bounds checking to be elided, and the optimizer will + // generate memcpy for simple cases (for example T = u8). + let len = self.len(); + let src = &src[..len]; + for i in 0..len { + self[i].clone_from(&src[i]); + } + } /// Copies all elements from `src` into `self`, using a memcpy. @@ -2096,7 +1632,12 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "copy_from_slice", since = "1.9.0")] pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - SliceExt::copy_from_slice(self, src) + assert!(self.len() == src.len(), + "destination and source slices have different lengths"); + unsafe { + ptr::copy_nonoverlapping( + src.as_ptr(), self.as_mut_ptr(), self.len()); + } } /// Swaps all elements in `self` with those in `other`. @@ -2148,22 +1689,18 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "swap_with_slice", since = "1.27.0")] pub fn swap_with_slice(&mut self, other: &mut [T]) { - SliceExt::swap_with_slice(self, other) + assert!(self.len() == other.len(), + "destination and source slices have different lengths"); + unsafe { + ptr::swap_nonoverlapping( + self.as_mut_ptr(), other.as_mut_ptr(), self.len()); + } } -}} - -#[lang = "slice"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl [T] { - slice_core_methods!(); } -// FIXME: remove (inline) this macro -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_slice_ext", issue = "32110")] -macro_rules! slice_u8_core_methods { () => { +#[lang = "slice_u8"] +#[cfg(not(test))] +impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] @@ -2217,13 +1754,7 @@ macro_rules! slice_u8_core_methods { () => { byte.make_ascii_lowercase(); } } -}} -#[lang = "slice_u8"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl [u8] { - slice_u8_core_methods!(); } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index df7b2f25a86..82bead0ab46 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2097,119 +2097,7 @@ mod traits { (..self.end+1).index_mut(slice) } } - -} - -public_in_stage0! { -{ -/// Methods for string slices -#[allow(missing_docs)] -#[doc(hidden)] -#[unstable(feature = "core_str_ext", - reason = "stable interface provided by `impl str` in later crates", - issue = "32110")] } -trait StrExt { - // NB there are no docs here are they're all located on the StrExt trait in - // liballoc, not here. - - #[stable(feature = "core", since = "1.6.0")] - fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn chars(&self) -> Chars; - #[stable(feature = "core", since = "1.6.0")] - fn bytes(&self) -> Bytes; - #[stable(feature = "core", since = "1.6.0")] - fn char_indices(&self) -> CharIndices; - #[stable(feature = "core", since = "1.6.0")] - fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn lines(&self) -> Lines; - #[stable(feature = "core", since = "1.6.0")] - #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] - #[allow(deprecated)] - fn lines_any(&self) -> LinesAny; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - fn get>(&self, i: I) -> Option<&I::Output>; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe fn get_unchecked>(&self, i: I) -> &I::Output; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output; - #[stable(feature = "core", since = "1.6.0")] - unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; - #[stable(feature = "core", since = "1.6.0")] - unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str; - #[stable(feature = "core", since = "1.6.0")] - fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str; - #[stable(feature = "core", since = "1.6.0")] - fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "is_char_boundary", since = "1.9.0")] - fn is_char_boundary(&self, index: usize) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn as_bytes(&self) -> &[u8]; - #[stable(feature = "str_mut_extras", since = "1.20.0")] - unsafe fn as_bytes_mut(&mut self) -> &mut [u8]; - #[stable(feature = "core", since = "1.6.0")] - fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a>; - fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn split_at(&self, mid: usize) -> (&str, &str); - #[stable(feature = "core", since = "1.6.0")] - fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str); - #[stable(feature = "core", since = "1.6.0")] - fn as_ptr(&self) -> *const u8; - #[stable(feature = "core", since = "1.6.0")] - fn len(&self) -> usize; - #[stable(feature = "core", since = "1.6.0")] - fn is_empty(&self) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn parse(&self) -> Result; - #[stable(feature = "split_whitespace", since = "1.1.0")] - fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim(&self) -> &str; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim_left(&self) -> &str; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim_right(&self) -> &str; -}} // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. @@ -2255,307 +2143,9 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { index, ch, char_range, s_trunc, ellipsis); } -#[stable(feature = "core", since = "1.6.0")] -impl StrExt for str { - #[inline] - fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - pat.is_contained_in(self) - } - - #[inline] - fn chars(&self) -> Chars { - Chars{iter: self.as_bytes().iter()} - } - - #[inline] - fn bytes(&self) -> Bytes { - Bytes(self.as_bytes().iter().cloned()) - } - - #[inline] - fn char_indices(&self) -> CharIndices { - CharIndices { front_offset: 0, iter: self.chars() } - } - - #[inline] - fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - Split(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_trailing_empty: true, - finished: false, - }) - } - - #[inline] - fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplit(self.split(pat).0) - } - - #[inline] - fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> { - SplitN(SplitNInternal { - iter: self.split(pat).0, - count, - }) - } - - #[inline] - fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplitN(self.splitn(count, pat).0) - } - - #[inline] - fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - SplitTerminator(SplitInternal { - allow_trailing_empty: false, - ..self.split(pat).0 - }) - } - - #[inline] - fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplitTerminator(self.split_terminator(pat).0) - } - - #[inline] - fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - Matches(MatchesInternal(pat.into_searcher(self))) - } - - #[inline] - fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RMatches(self.matches(pat).0) - } - - #[inline] - fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) - } - - #[inline] - fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RMatchIndices(self.match_indices(pat).0) - } - #[inline] - fn lines(&self) -> Lines { - Lines(self.split_terminator('\n').map(LinesAnyMap)) - } - - #[inline] - #[allow(deprecated)] - fn lines_any(&self) -> LinesAny { - LinesAny(self.lines()) - } - - #[inline] - fn get>(&self, i: I) -> Option<&I::Output> { - i.get(self) - } - - #[inline] - fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { - i.get_mut(self) - } - - #[inline] - unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - i.get_unchecked(self) - } - - #[inline] - unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - i.get_unchecked_mut(self) - } - - #[inline] - unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - (begin..end).get_unchecked(self) - } - - #[inline] - unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - (begin..end).get_unchecked_mut(self) - } - - #[inline] - fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - pat.is_prefix_of(self) - } - - #[inline] - fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a> - { - pat.is_suffix_of(self) - } - - #[inline] - fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a> - { - let mut i = 0; - let mut j = 0; - let mut matcher = pat.into_searcher(self); - if let Some((a, b)) = matcher.next_reject() { - i = a; - j = b; // Remember earliest known match, correct it below if - // last match is different - } - if let Some((_, b)) = matcher.next_reject_back() { - j = b; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(i, j) - } - } - - #[inline] - fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - let mut i = self.len(); - let mut matcher = pat.into_searcher(self); - if let Some((a, _)) = matcher.next_reject() { - i = a; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(i, self.len()) - } - } - - #[inline] - fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> - { - let mut j = 0; - let mut matcher = pat.into_searcher(self); - if let Some((_, b)) = matcher.next_reject_back() { - j = b; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(0, j) - } - } - - #[inline] - fn is_char_boundary(&self, index: usize) -> bool { - // 0 and len are always ok. - // Test for 0 explicitly so that it can optimize out the check - // easily and skip reading string data for that case. - if index == 0 || index == self.len() { return true; } - match self.as_bytes().get(index) { - None => false, - // This is bit magic equivalent to: b < 128 || b >= 192 - Some(&b) => (b as i8) >= -0x40, - } - } - - #[inline] - fn as_bytes(&self) -> &[u8] { - unsafe { &*(self as *const str as *const [u8]) } - } - - #[inline] - unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - &mut *(self as *mut str as *mut [u8]) - } - - fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - pat.into_searcher(self).next_match().map(|(i, _)| i) - } - - fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a> - { - pat.into_searcher(self).next_match_back().map(|(i, _)| i) - } - - fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - self.find(pat) - } - - #[inline] - fn split_at(&self, mid: usize) -> (&str, &str) { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(mid) { - unsafe { - (self.slice_unchecked(0, mid), - self.slice_unchecked(mid, self.len())) - } - } else { - slice_error_fail(self, 0, mid) - } - } - - fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(mid) { - let len = self.len(); - let ptr = self.as_ptr() as *mut u8; - unsafe { - (from_raw_parts_mut(ptr, mid), - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - } - } else { - slice_error_fail(self, 0, mid) - } - } - - #[inline] - fn as_ptr(&self) -> *const u8 { - self as *const str as *const u8 - } - - #[inline] - fn len(&self) -> usize { - self.as_bytes().len() - } - - #[inline] - fn is_empty(&self) -> bool { self.len() == 0 } - - #[inline] - fn parse(&self) -> Result { FromStr::from_str(self) } - - #[inline] - fn split_whitespace(&self) -> SplitWhitespace { - SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } - } - - #[inline] - fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_left(&self) -> &str { - self.trim_left_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_right(&self) -> &str { - self.trim_right_matches(|c: char| c.is_whitespace()) - } -} - -// FIXME: remove (inline) this macro and the SliceExt trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_str_ext", issue = "32110")] -macro_rules! str_core_methods { () => { +#[lang = "str"] +#[cfg(not(test))] +impl str { /// Returns the length of `self`. /// /// This length is in bytes, not [`char`]s or graphemes. In other words, @@ -2577,7 +2167,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len(&self) -> usize { - StrExt::len(self) + self.as_bytes().len() } /// Returns `true` if `self` has a length of zero bytes. @@ -2596,7 +2186,7 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { - StrExt::is_empty(self) + self.len() == 0 } /// Checks that `index`-th byte lies at the start and/or end of a @@ -2626,7 +2216,15 @@ macro_rules! str_core_methods { () => { #[stable(feature = "is_char_boundary", since = "1.9.0")] #[inline] pub fn is_char_boundary(&self, index: usize) -> bool { - StrExt::is_char_boundary(self, index) + // 0 and len are always ok. + // Test for 0 explicitly so that it can optimize out the check + // easily and skip reading string data for that case. + if index == 0 || index == self.len() { return true; } + match self.as_bytes().get(index) { + None => false, + // This is bit magic equivalent to: b < 128 || b >= 192 + Some(&b) => (b as i8) >= -0x40, + } } /// Converts a string slice to a byte slice. To convert the byte slice back @@ -2645,7 +2243,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline(always)] pub fn as_bytes(&self) -> &[u8] { - StrExt::as_bytes(self) + unsafe { &*(self as *const str as *const [u8]) } } /// Converts a mutable string slice to a mutable byte slice. To convert the @@ -2684,7 +2282,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_mut_extras", since = "1.20.0")] #[inline(always)] pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - StrExt::as_bytes_mut(self) + &mut *(self as *mut str as *mut [u8]) } /// Converts a string slice to a raw pointer. @@ -2706,7 +2304,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn as_ptr(&self) -> *const u8 { - StrExt::as_ptr(self) + self as *const str as *const u8 } /// Returns a subslice of `str`. @@ -2733,7 +2331,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub fn get>(&self, i: I) -> Option<&I::Output> { - StrExt::get(self, i) + i.get(self) } /// Returns a mutable subslice of `str`. @@ -2767,7 +2365,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { - StrExt::get_mut(self, i) + i.get_mut(self) } /// Returns a unchecked subslice of `str`. @@ -2799,7 +2397,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - StrExt::get_unchecked(self, i) + i.get_unchecked(self) } /// Returns a mutable, unchecked subslice of `str`. @@ -2831,7 +2429,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - StrExt::get_unchecked_mut(self, i) + i.get_unchecked_mut(self) } /// Creates a string slice from another string slice, bypassing safety @@ -2880,7 +2478,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - StrExt::slice_unchecked(self, begin, end) + (begin..end).get_unchecked(self) } /// Creates a string slice from another string slice, bypassing safety @@ -2910,7 +2508,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_slice_mut", since = "1.5.0")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - StrExt::slice_mut_unchecked(self, begin, end) + (begin..end).get_unchecked_mut(self) } /// Divide one string slice into two at an index. @@ -2946,7 +2544,15 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "str_split_at", since = "1.4.0")] pub fn split_at(&self, mid: usize) -> (&str, &str) { - StrExt::split_at(self, mid) + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + unsafe { + (self.slice_unchecked(0, mid), + self.slice_unchecked(mid, self.len())) + } + } else { + slice_error_fail(self, 0, mid) + } } /// Divide one mutable string slice into two at an index. @@ -2983,7 +2589,17 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "str_split_at", since = "1.4.0")] pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - StrExt::split_at_mut(self, mid) + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + let len = self.len(); + let ptr = self.as_ptr() as *mut u8; + unsafe { + (from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + } + } else { + slice_error_fail(self, 0, mid) + } } /// Returns an iterator over the [`char`]s of a string slice. @@ -3035,8 +2651,9 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chars(&self) -> Chars { - StrExt::chars(self) + Chars{iter: self.as_bytes().iter()} } + /// Returns an iterator over the [`char`]s of a string slice, and their /// positions. /// @@ -3091,7 +2708,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn char_indices(&self) -> CharIndices { - StrExt::char_indices(self) + CharIndices { front_offset: 0, iter: self.chars() } } /// An iterator over the bytes of a string slice. @@ -3116,7 +2733,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn bytes(&self) -> Bytes { - StrExt::bytes(self) + Bytes(self.as_bytes().iter().cloned()) } /// Split a string slice by whitespace. @@ -3156,7 +2773,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "split_whitespace", since = "1.1.0")] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace { - StrExt::split_whitespace(self) + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } } /// An iterator over the lines of a string, as string slices. @@ -3198,7 +2815,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn lines(&self) -> Lines { - StrExt::lines(self) + Lines(self.split_terminator('\n').map(LinesAnyMap)) } /// An iterator over the lines of a string. @@ -3207,7 +2824,7 @@ macro_rules! str_core_methods { () => { #[inline] #[allow(deprecated)] pub fn lines_any(&self) -> LinesAny { - StrExt::lines_any(self) + LinesAny(self.lines()) } /// Returns an iterator of `u16` over the string encoded as UTF-16. @@ -3226,7 +2843,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "encode_utf16", since = "1.8.0")] pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16::new(self) + EncodeUtf16 { chars: self.chars(), extra: 0 } } /// Returns `true` if the given pattern matches a sub-slice of @@ -3247,7 +2864,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - StrExt::contains(self, pat) + pat.is_contained_in(self) } /// Returns `true` if the given pattern matches a prefix of this @@ -3267,7 +2884,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - StrExt::starts_with(self, pat) + pat.is_prefix_of(self) } /// Returns `true` if the given pattern matches a suffix of this @@ -3289,7 +2906,7 @@ macro_rules! str_core_methods { () => { pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool where P::Searcher: ReverseSearcher<'a> { - StrExt::ends_with(self, pat) + pat.is_suffix_of(self) } /// Returns the byte index of the first character of this string slice that @@ -3337,7 +2954,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - StrExt::find(self, pat) + pat.into_searcher(self).next_match().map(|(i, _)| i) } /// Returns the byte index of the last character of this string slice that @@ -3384,7 +3001,7 @@ macro_rules! str_core_methods { () => { pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option where P::Searcher: ReverseSearcher<'a> { - StrExt::rfind(self, pat) + pat.into_searcher(self).next_match_back().map(|(i, _)| i) } /// An iterator over substrings of this string slice, separated by @@ -3496,7 +3113,13 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - StrExt::split(self, pat) + Split(SplitInternal { + start: 0, + end: self.len(), + matcher: pat.into_searcher(self), + allow_trailing_empty: true, + finished: false, + }) } /// An iterator over substrings of the given string slice, separated by @@ -3548,7 +3171,7 @@ macro_rules! str_core_methods { () => { pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplit(self, pat) + RSplit(self.split(pat).0) } /// An iterator over substrings of the given string slice, separated by @@ -3593,7 +3216,10 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - StrExt::split_terminator(self, pat) + SplitTerminator(SplitInternal { + allow_trailing_empty: false, + ..self.split(pat).0 + }) } /// An iterator over substrings of `self`, separated by characters @@ -3639,7 +3265,7 @@ macro_rules! str_core_methods { () => { pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplit_terminator(self, pat) + RSplitTerminator(self.split_terminator(pat).0) } /// An iterator over substrings of the given string slice, separated by a @@ -3690,7 +3316,10 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - StrExt::splitn(self, n, pat) + SplitN(SplitNInternal { + iter: self.split(pat).0, + count: n, + }) } /// An iterator over substrings of this string slice, separated by a @@ -3740,7 +3369,7 @@ macro_rules! str_core_methods { () => { pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplitn(self, n, pat) + RSplitN(self.splitn(n, pat).0) } /// An iterator over the disjoint matches of a pattern within the given string @@ -3779,7 +3408,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_matches", since = "1.2.0")] #[inline] pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - StrExt::matches(self, pat) + Matches(MatchesInternal(pat.into_searcher(self))) } /// An iterator over the disjoint matches of a pattern within this string slice, @@ -3818,7 +3447,7 @@ macro_rules! str_core_methods { () => { pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rmatches(self, pat) + RMatches(self.matches(pat).0) } /// An iterator over the disjoint matches of a pattern within this string @@ -3862,7 +3491,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - StrExt::match_indices(self, pat) + MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) } /// An iterator over the disjoint matches of a pattern within `self`, @@ -3907,7 +3536,7 @@ macro_rules! str_core_methods { () => { pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rmatch_indices(self, pat) + RMatchIndices(self.match_indices(pat).0) } /// Returns a string slice with leading and trailing whitespace removed. @@ -3926,7 +3555,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim(&self) -> &str { - StrExt::trim(self) + self.trim_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with leading whitespace removed. @@ -3962,7 +3591,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left(&self) -> &str { - StrExt::trim_left(self) + self.trim_left_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with trailing whitespace removed. @@ -3998,7 +3627,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_right(&self) -> &str { - StrExt::trim_right(self) + self.trim_right_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with all prefixes and suffixes that match a @@ -4030,7 +3659,21 @@ macro_rules! str_core_methods { () => { pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: DoubleEndedSearcher<'a> { - StrExt::trim_matches(self, pat) + let mut i = 0; + let mut j = 0; + let mut matcher = pat.into_searcher(self); + if let Some((a, b)) = matcher.next_reject() { + i = a; + j = b; // Remember earliest known match, correct it below if + // last match is different + } + if let Some((_, b)) = matcher.next_reject_back() { + j = b; + } + unsafe { + // Searcher is known to return valid indices + self.slice_unchecked(i, j) + } } /// Returns a string slice with all prefixes that match a pattern @@ -4061,7 +3704,15 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - StrExt::trim_left_matches(self, pat) + let mut i = self.len(); + let mut matcher = pat.into_searcher(self); + if let Some((a, _)) = matcher.next_reject() { + i = a; + } + unsafe { + // Searcher is known to return valid indices + self.slice_unchecked(i, self.len()) + } } /// Returns a string slice with all suffixes that match a pattern @@ -4100,7 +3751,15 @@ macro_rules! str_core_methods { () => { pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: ReverseSearcher<'a> { - StrExt::trim_right_matches(self, pat) + let mut j = 0; + let mut matcher = pat.into_searcher(self); + if let Some((_, b)) = matcher.next_reject_back() { + j = b; + } + unsafe { + // Searcher is known to return valid indices + self.slice_unchecked(0, j) + } } /// Parses this string slice into another type. @@ -4150,7 +3809,7 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn parse(&self) -> Result { - StrExt::parse(self) + FromStr::from_str(self) } /// Checks if all characters in this string are within the ASCII range. @@ -4220,16 +3879,8 @@ macro_rules! str_core_methods { () => { let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } -}} - -#[lang = "str"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl str { - str_core_methods!(); } - #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for str { #[inline] @@ -4332,17 +3983,6 @@ pub struct EncodeUtf16<'a> { extra: u16, } -// FIXME: remove (inline) this method -// when updating to a bootstrap compiler that has the new lang items. -// For grepping purpose: #[cfg(stage0)] -impl<'a> EncodeUtf16<'a> { - #[unstable(feature = "core_str_ext", issue = "32110")] - #[doc(hidden)] - pub fn new(s: &'a str) -> Self { - EncodeUtf16 { chars: s.chars(), extra: 0 } - } -} - #[stable(feature = "collection_debug", since = "1.17.0")] impl<'a> fmt::Debug for EncodeUtf16<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 7fb4b503c01..8c481338945 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -41,7 +41,6 @@ #![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] -#![cfg_attr(stage0, feature(atomic_nand))] #![feature(reverse_bits)] #![feature(inclusive_range_methods)] #![feature(iterator_find_map)] diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index 257f6ea20d4..ca6906f7310 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -98,7 +98,6 @@ mod tests { } #[test] - #[cfg(not(stage0))] fn test_reverse_bits() { assert_eq!(A.reverse_bits().reverse_bits(), A); assert_eq!(B.reverse_bits().reverse_bits(), B); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ac6ff6831ad..bbd684982fa 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -46,7 +46,6 @@ #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(entry_or_default)] -#![cfg_attr(stage0, feature(dyn_trait))] #![feature(from_ref)] #![feature(fs_read_write)] #![feature(iterator_find_map)] diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 0b1729294d8..a162ef36a60 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -240,11 +240,11 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( }); // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = do_catch! {{ + let _: io::Result<()> = do catch { let mut file = pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?; regioncx.dump_graphviz(&mut file)?; - }}; + }; } fn dump_annotation<'a, 'gcx, 'tcx>( diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index ecced1b8168..d9b6c406e20 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -24,7 +24,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] -#![cfg_attr(stage0, feature(dyn_trait))] #![feature(fs_read_write)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] @@ -34,7 +33,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(specialization)] -#![cfg_attr(stage0, feature(try_trait))] +#![feature(try_trait)] extern crate arena; #[macro_use] @@ -54,16 +53,6 @@ extern crate log_settings; extern crate rustc_apfloat; extern crate byteorder; -#[cfg(stage0)] -macro_rules! do_catch { - ($t:expr) => { (|| ::std::ops::Try::from_ok($t) )() } -} - -#[cfg(not(stage0))] -macro_rules! do_catch { - ($t:expr) => { do catch { $t } } -} - mod diagnostics; mod borrow_check; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 9d74ad0830f..9e1ce9b2851 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -137,7 +137,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( ) where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { - let _: io::Result<()> = do_catch! {{ + let _: io::Result<()> = do catch { let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?; writeln!(file, "// MIR for `{}`", node_path)?; writeln!(file, "// source = {:?}", source)?; @@ -150,14 +150,14 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( extra_data(PassWhere::BeforeCFG, &mut file)?; write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; extra_data(PassWhere::AfterCFG, &mut file)?; - }}; + }; if tcx.sess.opts.debugging_opts.dump_mir_graphviz { - let _: io::Result<()> = do_catch! {{ + let _: io::Result<()> = do catch { let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?; write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?; - }}; + }; } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 350b53a406b..ef79517d06a 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -71,8 +71,6 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] -#![cfg_attr(stage0, feature(dyn_trait))] - #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a14a27d5d61..e4b80b13aec 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -13,8 +13,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] -#![cfg_attr(stage0, feature(dyn_trait))] - #![feature(ascii_ctype)] #![feature(rustc_private)] #![feature(box_patterns)] diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index a8578404467..78d3d6d5e60 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -17,7 +17,6 @@ #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; -#[cfg(not(stage0))] #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] @@ -43,13 +42,6 @@ pub mod __default_lib_allocator { System.alloc(layout) as *mut u8 } - #[cfg(stage0)] - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_oom() -> ! { - super::oom() - } - #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, @@ -74,57 +66,4 @@ pub mod __default_lib_allocator { let layout = Layout::from_size_align_unchecked(size, align); System.alloc_zeroed(layout) as *mut u8 } - - #[cfg(stage0)] - pub mod stage0 { - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_usable_size(_layout: *const u8, - _min: *mut usize, - _max: *mut usize) { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_excess(_size: usize, - _align: usize, - _excess: *mut usize, - _err: *mut u8) -> *mut u8 { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8, - _old_size: usize, - _old_align: usize, - _new_size: usize, - _new_align: usize, - _excess: *mut usize, - _err: *mut u8) -> *mut u8 { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8, - _old_size: usize, - _old_align: usize, - _new_size: usize, - _new_align: usize) -> u8 { - unimplemented!() - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8, - _old_size: usize, - _old_align: usize, - _new_size: usize, - _new_align: usize) -> u8 { - unimplemented!() - } - - } } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7314d32b020..ae30321f46d 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -18,15 +18,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(not(test))] -#[cfg(stage0)] -use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -#[cfg(stage0)] -use num::FpCategory; -#[cfg(not(test))] use sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] @@ -41,12 +35,8 @@ pub use core::f32::{MIN, MIN_POSITIVE, MAX}; pub use core::f32::consts; #[cfg(not(test))] -#[cfg_attr(stage0, lang = "f32")] -#[cfg_attr(not(stage0), lang = "f32_runtime")] +#[lang = "f32_runtime"] impl f32 { - #[cfg(stage0)] - f32_core_methods!(); - /// Returns the largest integer less than or equal to a number. /// /// # Examples diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 75edba8979f..7950d434b77 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -18,15 +18,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[cfg(not(test))] -#[cfg(stage0)] -use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -#[cfg(stage0)] -use num::FpCategory; -#[cfg(not(test))] use sys::cmath; #[stable(feature = "rust1", since = "1.0.0")] @@ -41,12 +35,8 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX}; pub use core::f64::consts; #[cfg(not(test))] -#[cfg_attr(stage0, lang = "f64")] -#[cfg_attr(not(stage0), lang = "f64_runtime")] +#[lang = "f64_runtime"] impl f64 { - #[cfg(stage0)] - f64_core_methods!(); - /// Returns the largest integer less than or equal to a number. /// /// # Examples diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9cdc6a21622..f7d06852f27 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -252,7 +252,6 @@ #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] -#![cfg_attr(stage0, feature(core_float))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] @@ -260,10 +259,8 @@ #![feature(fs_read_write)] #![feature(fixed_size_array)] #![feature(float_from_str_radix)] -#![cfg_attr(stage0, feature(float_internals))] #![feature(fn_traits)] #![feature(fnbox)] -#![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(int_error_internals)] @@ -319,6 +316,7 @@ #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] #![feature(doc_alias)] +#![feature(float_internals)] #![default_lib_allocator] @@ -364,11 +362,6 @@ extern crate libc; #[allow(unused_extern_crates)] extern crate unwind; -// compiler-rt intrinsics -#[doc(masked)] -#[cfg(stage0)] -extern crate compiler_builtins; - // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 369c5b1ff60..dd8f79d20ab 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -45,17 +45,6 @@ impl State { } } -macro_rules! span_err_if_not_stage0 { - ($cx:expr, $sp:expr, $code:ident, $text:tt) => { - #[cfg(not(stage0))] { - span_err!($cx, $sp, $code, $text) - } - #[cfg(stage0)] { - $cx.span_err($sp, $text) - } - } -} - const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, @@ -100,7 +89,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, if asm_str_style.is_some() { // If we already have a string with instructions, // ending up in Asm state again is an error. - span_err_if_not_stage0!(cx, sp, E0660, "malformed inline assembly"); + span_err!(cx, sp, E0660, "malformed inline assembly"); return DummyResult::expr(sp); } // Nested parser, stop before the first colon (see above). @@ -153,7 +142,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, Some(Symbol::intern(&format!("={}", ch.as_str()))) } _ => { - span_err_if_not_stage0!(cx, span, E0661, + span_err!(cx, span, E0661, "output operand constraint lacks '=' or '+'"); None } @@ -179,10 +168,10 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, let (constraint, _str_style) = panictry!(p.parse_str()); if constraint.as_str().starts_with("=") { - span_err_if_not_stage0!(cx, p.prev_span, E0662, + span_err!(cx, p.prev_span, E0662, "input operand constraint contains '='"); } else if constraint.as_str().starts_with("+") { - span_err_if_not_stage0!(cx, p.prev_span, E0663, + span_err!(cx, p.prev_span, E0663, "input operand constraint contains '+'"); } @@ -205,7 +194,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, if OPTIONS.iter().any(|&opt| s == opt) { cx.span_warn(p.prev_span, "expected a clobber, found an option"); } else if s.as_str().starts_with("{") || s.as_str().ends_with("}") { - span_err_if_not_stage0!(cx, p.prev_span, E0664, + span_err!(cx, p.prev_span, E0664, "clobber should not be surrounded by braces"); } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index b6721dd28f3..e100ef29225 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -18,7 +18,7 @@ #![feature(decl_macro)] #![feature(str_escape)] -#![cfg_attr(not(stage0), feature(rustc_diagnostic_macros))] +#![feature(rustc_diagnostic_macros)] extern crate fmt_macros; #[macro_use] @@ -29,7 +29,6 @@ extern crate rustc_data_structures; extern crate rustc_errors as errors; extern crate rustc_target; -#[cfg(not(stage0))] mod diagnostics; mod assert; diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 7d5581bb774..8ff401164c1 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -23,7 +23,7 @@ // of other runtime components (registered via yet another special image section). #![feature(no_core, lang_items, optin_builtin_traits)] -#![crate_type="rlib"] +#![crate_type = "rlib"] #![no_core] #![allow(non_camel_case_types)] @@ -43,7 +43,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { drop_in_place(to_drop); } -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] +#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))] pub mod eh_frames { #[no_mangle] #[link_section = ".eh_frame"] @@ -54,6 +54,21 @@ pub mod eh_frames { // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h. static mut OBJ: [isize; 6] = [0; 6]; + macro_rules! impl_copy { + ($($t:ty)*) => { + $( + impl ::Copy for $t {} + )* + } + } + + impl_copy! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f32 f64 + bool char + } + // Unwind info registration/deregistration routines. // See the docs of `unwind` module in libstd. extern "C" { @@ -63,14 +78,18 @@ pub mod eh_frames { unsafe fn init() { // register unwind info on module startup - rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut OBJ as *mut _ as *mut u8); + rust_eh_register_frames( + &__EH_FRAME_BEGIN__ as *const u8, + &mut OBJ as *mut _ as *mut u8, + ); } unsafe fn uninit() { // unregister on shutdown - rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut OBJ as *mut _ as *mut u8); + rust_eh_unregister_frames( + &__EH_FRAME_BEGIN__ as *const u8, + &mut OBJ as *mut _ as *mut u8, + ); } // MSVC-specific init/uninit routine registration diff --git a/src/stage0.txt b/src/stage0.txt index a5ad2b315a1..435cfd2f6db 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-04-24 +date: 2018-05-10 rustc: beta cargo: beta -- cgit 1.4.1-3-g733a5 From f7c4a33f32b8139778b8c6792b9e55c74770a234 Mon Sep 17 00:00:00 2001 From: Cory Sherman Date: Thu, 24 May 2018 04:47:29 -0700 Subject: remove collections::range::RangeArgument was already moved to ops::RangeBounds (see #30877) --- src/libstd/collections/mod.rs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 9cf73824dea..d8e79b97970 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -437,14 +437,6 @@ pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; -#[unstable(feature = "collections_range", issue = "30877")] -#[rustc_deprecated(reason = "renamed and moved to `std::ops::RangeBounds`", since = "1.26.0")] -#[doc(hidden)] -/// Range syntax -pub mod range { - pub use ops::RangeBounds as RangeArgument; -} - #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] pub use heap::CollectionAllocErr; -- cgit 1.4.1-3-g733a5 From 1c2abda671ace3935a70b9d4c44bf944e1d34189 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 24 May 2018 14:08:47 +0200 Subject: Add `Once::new` as a way of constructing a `Once` --- src/libstd/sync/once.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 6fd8b6a5bba..138993e2271 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -73,9 +73,10 @@ use thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related /// functionality. This type can only be constructed with the [`ONCE_INIT`] -/// value. +/// value or the equivalent [`Once::new`] constructor. /// /// [`ONCE_INIT`]: constant.ONCE_INIT.html +/// [`Once::new`]: struct.Once.html#method.new /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 2a900e2b84f33a10ef810d6e986fc3d3be0c432d Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Thu, 24 May 2018 14:09:42 +0200 Subject: Update the `Once` docs to use `Once::new` --- src/libstd/sync/once.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 138993e2271..7eb7be23128 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -81,9 +81,9 @@ use thread::{self, Thread}; /// # Examples /// /// ``` -/// use std::sync::{Once, ONCE_INIT}; +/// use std::sync::Once; /// -/// static START: Once = ONCE_INIT; +/// static START: Once = Once::new(); /// /// START.call_once(|| { /// // run initialization here @@ -181,10 +181,10 @@ impl Once { /// # Examples /// /// ``` - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// /// static mut VAL: usize = 0; - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // Accessing a `static mut` is unsafe much of the time, but if we do so /// // in a synchronized fashion (e.g. write once or read all) then we're @@ -249,10 +249,10 @@ impl Once { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// use std::thread; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // poison the once /// let handle = thread::spawn(|| { @@ -432,10 +432,10 @@ impl OnceState { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// use std::thread; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// // poison the once /// let handle = thread::spawn(|| { @@ -453,9 +453,9 @@ impl OnceState { /// ``` /// #![feature(once_poison)] /// - /// use std::sync::{Once, ONCE_INIT}; + /// use std::sync::Once; /// - /// static INIT: Once = ONCE_INIT; + /// static INIT: Once = Once::new(); /// /// INIT.call_once_force(|state| { /// assert!(!state.poisoned()); -- cgit 1.4.1-3-g733a5 From 3f392abdfb2ec0f436352d349eedd5f6707bf817 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Thu, 24 May 2018 14:51:59 +0200 Subject: Implement suggestions from the PR - Move loading of atomic bool outside the loop - Add comment about TryFrom for future improvement --- src/libstd/sys/unix/fs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 8412540934e..6624c48cbe0 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -818,14 +818,16 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { (metadata.permissions(), metadata.size()) }; + let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); let mut written = 0u64; while written < len { + // TODO should ideally use TryFrom let bytes_to_copy = if len - written > usize::max_value() as u64 { usize::max_value() } else { (len - written) as usize }; - let copy_result = if HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) { + let copy_result = if has_copy_file_range { let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically -- cgit 1.4.1-3-g733a5 From fe9a19580cd12adc2d0483bb549140fc6566a57e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 May 2018 01:02:22 +0200 Subject: Add documentation about env! second argument --- src/libstd/macros.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index d1274a40900..8da70f5717e 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -364,7 +364,6 @@ pub mod builtin { /// /// let s = fmt::format(format_args!("hello {}", "world")); /// assert_eq!(s, format!("hello {}", "world")); - /// /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] @@ -379,7 +378,7 @@ pub mod builtin { /// compile time, yielding an expression of type `&'static str`. /// /// If the environment variable is not defined, then a compilation error - /// will be emitted. To not emit a compile error, use the [`option_env!`] + /// will be emitted. To not emit a compile error, use the [`option_env!`] /// macro instead. /// /// [`option_env!`]: ../std/macro.option_env.html @@ -390,6 +389,20 @@ pub mod builtin { /// let path: &'static str = env!("PATH"); /// println!("the $PATH variable at the time of compiling was: {}", path); /// ``` + /// + /// You can customize the error message by passing a string as the second + /// parameter: + /// + /// ```compile_fail + /// let doc: &'static str = env!("documentation", "what's that?!"); + /// ``` + /// + /// If the `documentation` environment variable is not defined, you'll get + /// the following error: + /// + /// ```text + /// error: what's that?! + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[macro_export] macro_rules! env { -- cgit 1.4.1-3-g733a5 From 3b271eb039d22a4b31caed29a2aac0a9ac604902 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Mon, 28 May 2018 17:19:42 +0200 Subject: Use FIXME instead of TODO; Move bytes_to_copy calculation inside if branch --- src/libstd/sys/unix/fs.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 6624c48cbe0..56075c5e8d0 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -821,13 +821,14 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); let mut written = 0u64; while written < len { - // TODO should ideally use TryFrom - let bytes_to_copy = if len - written > usize::max_value() as u64 { - usize::max_value() - } else { - (len - written) as usize - }; let copy_result = if has_copy_file_range { + // FIXME: should ideally use TryFrom + let bytes_to_copy = if len - written > usize::max_value() as u64 { + usize::max_value() + } else { + (len - written) as usize + }; + let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically -- cgit 1.4.1-3-g733a5 From 855ec8b6d54463e8d13676d325d828d30b2737f6 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Mon, 28 May 2018 18:24:01 -0600 Subject: Stabilize SystemTime::UNIX_EPOCH --- src/libstd/time.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 1215302757c..90ab3491599 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -271,7 +271,6 @@ impl SystemTime { /// # Examples /// /// ```no_run - /// #![feature(assoc_unix_epoch)] /// use std::time::SystemTime; /// /// match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { @@ -279,7 +278,7 @@ impl SystemTime { /// Err(_) => panic!("SystemTime before UNIX EPOCH!"), /// } /// ``` - #[unstable(feature = "assoc_unix_epoch", issue = "49502")] + #[stable(feature = "assoc_unix_epoch", since = "1.28.0")] pub const UNIX_EPOCH: SystemTime = UNIX_EPOCH; /// Returns the system time corresponding to "now". -- cgit 1.4.1-3-g733a5 From 0f4ef003ac1691d04f0ce519d1d78696689534aa Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 15 May 2018 09:56:46 +0900 Subject: Pass a `Layout` to `oom` As discussed in https://github.com/rust-lang/rust/issues/49668#issuecomment-384893456 and subsequent, there are use-cases where the OOM handler needs to know the size of the allocation that failed. The alignment might also be a cause for allocation failure, so providing it as well can be useful. --- src/liballoc/alloc.rs | 13 +-- src/liballoc/arc.rs | 2 +- src/liballoc/raw_vec.rs | 156 ++++++++++++++++-------------- src/liballoc/rc.rs | 2 +- src/libstd/alloc.rs | 4 +- src/libstd/collections/hash/map.rs | 39 ++++++-- src/libstd/collections/hash/table.rs | 43 +++++--- src/test/run-pass/allocator-alloc-one.rs | 4 +- src/test/run-pass/realloc-16687.rs | 6 +- src/test/run-pass/regions-mock-codegen.rs | 4 +- 10 files changed, 161 insertions(+), 112 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 4ae8fc649dd..8753c495737 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -115,7 +115,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if !ptr.is_null() { ptr as *mut u8 } else { - oom() + oom(layout) } } } @@ -134,12 +134,13 @@ pub(crate) unsafe fn box_free(ptr: Unique) { } #[rustc_allocator_nounwind] -pub fn oom() -> ! { - extern { +pub fn oom(layout: Layout) -> ! { + #[allow(improper_ctypes)] + extern "Rust" { #[lang = "oom"] - fn oom_impl() -> !; + fn oom_impl(layout: Layout) -> !; } - unsafe { oom_impl() } + unsafe { oom_impl(layout) } } #[cfg(test)] @@ -154,7 +155,7 @@ mod tests { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|_| oom()); + .unwrap_or_else(|_| oom(layout)); let mut i = ptr.cast::().as_ptr(); let end = i.offset(layout.size() as isize); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index d0950bff9ce..f7513248784 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -553,7 +553,7 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom()); + .unwrap_or_else(|_| oom(layout)); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 5c6f6b22aae..07bb7f1a3eb 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -96,14 +96,15 @@ impl RawVec { NonNull::::dangling().as_opaque() } else { let align = mem::align_of::(); + let layout = Layout::from_size_align(alloc_size, align).unwrap(); let result = if zeroed { - a.alloc_zeroed(Layout::from_size_align(alloc_size, align).unwrap()) + a.alloc_zeroed(layout) } else { - a.alloc(Layout::from_size_align(alloc_size, align).unwrap()) + a.alloc(layout) }; match result { Ok(ptr) => ptr, - Err(_) => oom(), + Err(_) => oom(layout), } }; @@ -318,7 +319,7 @@ impl RawVec { new_size); match ptr_res { Ok(ptr) => (new_cap, ptr.cast().into()), - Err(_) => oom(), + Err(_) => oom(Layout::from_size_align_unchecked(new_size, cur.align())), } } None => { @@ -327,7 +328,7 @@ impl RawVec { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(_) => oom(), + Err(_) => oom(Layout::array::(new_cap).unwrap()), } } }; @@ -389,37 +390,7 @@ impl RawVec { pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) -> Result<(), CollectionAllocErr> { - unsafe { - // NOTE: we don't early branch on ZSTs here because we want this - // to actually catch "asking for more than usize::MAX" in that case. - // If we make it past the first branch then we are guaranteed to - // panic. - - // Don't actually need any more capacity. - // Wrapping in case they gave a bad `used_cap`. - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { - return Ok(()); - } - - // Nothing we can really do about these checks :( - let new_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?; - let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; - - alloc_guard(new_layout.size())?; - - let res = match self.current_layout() { - Some(layout) => { - debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) - } - None => self.a.alloc(new_layout), - }; - - self.ptr = res?.cast().into(); - self.cap = new_cap; - - Ok(()) - } + self.reserve_internal(used_cap, needed_extra_cap, Fallible, Exact) } /// Ensures that the buffer contains at least enough space to hold @@ -443,9 +414,9 @@ impl RawVec { /// /// Aborts on OOM pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { - match self.try_reserve_exact(used_cap, needed_extra_cap) { + match self.reserve_internal(used_cap, needed_extra_cap, Infallible, Exact) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => oom(), + Err(AllocErr) => unreachable!(), Ok(()) => { /* yay */ } } } @@ -467,37 +438,7 @@ impl RawVec { /// The same as `reserve`, but returns on errors instead of panicking or aborting. pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize) -> Result<(), CollectionAllocErr> { - unsafe { - // NOTE: we don't early branch on ZSTs here because we want this - // to actually catch "asking for more than usize::MAX" in that case. - // If we make it past the first branch then we are guaranteed to - // panic. - - // Don't actually need any more capacity. - // Wrapping in case they give a bad `used_cap` - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { - return Ok(()); - } - - let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; - let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; - - // FIXME: may crash and burn on over-reserve - alloc_guard(new_layout.size())?; - - let res = match self.current_layout() { - Some(layout) => { - debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) - } - None => self.a.alloc(new_layout), - }; - - self.ptr = res?.cast().into(); - self.cap = new_cap; - - Ok(()) - } + self.reserve_internal(used_cap, needed_extra_cap, Fallible, Amortized) } /// Ensures that the buffer contains at least enough space to hold @@ -553,12 +494,12 @@ impl RawVec { /// # } /// ``` pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { - match self.try_reserve(used_cap, needed_extra_cap) { + match self.reserve_internal(used_cap, needed_extra_cap, Infallible, Amortized) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => oom(), + Err(AllocErr) => unreachable!(), Ok(()) => { /* yay */ } - } - } + } + } /// Attempts to ensure that the buffer contains at least enough space to hold /// `used_cap + needed_extra_cap` elements. If it doesn't already have /// enough capacity, will reallocate in place enough space plus comfortable slack @@ -670,7 +611,7 @@ impl RawVec { old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), - Err(_) => oom(), + Err(_) => oom(Layout::from_size_align_unchecked(new_size, align)), } } self.cap = amount; @@ -678,6 +619,73 @@ impl RawVec { } } +enum Fallibility { + Fallible, + Infallible, +} + +use self::Fallibility::*; + +enum ReserveStrategy { + Exact, + Amortized, +} + +use self::ReserveStrategy::*; + +impl RawVec { + fn reserve_internal( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + fallibility: Fallibility, + strategy: ReserveStrategy, + ) -> Result<(), CollectionAllocErr> { + unsafe { + use alloc::AllocErr; + + // NOTE: we don't early branch on ZSTs here because we want this + // to actually catch "asking for more than usize::MAX" in that case. + // If we make it past the first branch then we are guaranteed to + // panic. + + // Don't actually need any more capacity. + // Wrapping in case they gave a bad `used_cap`. + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return Ok(()); + } + + // Nothing we can really do about these checks :( + let new_cap = match strategy { + Exact => used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?, + Amortized => self.amortized_new_size(used_cap, needed_extra_cap)?, + }; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; + + alloc_guard(new_layout.size())?; + + let res = match self.current_layout() { + Some(layout) => { + debug_assert!(new_layout.align() == layout.align()); + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) + } + None => self.a.alloc(new_layout), + }; + + match (&res, fallibility) { + (Err(AllocErr), Infallible) => oom(new_layout), + _ => {} + } + + self.ptr = res?.cast().into(); + self.cap = new_cap; + + Ok(()) + } + } + +} + impl RawVec { /// Converts the entire buffer into `Box<[T]>`. /// diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d0188c6e828..1648fc6b7ef 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -668,7 +668,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom()); + .unwrap_or_else(|_| oom(layout)); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 78d3d6d5e60..0c95ceff2e3 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -13,14 +13,14 @@ #![unstable(issue = "32838", feature = "allocator_api")] #[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; -#[doc(inline)] pub use alloc_crate::alloc::{Global, oom}; +#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom}; #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] -pub extern fn rust_oom() -> ! { +pub extern fn rust_oom(_: Layout) -> ! { rtabort!("memory allocation failed"); } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a7eb002d5a1..935ea4b62b5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,7 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::{CollectionAllocErr, oom}; +use alloc::CollectionAllocErr; use cell::Cell; use borrow::Borrow; use cmp::max; @@ -23,8 +23,10 @@ use mem::{self, replace}; use ops::{Deref, Index}; use sys; -use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; +use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable, + SafeHash}; use super::table::BucketState::{Empty, Full}; +use super::table::Fallibility::{Fallible, Infallible}; const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two @@ -783,11 +785,11 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - match self.try_reserve(additional) { + match self.reserve_internal(additional, Infallible) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => oom(), + Err(CollectionAllocErr::AllocErr) => unreachable!(), Ok(()) => { /* yay */ } - } + } } /// Tries to reserve capacity for at least `additional` more elements to be inserted @@ -809,17 +811,24 @@ impl HashMap /// ``` #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.reserve_internal(additional, Fallible) + } + + fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility) + -> Result<(), CollectionAllocErr> { + let remaining = self.capacity() - self.len(); // this can't overflow if remaining < additional { - let min_cap = self.len().checked_add(additional) + let min_cap = self.len() + .checked_add(additional) .ok_or(CollectionAllocErr::CapacityOverflow)?; let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?; - self.try_resize(raw_cap)?; + self.try_resize(raw_cap, fallibility)?; } else if self.table.tag() && remaining <= self.len() { // Probe sequence is too long and table is half full, // resize early to reduce probing length. let new_capacity = self.table.capacity() * 2; - self.try_resize(new_capacity)?; + self.try_resize(new_capacity, fallibility)?; } Ok(()) } @@ -831,11 +840,21 @@ impl HashMap /// 2) Ensure `new_raw_cap` is a power of two or zero. #[inline(never)] #[cold] - fn try_resize(&mut self, new_raw_cap: usize) -> Result<(), CollectionAllocErr> { + fn try_resize( + &mut self, + new_raw_cap: usize, + fallibility: Fallibility, + ) -> Result<(), CollectionAllocErr> { assert!(self.table.size() <= new_raw_cap); assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); - let mut old_table = replace(&mut self.table, RawTable::try_new(new_raw_cap)?); + let mut old_table = replace( + &mut self.table, + match fallibility { + Infallible => RawTable::new(new_raw_cap), + Fallible => RawTable::try_new(new_raw_cap)?, + } + ); let old_size = old_table.size(); if old_table.size() == 0 { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index b50652ed6b5..eed2debcaa2 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -711,11 +711,21 @@ fn test_offset_calculation() { assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); } +pub(crate) enum Fallibility { + Fallible, + Infallible, +} + +use self::Fallibility::*; + impl RawTable { /// Does not initialize the buckets. The caller should ensure they, /// at the very least, set every hash to EMPTY_BUCKET. /// Returns an error if it cannot allocate or capacity overflows. - unsafe fn try_new_uninitialized(capacity: usize) -> Result, CollectionAllocErr> { + unsafe fn new_uninitialized_internal( + capacity: usize, + fallibility: Fallibility, + ) -> Result, CollectionAllocErr> { if capacity == 0 { return Ok(RawTable { size: 0, @@ -754,8 +764,12 @@ impl RawTable { return Err(CollectionAllocErr::CapacityOverflow); } - let buffer = Global.alloc(Layout::from_size_align(size, alignment) - .map_err(|_| CollectionAllocErr::CapacityOverflow)?)?; + let layout = Layout::from_size_align(size, alignment) + .map_err(|_| CollectionAllocErr::CapacityOverflow)?; + let buffer = Global.alloc(layout).map_err(|e| match fallibility { + Infallible => oom(layout), + Fallible => e, + })?; Ok(RawTable { capacity_mask: capacity.wrapping_sub(1), @@ -768,9 +782,9 @@ impl RawTable { /// Does not initialize the buckets. The caller should ensure they, /// at the very least, set every hash to EMPTY_BUCKET. unsafe fn new_uninitialized(capacity: usize) -> RawTable { - match Self::try_new_uninitialized(capacity) { + match Self::new_uninitialized_internal(capacity, Infallible) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => oom(), + Err(CollectionAllocErr::AllocErr) => unreachable!(), Ok(table) => { table } } } @@ -794,22 +808,29 @@ impl RawTable { } } - /// Tries to create a new raw table from a given capacity. If it cannot allocate, - /// it returns with AllocErr. - pub fn try_new(capacity: usize) -> Result, CollectionAllocErr> { + fn new_internal( + capacity: usize, + fallibility: Fallibility, + ) -> Result, CollectionAllocErr> { unsafe { - let ret = RawTable::try_new_uninitialized(capacity)?; + let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?; ptr::write_bytes(ret.hashes.ptr(), 0, capacity); Ok(ret) } } + /// Tries to create a new raw table from a given capacity. If it cannot allocate, + /// it returns with AllocErr. + pub fn try_new(capacity: usize) -> Result, CollectionAllocErr> { + Self::new_internal(capacity, Fallible) + } + /// Creates a new raw table from a given capacity. All buckets are /// initially empty. pub fn new(capacity: usize) -> RawTable { - match Self::try_new(capacity) { + match Self::new_internal(capacity, Infallible) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => oom(), + Err(CollectionAllocErr::AllocErr) => unreachable!(), Ok(table) => { table } } } diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index 12b115d0938..f1fdbfc702d 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -10,11 +10,11 @@ #![feature(allocator_api, nonnull)] -use std::alloc::{Alloc, Global, oom}; +use std::alloc::{Alloc, Global, Layout, oom}; fn main() { unsafe { - let ptr = Global.alloc_one::().unwrap_or_else(|_| oom()); + let ptr = Global.alloc_one::().unwrap_or_else(|_| oom(Layout::new::())); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); Global.dealloc_one(ptr); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 308792e5d89..febd249d776 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| oom()); + let ret = Global.alloc(layout).unwrap_or_else(|_| oom(layout)); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -72,8 +72,8 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size()) - .unwrap_or_else(|_| oom()); + let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old, new.size()) + .unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align()))); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-codegen.rs b/src/test/run-pass/regions-mock-codegen.rs index 60a7f70931d..745a19dec4d 100644 --- a/src/test/run-pass/regions-mock-codegen.rs +++ b/src/test/run-pass/regions-mock-codegen.rs @@ -32,8 +32,8 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { - let ptr = Global.alloc(Layout::new::()) - .unwrap_or_else(|_| oom()); + let layout = Layout::new::(); + let ptr = Global.alloc(layout).unwrap_or_else(|_| oom(layout)); &*(ptr.as_ptr() as *const _) } } -- cgit 1.4.1-3-g733a5 From c7d6a0130b6b76b65982916198e7de2b348f9718 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Tue, 29 May 2018 23:42:42 +0200 Subject: Fix additional nits: - compute bytes_to_copy more elegantly - add assert that written is 0 in fallback case --- src/libstd/sys/unix/fs.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 56075c5e8d0..38f1ac472fa 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -780,6 +780,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { #[cfg(any(target_os = "linux", target_os = "android"))] pub fn copy(from: &Path, to: &Path) -> io::Result { + use cmp; use fs::{File, set_permissions}; use sync::atomic::{AtomicBool, Ordering}; @@ -822,13 +823,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let mut written = 0u64; while written < len { let copy_result = if has_copy_file_range { - // FIXME: should ideally use TryFrom - let bytes_to_copy = if len - written > usize::max_value() as u64 { - usize::max_value() - } else { - (len - written) as usize - }; - + let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically @@ -856,6 +851,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Some(os_err) if os_err == libc::ENOSYS || os_err == libc::EXDEV => { // Either kernel is too old or the files are not mounted on the same fs. // Try again with fallback method + assert_eq!(written, 0); let ret = io::copy(&mut reader, &mut writer)?; set_permissions(to, perm)?; return Ok(ret) -- cgit 1.4.1-3-g733a5 From a4d899b4a1248f885563e241fa56fe9f69616dc2 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 16 May 2018 09:16:37 +0900 Subject: Add hooks allowing to override the `oom` behavior --- src/libstd/alloc.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 0c95ceff2e3..4f9dffc7c95 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -17,11 +17,55 @@ #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; +use core::sync::atomic::{AtomicPtr, Ordering}; +use core::{mem, ptr}; + +static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); + +/// Registers a custom OOM hook, replacing any that was previously registered. +/// +/// The OOM hook is invoked when an infallible memory allocation fails. +/// The default hook prints a message to standard error and aborts the +/// execution, but this behavior can be customized with the [`set_oom_hook`] +/// and [`take_oom_hook`] functions. +/// +/// The hook is provided with a `Layout` struct which contains information +/// about the allocation that failed. +/// +/// The OOM hook is a global resource. +pub fn set_oom_hook(hook: fn(Layout) -> !) { + HOOK.store(hook as *mut (), Ordering::SeqCst); +} + +/// Unregisters the current OOM hook, returning it. +/// +/// *See also the function [`set_oom_hook`].* +/// +/// If no custom hook is registered, the default hook will be returned. +pub fn take_oom_hook() -> fn(Layout) -> ! { + let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); + if hook.is_null() { + default_oom_hook + } else { + unsafe { mem::transmute(hook) } + } +} + +fn default_oom_hook(layout: Layout) -> ! { + rtabort!("memory allocation of {} bytes failed", layout.size()) +} + #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] -pub extern fn rust_oom(_: Layout) -> ! { - rtabort!("memory allocation failed"); +pub extern fn rust_oom(layout: Layout) -> ! { + let hook = HOOK.load(Ordering::SeqCst); + let hook: fn(Layout) -> ! = if hook.is_null() { + default_oom_hook + } else { + unsafe { mem::transmute(hook) } + }; + hook(layout) } #[cfg(not(test))] -- cgit 1.4.1-3-g733a5 From 9b6940d0b46284f24410050e9bfde0a9ab08d0fb Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Wed, 30 May 2018 06:33:54 +0200 Subject: fs: copy: Use File::set_permissions instead of fs::set_permissions We already got the open file descriptor at this point. Don't make the kernel resolve the path again. --- src/libstd/sys/unix/fs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 889d21cad65..9d0d3779057 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -807,14 +807,14 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { let perm = reader.metadata()?.permissions(); let ret = io::copy(&mut reader, &mut writer)?; - set_permissions(to, perm)?; + writer.set_permissions(perm)?; Ok(ret) } #[cfg(any(target_os = "linux", target_os = "android"))] pub fn copy(from: &Path, to: &Path) -> io::Result { use cmp; - use fs::{File, set_permissions}; + use fs::File; use sync::atomic::{AtomicBool, Ordering}; // Kernel prior to 4.5 don't have copy_file_range @@ -886,7 +886,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { // Try again with fallback method assert_eq!(written, 0); let ret = io::copy(&mut reader, &mut writer)?; - set_permissions(to, perm)?; + writer.set_permissions(perm)?; return Ok(ret) }, _ => return Err(err), @@ -894,6 +894,6 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } } } - set_permissions(to, perm)?; + writer.set_permissions(perm)?; Ok(written) } -- cgit 1.4.1-3-g733a5 From c5ee3b6df1db2c4410b0e8d7a80a2885cf5628f1 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Wed, 30 May 2018 12:09:20 +0200 Subject: Remobve unused import --- src/libstd/sys/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 9d0d3779057..758286fce6c 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -796,7 +796,7 @@ pub fn canonicalize(p: &Path) -> io::Result { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub fn copy(from: &Path, to: &Path) -> io::Result { - use fs::{File, set_permissions}; + use fs::File; if !from.is_file() { return Err(Error::new(ErrorKind::InvalidInput, "the source path is not an existing regular file")) -- cgit 1.4.1-3-g733a5 From 7c14a54bc81d8e259b43ac8077f2e851c7769753 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 22 May 2018 19:40:02 -0700 Subject: Replace libbacktrace with a submodule While we're at it update the `backtrace` crate from crates.io. It turns out that the submodule's configure script has gotten a lot more finnicky as of late so also switch over to using the `cc` crate manually which allows to avoid some hacks around the configure script as well --- .gitmodules | 3 ++ src/Cargo.lock | 8 +++-- src/libbacktrace | 1 + src/libstd/Cargo.toml | 1 + src/libstd/build.rs | 75 ++++++++++++++++++++++++++++++++-------------- src/tools/tidy/src/deps.rs | 1 + 6 files changed, 63 insertions(+), 26 deletions(-) create mode 160000 src/libbacktrace (limited to 'src/libstd') diff --git a/.gitmodules b/.gitmodules index 55f586389b1..f3eb902709c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -53,3 +53,6 @@ [submodule "src/tools/lld"] path = src/tools/lld url = https://github.com/rust-lang/lld.git +[submodule "src/libbacktrace"] + path = src/libbacktrace + url = https://github.com/rust-lang-nursery/libbacktrace diff --git a/src/Cargo.lock b/src/Cargo.lock index d61f007b6a5..3a27107f825 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -105,7 +105,7 @@ name = "backtrace" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -114,11 +114,12 @@ dependencies = [ [[package]] name = "backtrace-sys" -version = "0.1.16" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2513,6 +2514,7 @@ dependencies = [ "alloc_jemalloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", @@ -3051,7 +3053,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum assert_cli 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da59dbd8df54562665b925b427221ceda9b771408cb8a6cbd2125d3b001330b" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" -"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" +"checksum backtrace-sys 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5fd343a2466c4603f76f38de264bc0526cffc7fa38ba52fb9f13237eccc1ced2" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" diff --git a/src/libbacktrace b/src/libbacktrace new file mode 160000 index 00000000000..f4d02bbdbf8 --- /dev/null +++ b/src/libbacktrace @@ -0,0 +1 @@ +Subproject commit f4d02bbdbf8a2c5a31f0801dfef597a86caad9e3 diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 12017598853..5a2dce5930a 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -39,6 +39,7 @@ rustc_msan = { path = "../librustc_msan" } rustc_tsan = { path = "../librustc_tsan" } [build-dependencies] +cc = "1.0" build_helper = { path = "../build_helper" } [features] diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 6652ff98201..c34877d369c 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -11,14 +11,14 @@ #![deny(warnings)] extern crate build_helper; +extern crate cc; +use build_helper::native_lib_boilerplate; use std::env; -use std::process::Command; -use build_helper::{run, native_lib_boilerplate}; +use std::fs::File; fn main() { let target = env::var("TARGET").expect("TARGET was not set"); - let host = env::var("HOST").expect("HOST was not set"); if cfg!(feature = "backtrace") && !target.contains("cloudabi") && !target.contains("emscripten") && @@ -26,7 +26,7 @@ fn main() { !target.contains("msvc") && !target.contains("wasm32") { - let _ = build_libbacktrace(&host, &target); + let _ = build_libbacktrace(&target); } if target.contains("linux") { @@ -84,26 +84,55 @@ fn main() { } } -fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { - let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?; - let cflags = env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden -O2"; +fn build_libbacktrace(target: &str) -> Result<(), ()> { + let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?; - run(Command::new("sh") - .current_dir(&native.out_dir) - .arg(native.src_dir.join("configure").to_str().unwrap() - .replace("C:\\", "/c/") - .replace("\\", "/")) - .arg("--with-pic") - .arg("--disable-multilib") - .arg("--disable-shared") - .arg("--disable-host-shared") - .arg(format!("--host={}", build_helper::gnu_target(target))) - .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CFLAGS", cflags)); + let mut build = cc::Build::new(); + build + .flag("-fvisibility=hidden") + .include("../libbacktrace") + .include(&native.out_dir) + .out_dir(&native.out_dir) + .warnings(false) + .file("../libbacktrace/alloc.c") + .file("../libbacktrace/backtrace.c") + .file("../libbacktrace/dwarf.c") + .file("../libbacktrace/fileline.c") + .file("../libbacktrace/posix.c") + .file("../libbacktrace/read.c") + .file("../libbacktrace/sort.c") + .file("../libbacktrace/state.c"); - run(Command::new(build_helper::make(host)) - .current_dir(&native.out_dir) - .arg(format!("INCDIR={}", native.src_dir.display())) - .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"))); + if target.contains("darwin") { + build.file("../libbacktrace/macho.c"); + } else if target.contains("windows") { + build.file("../libbacktrace/pecoff.c"); + } else { + build.file("../libbacktrace/elf.c"); + + if target.contains("64") { + build.define("BACKTRACE_ELF_SIZE", "64"); + } else { + build.define("BACKTRACE_ELF_SIZE", "32"); + } + } + + File::create(native.out_dir.join("backtrace-supported.h")).unwrap(); + build.define("BACKTRACE_SUPPORTED", "1"); + build.define("BACKTRACE_USES_MALLOC", "1"); + build.define("BACKTRACE_SUPPORTS_THREADS", "0"); + build.define("BACKTRACE_SUPPORTS_DATA", "0"); + + File::create(native.out_dir.join("config.h")).unwrap(); + if !target.contains("apple-ios") && + !target.contains("solaris") && + !target.contains("redox") && + !target.contains("android") { + build.define("HAVE_DL_ITERATE_PHDR", "1"); + } + build.define("_GNU_SOURCE", "1"); + build.define("_LARGE_FILES", "1"); + + build.compile("backtrace"); Ok(()) } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index a4eb784fa7d..cef548b0d94 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -98,6 +98,7 @@ static WHITELIST: &'static [Crate] = &[ Crate("parking_lot"), Crate("parking_lot_core"), Crate("polonius-engine"), + Crate("pkg-config"), Crate("quick-error"), Crate("rand"), Crate("redox_syscall"), -- cgit 1.4.1-3-g733a5 From cb2a0d61adb47b530f8922c9ae3c816cbbf062c5 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 24 May 2018 23:50:28 +0200 Subject: std::fs::DirEntry.metadata(): use fstatat instead of lstat when possible --- src/libstd/sys/unix/fs.rs | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 889d21cad65..007511a992b 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -25,6 +25,8 @@ use sys_common::{AsInner, FromInner}; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; +#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] +use libc::{fstatat, dirfd}; #[cfg(target_os = "android")] use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64, dirent as dirent64, open as open64}; @@ -48,11 +50,15 @@ pub struct FileAttr { stat: stat64, } -pub struct ReadDir { +// all DirEntry's will have a reference to this struct +struct InnerReadDir { dirp: Dir, - root: Arc, + root: PathBuf, } +#[derive(Clone)] +pub struct ReadDir(Arc); + struct Dir(*mut libc::DIR); unsafe impl Send for Dir {} @@ -60,8 +66,8 @@ unsafe impl Sync for Dir {} pub struct DirEntry { entry: dirent64, - root: Arc, - // We need to store an owned copy of the directory name + dir: ReadDir, + // We need to store an owned copy of the entry name // on Solaris and Fuchsia because a) it uses a zero-length // array to store the name, b) its lifetime between readdir // calls is not guaranteed. @@ -207,7 +213,7 @@ impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.root, f) + fmt::Debug::fmt(&*self.0.root, f) } } @@ -240,7 +246,7 @@ impl Iterator for ReadDir { entry: *entry_ptr, name: ::slice::from_raw_parts(name as *const u8, namelen as usize).to_owned().into_boxed_slice(), - root: self.root.clone() + dir: self.clone() }; if ret.name_bytes() != b"." && ret.name_bytes() != b".." { return Some(Ok(ret)) @@ -254,11 +260,11 @@ impl Iterator for ReadDir { unsafe { let mut ret = DirEntry { entry: mem::zeroed(), - root: self.root.clone() + dir: self.clone(), }; let mut entry_ptr = ptr::null_mut(); loop { - if readdir64_r(self.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + if readdir64_r(self.0.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { return Some(Err(Error::last_os_error())) } if entry_ptr.is_null() { @@ -281,13 +287,27 @@ impl Drop for Dir { impl DirEntry { pub fn path(&self) -> PathBuf { - self.root.join(OsStr::from_bytes(self.name_bytes())) + self.dir.0.root.join(OsStr::from_bytes(self.name_bytes())) } pub fn file_name(&self) -> OsString { OsStr::from_bytes(self.name_bytes()).to_os_string() } + #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] + pub fn metadata(&self) -> io::Result { + let fd = cvt(unsafe {dirfd(self.dir.0.dirp.0)})?; + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { + fstatat(fd, + self.entry.d_name.as_ptr(), + &mut stat as *mut _ as *mut _, + libc::AT_SYMLINK_NOFOLLOW) + })?; + Ok(FileAttr { stat: stat }) + } + + #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] pub fn metadata(&self) -> io::Result { lstat(&self.path()) } @@ -664,14 +684,15 @@ impl fmt::Debug for File { } pub fn readdir(p: &Path) -> io::Result { - let root = Arc::new(p.to_path_buf()); + let root = p.to_path_buf(); let p = cstr(p)?; unsafe { let ptr = libc::opendir(p.as_ptr()); if ptr.is_null() { Err(Error::last_os_error()) } else { - Ok(ReadDir { dirp: Dir(ptr), root: root }) + let inner = InnerReadDir { dirp: Dir(ptr), root }; + Ok(ReadDir(Arc::new(inner))) } } } -- cgit 1.4.1-3-g733a5 From 8dec03b71af22a160803c241b6812b8e54ee9671 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Thu, 31 May 2018 19:18:58 +0200 Subject: libstd/sys/unix/fs.rs: fix compilation on fuchsia --- src/libstd/sys/unix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 007511a992b..c4d94259bd6 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -229,7 +229,7 @@ impl Iterator for ReadDir { // is safe to use in threaded applications and it is generally preferred // over the readdir_r(3C) function. super::os::set_errno(0); - let entry_ptr = libc::readdir(self.dirp.0); + let entry_ptr = libc::readdir(self.0.dirp.0); if entry_ptr.is_null() { // NULL can mean either the end is reached or an error occurred. // So we had to clear errno beforehand to check for an error now. -- cgit 1.4.1-3-g733a5 From 95e2bf253d864c5e14ad000ffa2040ce85916056 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Thu, 31 May 2018 22:05:36 +0200 Subject: Fix confusing error message for sub_instant When subtracting an Instant from another, the function will panick when `RHS > self`, but the error message confusingly displays a different error: ```rust let i = Instant::now(); let other = Instant::now(); if other > i { println!("{:?}", i - other); } ``` This results in a panic: ``` thread 'test_instant' panicked at 'other was less than the current instant', libstd/sys/unix/time.rs:292:17 ``` --- src/libstd/sys/unix/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 83127935909..f7459cb55d5 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -289,7 +289,7 @@ mod inner { pub fn sub_instant(&self, other: &Instant) -> Duration { self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("other was less than the current instant") + panic!("other was greater than the current instant") }) } -- cgit 1.4.1-3-g733a5 From b945be71e87f99f7578a039a541aeae6de8b6020 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 1 Jun 2018 08:50:07 +0900 Subject: Make the OOM hook return `()` rather than `!` Per discussion in https://github.com/rust-lang/rust/issues/51245#issuecomment-393651083 This allows more flexibility in what can be done with the API. This also splits `rtabort!` into `dumb_print` happening in the default hook and `abort_internal`, happening in the actual oom handler after calling the hook. Registering an empty function thus makes the oom handler not print anything but still abort. Cc: @alexcrichton --- src/libstd/alloc.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 4f9dffc7c95..3b1a3a439e7 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -19,21 +19,22 @@ use core::sync::atomic::{AtomicPtr, Ordering}; use core::{mem, ptr}; +use sys_common::util::dumb_print; static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// Registers a custom OOM hook, replacing any that was previously registered. /// -/// The OOM hook is invoked when an infallible memory allocation fails. -/// The default hook prints a message to standard error and aborts the -/// execution, but this behavior can be customized with the [`set_oom_hook`] -/// and [`take_oom_hook`] functions. +/// The OOM hook is invoked when an infallible memory allocation fails, before +/// the runtime aborts. The default hook prints a message to standard error, +/// but this behavior can be customized with the [`set_oom_hook`] and +/// [`take_oom_hook`] functions. /// /// The hook is provided with a `Layout` struct which contains information /// about the allocation that failed. /// /// The OOM hook is a global resource. -pub fn set_oom_hook(hook: fn(Layout) -> !) { +pub fn set_oom_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); } @@ -42,7 +43,7 @@ pub fn set_oom_hook(hook: fn(Layout) -> !) { /// *See also the function [`set_oom_hook`].* /// /// If no custom hook is registered, the default hook will be returned. -pub fn take_oom_hook() -> fn(Layout) -> ! { +pub fn take_oom_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); if hook.is_null() { default_oom_hook @@ -51,8 +52,8 @@ pub fn take_oom_hook() -> fn(Layout) -> ! { } } -fn default_oom_hook(layout: Layout) -> ! { - rtabort!("memory allocation of {} bytes failed", layout.size()) +fn default_oom_hook(layout: Layout) { + dumb_print(format_args!("memory allocation of {} bytes failed", layout.size())); } #[cfg(not(test))] @@ -60,12 +61,13 @@ fn default_oom_hook(layout: Layout) -> ! { #[lang = "oom"] pub extern fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); - let hook: fn(Layout) -> ! = if hook.is_null() { + let hook: fn(Layout) = if hook.is_null() { default_oom_hook } else { unsafe { mem::transmute(hook) } }; - hook(layout) + hook(layout); + unsafe { ::sys::abort_internal(); } } #[cfg(not(test))] -- cgit 1.4.1-3-g733a5 From 2c3eff99f0cc0bb460f9068c553e5d029e7b7ec3 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Fri, 1 Jun 2018 09:32:20 +0200 Subject: fs: copy: Add EPERM to fallback error conditions Fixes #51266 --- src/libstd/sys/unix/fs.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index c4092dcd388..774340388e1 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -890,8 +890,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { ) }; if let Err(ref copy_err) = copy_result { - if let Some(libc::ENOSYS) = copy_err.raw_os_error() { - HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); + match copy_err.raw_os_error() { + Some(libc::ENOSYS) | Some(libc::EPERM) => { + HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); + } + _ => {} } } copy_result @@ -902,9 +905,13 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Ok(ret) => written += ret as u64, Err(err) => { match err.raw_os_error() { - Some(os_err) if os_err == libc::ENOSYS || os_err == libc::EXDEV => { - // Either kernel is too old or the files are not mounted on the same fs. - // Try again with fallback method + Some(os_err) if os_err == libc::ENOSYS + || os_err == libc::EXDEV + || os_err == libc::EPERM => { + // Try fallback io::copy if either: + // - Kernel version is < 4.5 (ENOSYS) + // - Files are mounted on different fs (EXDEV) + // - copy_file_range is disallowed, for example by seccomp (EPERM) assert_eq!(written, 0); let ret = io::copy(&mut reader, &mut writer)?; writer.set_permissions(perm)?; -- cgit 1.4.1-3-g733a5 From 48bd07e3a9220a937fdfa139c7127009ee5a1130 Mon Sep 17 00:00:00 2001 From: steveklabnik Date: Fri, 1 Jun 2018 08:24:36 -0400 Subject: Remove feature flag from fs::read_to_string example This is stable, and so no longer needed --- src/libstd/fs.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 442a0873ae0..987687ea8e8 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -295,8 +295,6 @@ pub fn read>(path: P) -> io::Result> { /// # Examples /// /// ```no_run -/// #![feature(fs_read_write)] -/// /// use std::fs; /// use std::net::SocketAddr; /// -- cgit 1.4.1-3-g733a5 From c6bebf4554692c07ff96c8395f8aeddb09443708 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 29 May 2018 13:09:09 +0200 Subject: Simplify HashMap layout calculation by using Layout --- src/libcore/alloc.rs | 8 +++ src/libstd/collections/hash/table.rs | 120 ++++------------------------------- 2 files changed, 21 insertions(+), 107 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 674c4fb57c7..6172a98bca6 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -392,6 +392,14 @@ impl From for CollectionAllocErr { } } +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(_: LayoutErr) -> Self { + CollectionAllocErr::CapacityOverflow + } +} + /// A memory allocator that can be registered to be the one backing `std::alloc::Global` /// though the `#[global_allocator]` attributes. pub unsafe trait GlobalAlloc { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index eed2debcaa2..c62a409ac02 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom}; -use cmp; +use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom}; use hash::{BuildHasher, Hash, Hasher}; use marker; -use mem::{align_of, size_of, needs_drop}; +use mem::{size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, NonNull}; @@ -651,64 +650,12 @@ impl GapThenFull } } - -/// Rounds up to a multiple of a power of two. Returns the closest multiple -/// of `target_alignment` that is higher or equal to `unrounded`. -/// -/// # Panics -/// -/// Panics if `target_alignment` is not a power of two. -#[inline] -fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize { - assert!(target_alignment.is_power_of_two()); - (unrounded + target_alignment - 1) & !(target_alignment - 1) -} - -#[test] -fn test_rounding() { - assert_eq!(round_up_to_next(0, 4), 0); - assert_eq!(round_up_to_next(1, 4), 4); - assert_eq!(round_up_to_next(2, 4), 4); - assert_eq!(round_up_to_next(3, 4), 4); - assert_eq!(round_up_to_next(4, 4), 4); - assert_eq!(round_up_to_next(5, 4), 8); -} - -// Returns a tuple of (pairs_offset, end_of_pairs_offset), -// from the start of a mallocated array. -#[inline] -fn calculate_offsets(hashes_size: usize, - pairs_size: usize, - pairs_align: usize) - -> (usize, usize, bool) { - let pairs_offset = round_up_to_next(hashes_size, pairs_align); - let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size); - - (pairs_offset, end_of_pairs, oflo) -} - -// Returns a tuple of (minimum required malloc alignment, -// array_size), from the start of a mallocated array. -fn calculate_allocation(hash_size: usize, - hash_align: usize, - pairs_size: usize, - pairs_align: usize) - -> (usize, usize, bool) { - let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); - - let align = cmp::max(hash_align, pairs_align); - - (align, end_of_pairs, oflo) -} - -#[test] -fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false)); - assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); - assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); - assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); +// Returns a Layout which describes the allocation required for a hash table, +// and the offset of the array of (key, value) pairs in the allocation. +fn calculate_layout(capacity: usize) -> Result<(Layout, usize), LayoutErr> { + let hashes = Layout::array::(capacity)?; + let pairs = Layout::array::<(K, V)>(capacity)?; + hashes.extend(pairs) } pub(crate) enum Fallibility { @@ -735,37 +682,11 @@ impl RawTable { }); } - // No need for `checked_mul` before a more restrictive check performed - // later in this method. - let hashes_size = capacity.wrapping_mul(size_of::()); - let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>()); - // Allocating hashmaps is a little tricky. We need to allocate two // arrays, but since we know their sizes and alignments up front, // we just allocate a single array, and then have the subarrays // point into it. - // - // This is great in theory, but in practice getting the alignment - // right is a little subtle. Therefore, calculating offsets has been - // factored out into a different function. - let (alignment, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); - if oflo { - return Err(CollectionAllocErr::CapacityOverflow); - } - - // One check for overflow that covers calculation and rounding of size. - let size_of_bucket = size_of::().checked_add(size_of::<(K, V)>()) - .ok_or(CollectionAllocErr::CapacityOverflow)?; - let capacity_mul_size_of_bucket = capacity.checked_mul(size_of_bucket); - if capacity_mul_size_of_bucket.is_none() || size < capacity_mul_size_of_bucket.unwrap() { - return Err(CollectionAllocErr::CapacityOverflow); - } - - let layout = Layout::from_size_align(size, alignment) - .map_err(|_| CollectionAllocErr::CapacityOverflow)?; + let (layout, _) = calculate_layout::(capacity)?; let buffer = Global.alloc(layout).map_err(|e| match fallibility { Infallible => oom(layout), Fallible => e, @@ -790,18 +711,12 @@ impl RawTable { } fn raw_bucket_at(&self, index: usize) -> RawBucket { - let hashes_size = self.capacity() * size_of::(); - let pairs_size = self.capacity() * size_of::<(K, V)>(); - - let (pairs_offset, _, oflo) = - calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); - debug_assert!(!oflo, "capacity overflow"); - + let (_, pairs_offset) = calculate_layout::(self.capacity()).unwrap(); let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { hash_start: buffer as *mut HashUint, - pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + pair_start: buffer.add(pairs_offset) as *const (K, V), idx: index, _marker: marker::PhantomData, } @@ -1194,18 +1109,9 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { } } - let hashes_size = self.capacity() * size_of::(); - let pairs_size = self.capacity() * size_of::<(K, V)>(); - let (align, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); - - debug_assert!(!oflo, "should be impossible"); - + let (layout, _) = calculate_layout::(self.capacity()).unwrap(); unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), - Layout::from_size_align(size, align).unwrap()); + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } -- cgit 1.4.1-3-g733a5 From 7da469da8b9f389500d0dac17f67d8928386ef60 Mon Sep 17 00:00:00 2001 From: Pslydhh Date: Sat, 2 Jun 2018 14:34:34 +0800 Subject: park():prohibit spurious wakeups in next park should consume this notification, so prohibit spurious wakeups in next park --- src/libstd/thread/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 1b976b79b4c..d4ee172c961 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -796,7 +796,11 @@ pub fn park() { let mut m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => return, // notified after we locked + Err(NOTIFIED) => { + // should consume this notification, so prohibit spurious wakeups in next park... + thread.inner.state.store(EMPTY, SeqCst); + return; + }, // notified after we locked Err(_) => panic!("inconsistent park state"), } loop { @@ -882,7 +886,11 @@ pub fn park_timeout(dur: Duration) { let m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => return, // notified after we locked + Err(NOTIFIED) => { + // should consume this notification, so prohibit spurious wakeups in next park... + thread.inner.state.store(EMPTY, SeqCst); + return; + }, // notified after we locked Err(_) => panic!("inconsistent park_timeout state"), } -- cgit 1.4.1-3-g733a5 From 151e41ff0c2769b5bc9f0d37ae37136fb4fcb7e0 Mon Sep 17 00:00:00 2001 From: Pslydhh Date: Sat, 2 Jun 2018 15:36:23 +0800 Subject: remove trailing whitespace remove trailing whitespace --- src/libstd/thread/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index d4ee172c961..d76107e9909 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -796,10 +796,10 @@ pub fn park() { let mut m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => { + Err(NOTIFIED) => { // should consume this notification, so prohibit spurious wakeups in next park... - thread.inner.state.store(EMPTY, SeqCst); - return; + thread.inner.state.store(EMPTY, SeqCst); + return; }, // notified after we locked Err(_) => panic!("inconsistent park state"), } @@ -886,10 +886,10 @@ pub fn park_timeout(dur: Duration) { let m = thread.inner.lock.lock().unwrap(); match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} - Err(NOTIFIED) => { + Err(NOTIFIED) => { // should consume this notification, so prohibit spurious wakeups in next park... - thread.inner.state.store(EMPTY, SeqCst); - return; + thread.inner.state.store(EMPTY, SeqCst); + return; }, // notified after we locked Err(_) => panic!("inconsistent park_timeout state"), } -- cgit 1.4.1-3-g733a5 From b352d2d167f1de4ed8a6da3405dc90fe9d646204 Mon Sep 17 00:00:00 2001 From: Pslydhh Date: Sat, 2 Jun 2018 15:59:54 +0800 Subject: removes tabs --- src/libstd/thread/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index d76107e9909..e6d052a458f 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -797,10 +797,9 @@ pub fn park() { match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} Err(NOTIFIED) => { - // should consume this notification, so prohibit spurious wakeups in next park... - thread.inner.state.store(EMPTY, SeqCst); - return; - }, // notified after we locked + thread.inner.state.store(EMPTY, SeqCst); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park state"), } loop { @@ -887,10 +886,9 @@ pub fn park_timeout(dur: Duration) { match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} Err(NOTIFIED) => { - // should consume this notification, so prohibit spurious wakeups in next park... - thread.inner.state.store(EMPTY, SeqCst); - return; - }, // notified after we locked + thread.inner.state.store(EMPTY, SeqCst); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park_timeout state"), } -- cgit 1.4.1-3-g733a5 From 1bc6c4b10e7036be6fe61999fabf3462eeed39be Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Fri, 6 Apr 2018 15:32:54 -0400 Subject: Clarify the difference between get_mut and into_mut for OccupiedEntry The examples for both hash_map::OccupiedEntry::get_mut and hash_map::OccupiedEntry::into_mut were almost identical. This led to some confusion over the difference, namely why you would ever use get_mut when into_mut gives alonger lifetime. Reddit thread: https://www.reddit.com/r/rust/comments/8a5swr/why_does_hashmaps This commit adds two lines and a comment to the example, to show that the entry object can be re-used after calling get_mut. --- src/libstd/collections/hash/map.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 935ea4b62b5..e733b0b8048 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2261,10 +2261,14 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map["poneyland"], 12); /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// *o.get_mut() += 10; + /// *o.get_mut() += 10; + /// assert_eq!(o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; /// } /// - /// assert_eq!(map["poneyland"], 22); + /// assert_eq!(map["poneyland"], 24); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { -- cgit 1.4.1-3-g733a5 From ed1a8fff6282e1e9ed49e3638f365c358385fd99 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Fri, 6 Apr 2018 17:10:35 -0400 Subject: Fixed typo --- src/libstd/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e733b0b8048..4a67c444ed6 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2262,7 +2262,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// assert_eq!(map["poneyland"], 12); /// if let Entry::Occupied(mut o) = map.entry("poneyland") { /// *o.get_mut() += 10; - /// assert_eq!(o.get(), 22); + /// assert_eq!(*o.get(), 22); /// /// // We can use the same Entry multiple times. /// *o.get_mut() += 2; -- cgit 1.4.1-3-g733a5 From a86f556ee37c13047f966c35effab8b334b7de67 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 2 Jun 2018 16:04:53 -0400 Subject: Add a couple lines describing differences between into_mut/get_mut. --- src/libstd/collections/hash/map.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4a67c444ed6..5cbd8891364 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2250,6 +2250,11 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a mutable reference to the value in the entry. /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// /// # Examples /// /// ``` @@ -2278,6 +2283,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself. /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// /// # Examples /// /// ``` -- cgit 1.4.1-3-g733a5 From e44ad61a2d8e3bac1d2cbf2467a7202250b8a77e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 30 Apr 2018 10:55:24 +0200 Subject: implement #[panic_implementation] --- src/libcore/macros.rs | 22 +++++ src/libcore/panic.rs | 6 +- src/libcore/panicking.rs | 40 +++++++++ src/librustc/middle/dead.rs | 2 +- src/librustc/middle/lang_items.rs | 5 +- src/librustc/middle/weak_lang_items.rs | 2 +- src/librustc_typeck/check/mod.rs | 44 +++++++++- src/libstd/lib.rs | 2 + src/libstd/panicking.rs | 97 +++++++++++++++++++++- src/libsyntax/feature_gate.rs | 9 ++ src/test/compile-fail/duplicate_entry_error.rs | 8 +- .../feature-gate-panic-implementation.rs | 21 +++++ src/test/compile-fail/no_owned_box_lang_item.rs | 2 +- .../panic-implementation-bad-signature-1.rs | 24 ++++++ .../panic-implementation-bad-signature-2.rs | 25 ++++++ .../panic-implementation-bad-signature-3.rs | 22 +++++ .../compile-fail/panic-implementation-duplicate.rs | 28 +++++++ .../panic-implementation-requires-panic-info.rs | 26 ++++++ .../auxiliary/panic-runtime-lang-items.rs | 6 +- src/test/compile-fail/weak-lang-item.rs | 2 +- src/test/ui/error-codes/E0152.rs | 2 +- src/test/ui/error-codes/E0152.stderr | 2 +- 22 files changed, 379 insertions(+), 18 deletions(-) create mode 100644 src/test/compile-fail/feature-gate-panic-implementation.rs create mode 100644 src/test/compile-fail/panic-implementation-bad-signature-1.rs create mode 100644 src/test/compile-fail/panic-implementation-bad-signature-2.rs create mode 100644 src/test/compile-fail/panic-implementation-bad-signature-3.rs create mode 100644 src/test/compile-fail/panic-implementation-duplicate.rs create mode 100644 src/test/compile-fail/panic-implementation-requires-panic-info.rs (limited to 'src/libstd') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c830c22ee5f..f98626d939d 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -9,6 +9,7 @@ // except according to those terms. /// Entry point of thread panic, for details, see std::macros +#[cfg(stage0)] #[macro_export] #[allow_internal_unstable] #[stable(feature = "core", since = "1.6.0")] @@ -28,6 +29,27 @@ macro_rules! panic { }); } +/// Entry point of thread panic, for details, see std::macros +#[cfg(not(stage0))] +#[macro_export] +#[allow_internal_unstable] +#[stable(feature = "core", since = "1.6.0")] +macro_rules! panic { + () => ( + panic!("explicit panic") + ); + ($msg:expr) => ({ + $crate::panicking::panic_payload($msg, &(file!(), line!(), __rust_unstable_column!())) + }); + ($msg:expr,) => ( + panic!($msg) + ); + ($fmt:expr, $($arg:tt)+) => ({ + $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), + &(file!(), line!(), __rust_unstable_column!())) + }); +} + /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print the values of the expressions with their diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 27ec4aaac75..37ae05309af 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -35,6 +35,7 @@ use fmt; /// /// panic!("Normal panic"); /// ``` +#[cfg_attr(not(stage0), lang = "panic_info")] #[stable(feature = "panic_hooks", since = "1.10.0")] #[derive(Debug)] pub struct PanicInfo<'a> { @@ -53,7 +54,8 @@ impl<'a> PanicInfo<'a> { pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>) -> Self { - PanicInfo { payload: &(), location, message } + struct NoPayload; + PanicInfo { payload: &NoPayload, location, message } } #[doc(hidden)] @@ -121,7 +123,7 @@ impl<'a> PanicInfo<'a> { #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn location(&self) -> Option<&Location> { // NOTE: If this is changed to sometimes return None, - // deal with that case in std::panicking::default_hook. + // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt. Some(&self.location) } } diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 6b3dc75af46..1470a01e0e6 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -36,7 +36,33 @@ and related macros", issue = "0")] +#[cfg(not(stage0))] +use any::Any; use fmt; +#[cfg(not(stage0))] +use panic::{Location, PanicInfo}; + +#[cfg(not(stage0))] +#[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe +extern "C" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo) -> !; +} + +#[cfg(not(stage0))] +#[cold] #[inline(never)] +pub fn panic_payload(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! +where + M: Any + Send, +{ + let (file, line, col) = *file_line_col; + let mut pi = PanicInfo::internal_constructor( + None, + Location::internal_constructor(file, line, col), + ); + pi.set_payload(&msg); + unsafe { panic_impl(&pi) } +} #[cold] #[inline(never)] // this is the slow path, always #[lang = "panic"] @@ -59,6 +85,7 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), len, index), file_line_col) } +#[cfg(stage0)] #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { #[allow(improper_ctypes)] @@ -70,3 +97,16 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) let (file, line, col) = *file_line_col; unsafe { panic_impl(fmt, file, line, col) } } + +#[cfg(not(stage0))] +#[cold] #[inline(never)] +pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + struct NoPayload; + + let (file, line, col) = *file_line_col; + let pi = PanicInfo::internal_constructor( + Some(&fmt), + Location::internal_constructor(file, line, col), + ); + unsafe { panic_impl(&pi) } +} diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index e3b20789714..7ebc0d4a4de 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -284,7 +284,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt, id: ast::NodeId, attrs: &[ast::Attribute]) -> bool { - if attr::contains_name(attrs, "lang") { + if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") { return true; } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index d70f994e87b..fe676919a7d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -185,6 +185,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { if let Some(value) = attribute.value_str() { return Some((value, attribute.span)); } + } else if attribute.check_name("panic_implementation") { + return Some((Symbol::intern("panic_impl"), attribute.span)) } } @@ -299,7 +301,8 @@ language_item_table! { // lang item, but do not have it defined. PanicFnLangItem, "panic", panic_fn; PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn; - PanicFmtLangItem, "panic_fmt", panic_fmt; + PanicInfoLangItem, "panic_info", panic_info; + PanicImplLangItem, "panic_impl", panic_impl; ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; BoxFreeFnLangItem, "box_free", box_free_fn; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 42e4d3861ba..3c2ea047218 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -148,7 +148,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { ) } weak_lang_items! { - panic_fmt, PanicFmtLangItem, rust_begin_unwind; + panic_impl, PanicImplLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; oom, OomLangItem, rust_oom; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 90b974fb972..5c33eb5f0af 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -96,7 +96,7 @@ use rustc::middle::region; use rustc::mir::interpret::{GlobalId}; use rustc::ty::subst::{UnpackedKind, Subst, Substs}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; -use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate}; +use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::ty::maps::Providers; @@ -1129,6 +1129,48 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } } + // Check that a function marked as `#[panic_implementation]` has signature `fn(&PanicInfo) -> !` + if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() { + if panic_impl_did == fn_hir_id.owner_def_id() { + if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() { + if ret_ty.sty != ty::TyNever { + fcx.tcx.sess.span_err( + decl.output.span(), + "return type should be `!`", + ); + } + + let inputs = fn_sig.inputs(); + let span = fcx.tcx.hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_panic_info = match inputs[0].sty { + ty::TyRef(region, ty::TypeAndMut { ty, mutbl }) => match ty.sty { + ty::TyAdt(ref adt, _) => { + adt.did == panic_info_did && + mutbl == hir::Mutability::MutImmutable && + *region != RegionKind::ReStatic + }, + _ => false, + }, + _ => false, + }; + + if !arg_is_panic_info { + fcx.tcx.sess.span_err( + decl.inputs[0].span, + "argument should be `&PanicInfo`", + ); + } + } else { + fcx.tcx.sess.span_err(span, "function should have one argument"); + } + } else { + fcx.tcx.sess.err("language item required, but not found: `panic_info`"); + } + } + + } + (fcx, gen_ty) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f7d06852f27..c576245edb7 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -317,6 +317,8 @@ #![cfg_attr(windows, feature(used))] #![feature(doc_alias)] #![feature(float_internals)] +#![feature(panic_info_message)] +#![cfg_attr(not(stage0), feature(panic_implementation))] #![default_lib_allocator] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 403056240bf..6bb098310de 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -186,7 +186,7 @@ fn default_hook(info: &PanicInfo) { let location = info.location().unwrap(); // The current implementation always returns Some - let msg = match info.payload().downcast_ref::<&'static str>() { + let msg = match info.payload().downcast_ref::<&str>() { Some(s) => *s, None => match info.payload().downcast_ref::() { Some(s) => &s[..], @@ -319,6 +319,7 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] +#[cfg(stage0)] #[lang = "panic_fmt"] #[unwind(allowed)] pub extern fn rust_begin_panic(msg: fmt::Arguments, @@ -328,12 +329,22 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments, begin_panic_fmt(&msg, &(file, line, col)) } +/// Entry point of panic from the libcore crate. +#[cfg(not(test))] +#[cfg(not(stage0))] +#[panic_implementation] +#[unwind(allowed)] +pub fn rust_begin_panic(info: &PanicInfo) -> ! { + continue_panic_fmt(&info) +} + /// The entry point for panicking with a formatted message. /// /// This is designed to reduce the amount of code required at the call /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. +#[cfg(stage0)] #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] @@ -381,12 +392,92 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, } } +/// The entry point for panicking with a formatted message. +/// +/// This is designed to reduce the amount of code required at the call +/// site as much as possible (so that `panic!()` has as low an impact +/// on (e.g.) the inlining of other functions as possible), by moving +/// the actual formatting into this shared place. +#[cfg(not(stage0))] +#[unstable(feature = "libstd_sys_internals", + reason = "used by the panic! macro", + issue = "0")] +#[inline(never)] #[cold] +pub fn begin_panic_fmt(msg: &fmt::Arguments, + file_line_col: &(&'static str, u32, u32)) -> ! { + let (file, line, col) = *file_line_col; + let info = PanicInfo::internal_constructor( + Some(msg), + Location::internal_constructor(file, line, col), + ); + continue_panic_fmt(&info) +} + +#[cfg(not(stage0))] +fn continue_panic_fmt(info: &PanicInfo) -> ! { + use fmt::Write; + + // We do two allocations here, unfortunately. But (a) they're + // required with the current scheme, and (b) we don't handle + // panic + OOM properly anyway (see comment in begin_panic + // below). + + let loc = info.location().unwrap(); // The current implementation always returns Some + let file_line_col = (loc.file(), loc.line(), loc.column()); + rust_panic_with_hook( + &mut PanicPayload::new(info.payload(), info.message()), + info.message(), + &file_line_col); + + struct PanicPayload<'a> { + payload: &'a (Any + Send), + msg: Option<&'a fmt::Arguments<'a>>, + string: Option, + } + + impl<'a> PanicPayload<'a> { + fn new(payload: &'a (Any + Send), msg: Option<&'a fmt::Arguments<'a>>) -> PanicPayload<'a> { + PanicPayload { payload, msg, string: None } + } + + + fn fill(&mut self) -> Option<&mut String> { + if let Some(msg) = self.msg.take() { + Some(self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*msg)); + s + })) + } else { + None + } + } + } + + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + if let Some(string) = self.fill() { + let contents = mem::replace(string, String::new()); + Box::into_raw(Box::new(contents)) + } else { + // We can't go from &(Any+Send) to Box so the payload is lost here + struct NoPayload; + Box::into_raw(Box::new(NoPayload)) + } + } + + fn get(&mut self) -> &(Any + Send) { + self.payload + } + } +} + /// This is the entry point of panicking for panic!() and assert!(). #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { +pub fn begin_panic(msg: M, file_line_col: &(&str, u32, u32)) -> ! { // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If @@ -431,7 +522,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// abort or unwind. fn rust_panic_with_hook(payload: &mut BoxMeUp, message: Option<&fmt::Arguments>, - file_line_col: &(&'static str, u32, u32)) -> ! { + file_line_col: &(&str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; let panics = update_panic_count(1); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9b84713b0f9..7349745fefe 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -475,6 +475,9 @@ declare_features! ( // 'a: { break 'a; } (active, label_break_value, "1.28.0", Some(48594), None), + + // #[panic_implementation] + (active, panic_implementation, "1.28.0", Some(44489), None), ); declare_features! ( @@ -1069,6 +1072,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "attribute is currently unstable", cfg_fn!(wasm_custom_section))), + // RFC 2070 + ("panic_implementation", Normal, Gated(Stability::Unstable, + "panic_implementation", + "#[panic_implementation] is an unstable feature", + cfg_fn!(panic_implementation))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), diff --git a/src/test/compile-fail/duplicate_entry_error.rs b/src/test/compile-fail/duplicate_entry_error.rs index 485519e8c3d..176aa7cca53 100644 --- a/src/test/compile-fail/duplicate_entry_error.rs +++ b/src/test/compile-fail/duplicate_entry_error.rs @@ -14,9 +14,11 @@ #![feature(lang_items)] -#[lang = "panic_fmt"] -fn panic_fmt() -> ! { -//~^ ERROR: duplicate lang item found: `panic_fmt`. +use std::panic::PanicInfo; + +#[lang = "panic_impl"] +fn panic_impl(info: &PanicInfo) -> ! { +//~^ ERROR: duplicate lang item found: `panic_impl`. loop {} } diff --git a/src/test/compile-fail/feature-gate-panic-implementation.rs b/src/test/compile-fail/feature-gate-panic-implementation.rs new file mode 100644 index 00000000000..ae9fbc7b13b --- /dev/null +++ b/src/test/compile-fail/feature-gate-panic-implementation.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] //~ ERROR #[panic_implementation] is an unstable feature (see issue #44489) +fn panic(info: &PanicInfo) -> ! { + loop {} +} diff --git a/src/test/compile-fail/no_owned_box_lang_item.rs b/src/test/compile-fail/no_owned_box_lang_item.rs index 72eb687adc6..1c2bf1573dc 100644 --- a/src/test/compile-fail/no_owned_box_lang_item.rs +++ b/src/test/compile-fail/no_owned_box_lang_item.rs @@ -21,4 +21,4 @@ fn main() { #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +#[lang = "panic_impl"] fn panic_impl() -> ! { loop {} } diff --git a/src/test/compile-fail/panic-implementation-bad-signature-1.rs b/src/test/compile-fail/panic-implementation-bad-signature-1.rs new file mode 100644 index 00000000000..fec11fdbd7b --- /dev/null +++ b/src/test/compile-fail/panic-implementation-bad-signature-1.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic( + info: PanicInfo, //~ ERROR argument should be `&PanicInfo` +) -> () //~ ERROR return type should be `!` +{ +} diff --git a/src/test/compile-fail/panic-implementation-bad-signature-2.rs b/src/test/compile-fail/panic-implementation-bad-signature-2.rs new file mode 100644 index 00000000000..2a628c05699 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-bad-signature-2.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic( + info: &'static PanicInfo, //~ ERROR argument should be `&PanicInfo` +) -> ! +{ + loop {} +} diff --git a/src/test/compile-fail/panic-implementation-bad-signature-3.rs b/src/test/compile-fail/panic-implementation-bad-signature-3.rs new file mode 100644 index 00000000000..29337025b70 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-bad-signature-3.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic() -> ! { //~ ERROR function should have one argument + loop {} +} diff --git a/src/test/compile-fail/panic-implementation-duplicate.rs b/src/test/compile-fail/panic-implementation-duplicate.rs new file mode 100644 index 00000000000..017113af409 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-duplicate.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(lang_items)] +#![feature(panic_implementation)] +#![no_std] +#![no_main] + +use core::panic::PanicInfo; + +#[panic_implementation] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +#[lang = "panic_impl"] +fn panic2(info: &PanicInfo) -> ! { //~ ERROR duplicate lang item found: `panic_impl`. + loop {} +} diff --git a/src/test/compile-fail/panic-implementation-requires-panic-info.rs b/src/test/compile-fail/panic-implementation-requires-panic-info.rs new file mode 100644 index 00000000000..597f44d9832 --- /dev/null +++ b/src/test/compile-fail/panic-implementation-requires-panic-info.rs @@ -0,0 +1,26 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort +// error-pattern: language item required, but not found: `panic_info` + +#![feature(lang_items)] +#![feature(no_core)] +#![feature(panic_implementation)] +#![no_core] +#![no_main] + +#[panic_implementation] +fn panic() -> ! { + loop {} +} + +#[lang = "sized"] +trait Sized {} diff --git a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs index fbf70b3d3fe..d9848a554ab 100644 --- a/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/compile-fail/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -15,8 +15,10 @@ #![no_std] #![feature(lang_items)] -#[lang = "panic_fmt"] -fn panic_fmt() {} +use core::panic::PanicInfo; + +#[lang = "panic_impl"] +fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} #[lang = "eh_unwind_resume"] diff --git a/src/test/compile-fail/weak-lang-item.rs b/src/test/compile-fail/weak-lang-item.rs index 8579611b938..7b988c3595f 100644 --- a/src/test/compile-fail/weak-lang-item.rs +++ b/src/test/compile-fail/weak-lang-item.rs @@ -9,7 +9,7 @@ // except according to those terms. // aux-build:weak-lang-items.rs -// error-pattern: language item required, but not found: `panic_fmt` +// error-pattern: language item required, but not found: `panic_impl` // error-pattern: language item required, but not found: `eh_personality` // ignore-wasm32-bare compiled with panic=abort, personality not required diff --git a/src/test/ui/error-codes/E0152.rs b/src/test/ui/error-codes/E0152.rs index ae501b94e3f..8fbad7b3ff3 100644 --- a/src/test/ui/error-codes/E0152.rs +++ b/src/test/ui/error-codes/E0152.rs @@ -10,7 +10,7 @@ #![feature(lang_items)] -#[lang = "panic_fmt"] +#[lang = "panic_impl"] struct Foo; //~ ERROR E0152 fn main() { diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index f67022bd6d3..c7f5f362efb 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -1,4 +1,4 @@ -error[E0152]: duplicate lang item found: `panic_fmt`. +error[E0152]: duplicate lang item found: `panic_impl`. --> $DIR/E0152.rs:14:1 | LL | struct Foo; //~ ERROR E0152 -- cgit 1.4.1-3-g733a5 From eaef110890837283a1504eb200cab1eba03650ea Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 1 May 2018 03:02:39 +0200 Subject: format payload if possible instead of returning "Box" --- src/libstd/panicking.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 6bb098310de..1f80fb6f738 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -440,12 +440,11 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { PanicPayload { payload, msg, string: None } } - fn fill(&mut self) -> Option<&mut String> { - if let Some(msg) = self.msg.take() { + if let Some(msg) = self.msg.cloned() { Some(self.string.get_or_insert_with(|| { let mut s = String::new(); - drop(s.write_fmt(*msg)); + drop(s.write_fmt(msg)); s })) } else { @@ -459,6 +458,10 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { if let Some(string) = self.fill() { let contents = mem::replace(string, String::new()); Box::into_raw(Box::new(contents)) + } else if let Some(s) = self.payload.downcast_ref::<&str>() { + Box::into_raw(Box::new(s.to_owned())) + } else if let Some(s) = self.payload.downcast_ref::() { + Box::into_raw(Box::new(s.clone())) } else { // We can't go from &(Any+Send) to Box so the payload is lost here struct NoPayload; @@ -467,7 +470,11 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { } fn get(&mut self) -> &(Any + Send) { - self.payload + if let Some(s) = self.fill() { + s + } else { + self.payload + } } } } -- cgit 1.4.1-3-g733a5 From 430ad769008c0aaa40949a1d98a6f0e18e35ec65 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 16 May 2018 14:07:58 +0200 Subject: undo payload in core::panic! changes --- src/libcore/macros.rs | 22 ---------- src/libcore/panicking.rs | 32 +++----------- src/libstd/panicking.rs | 109 +++++++++++++---------------------------------- 3 files changed, 37 insertions(+), 126 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f98626d939d..c830c22ee5f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -9,7 +9,6 @@ // except according to those terms. /// Entry point of thread panic, for details, see std::macros -#[cfg(stage0)] #[macro_export] #[allow_internal_unstable] #[stable(feature = "core", since = "1.6.0")] @@ -29,27 +28,6 @@ macro_rules! panic { }); } -/// Entry point of thread panic, for details, see std::macros -#[cfg(not(stage0))] -#[macro_export] -#[allow_internal_unstable] -#[stable(feature = "core", since = "1.6.0")] -macro_rules! panic { - () => ( - panic!("explicit panic") - ); - ($msg:expr) => ({ - $crate::panicking::panic_payload($msg, &(file!(), line!(), __rust_unstable_column!())) - }); - ($msg:expr,) => ( - panic!($msg) - ); - ($fmt:expr, $($arg:tt)+) => ({ - $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), - &(file!(), line!(), __rust_unstable_column!())) - }); -} - /// Asserts that two expressions are equal to each other (using [`PartialEq`]). /// /// On panic, this macro will print the values of the expressions with their diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 4b4fa73c478..0d4f8d1141e 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -36,35 +36,10 @@ and related macros", issue = "0")] -#[cfg(not(stage0))] -use any::Any; use fmt; #[cfg(not(stage0))] use panic::{Location, PanicInfo}; -// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call -#[cfg(not(stage0))] -#[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe -extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo) -> !; -} - -#[cfg(not(stage0))] -#[cold] #[inline(never)] -pub fn panic_payload(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! -where - M: Any + Send, -{ - let (file, line, col) = *file_line_col; - let mut pi = PanicInfo::internal_constructor( - None, - Location::internal_constructor(file, line, col), - ); - pi.set_payload(&msg); - unsafe { panic_impl(&pi) } -} - #[cold] #[inline(never)] // this is the slow path, always #[lang = "panic"] pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { @@ -102,6 +77,13 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) #[cfg(not(stage0))] #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo) -> !; + } + let (file, line, col) = *file_line_col; let pi = PanicInfo::internal_constructor( Some(&fmt), diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 1f80fb6f738..9d8052143b9 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -186,7 +186,7 @@ fn default_hook(info: &PanicInfo) { let location = info.location().unwrap(); // The current implementation always returns Some - let msg = match info.payload().downcast_ref::<&str>() { + let msg = match info.payload().downcast_ref::<&'static str>() { Some(s) => *s, None => match info.payload().downcast_ref::() { Some(s) => &s[..], @@ -351,44 +351,45 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { #[inline(never)] #[cold] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - use fmt::Write; - // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic // below). rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); +} + +// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update +struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option, +} - struct PanicPayload<'a> { - inner: &'a fmt::Arguments<'a>, - string: Option, +impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } } - impl<'a> PanicPayload<'a> { - fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { - PanicPayload { inner, string: None } - } + fn fill(&mut self) -> &mut String { + use fmt::Write; - fn fill(&mut self) -> &mut String { - let inner = self.inner; - self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(*inner)); - s - }) - } + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) } +} - unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { - let contents = mem::replace(self.fill(), String::new()); - Box::into_raw(Box::new(contents)) - } +unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } - fn get(&mut self) -> &(Any + Send) { - self.fill() - } + fn get(&mut self) -> &(Any + Send) { + self.fill() } } @@ -415,68 +416,18 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, #[cfg(not(stage0))] fn continue_panic_fmt(info: &PanicInfo) -> ! { - use fmt::Write; - // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic // below). let loc = info.location().unwrap(); // The current implementation always returns Some + let msg = info.message().unwrap(); // The current implementation always returns Some let file_line_col = (loc.file(), loc.line(), loc.column()); rust_panic_with_hook( - &mut PanicPayload::new(info.payload(), info.message()), + &mut PanicPayload::new(msg), info.message(), &file_line_col); - - struct PanicPayload<'a> { - payload: &'a (Any + Send), - msg: Option<&'a fmt::Arguments<'a>>, - string: Option, - } - - impl<'a> PanicPayload<'a> { - fn new(payload: &'a (Any + Send), msg: Option<&'a fmt::Arguments<'a>>) -> PanicPayload<'a> { - PanicPayload { payload, msg, string: None } - } - - fn fill(&mut self) -> Option<&mut String> { - if let Some(msg) = self.msg.cloned() { - Some(self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(msg)); - s - })) - } else { - None - } - } - } - - unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { - if let Some(string) = self.fill() { - let contents = mem::replace(string, String::new()); - Box::into_raw(Box::new(contents)) - } else if let Some(s) = self.payload.downcast_ref::<&str>() { - Box::into_raw(Box::new(s.to_owned())) - } else if let Some(s) = self.payload.downcast_ref::() { - Box::into_raw(Box::new(s.clone())) - } else { - // We can't go from &(Any+Send) to Box so the payload is lost here - struct NoPayload; - Box::into_raw(Box::new(NoPayload)) - } - } - - fn get(&mut self) -> &(Any + Send) { - if let Some(s) = self.fill() { - s - } else { - self.payload - } - } - } } /// This is the entry point of panicking for panic!() and assert!(). @@ -484,7 +435,7 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -pub fn begin_panic(msg: M, file_line_col: &(&str, u32, u32)) -> ! { +pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If -- cgit 1.4.1-3-g733a5 From 4c84d382ed87521a5b98b30f508366111dbbc7d5 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 16 May 2018 19:56:24 +0200 Subject: remove #[unwind(allowed)] not required because this is a Rust function --- src/libstd/panicking.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 9d8052143b9..0808efa2ece 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -321,7 +321,6 @@ pub fn panicking() -> bool { #[cfg(not(test))] #[cfg(stage0)] #[lang = "panic_fmt"] -#[unwind(allowed)] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, -- cgit 1.4.1-3-g733a5 From 33c4b37d00985f8f12796ef1b0b8ff97a4f3db99 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 4 Jun 2018 08:58:55 +0200 Subject: Clarify error phrase in `sub_instant` function Uses the same wording as [`src/libstd/sys/windows/time.rs`][1]. 1: https://github.com/avdv/rust/blob/95e2bf253d864c5e14ad000ffa2040ce85916056/src/libstd/sys/windows/time.rs#L65 --- src/libstd/sys/redox/time.rs | 2 +- src/libstd/sys/unix/time.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index cf798500b7f..5c491115c55 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -144,7 +144,7 @@ impl Instant { pub fn sub_instant(&self, other: &Instant) -> Duration { self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("other was less than the current instant") + panic!("specified instant was later than self") }) } diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index f7459cb55d5..89786eb2a6c 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -289,7 +289,7 @@ mod inner { pub fn sub_instant(&self, other: &Instant) -> Duration { self.t.sub_timespec(&other.t).unwrap_or_else(|_| { - panic!("other was greater than the current instant") + panic!("specified instant was later than self") }) } -- cgit 1.4.1-3-g733a5 From ded5c5a9eeb83ea7ec3c572a601afaaca6a3d9e6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 3 Jun 2018 00:45:49 +0200 Subject: Put doc keyword behind feature flag --- src/libstd/lib.rs | 1 + src/libsyntax/feature_gate.rs | 8 ++++++++ src/test/rustdoc/keyword.rs | 2 ++ 3 files changed, 11 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c576245edb7..8266cec5139 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -316,6 +316,7 @@ #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] #![feature(doc_alias)] +#![feature(doc_keyword)] #![feature(float_internals)] #![feature(panic_info_message)] #![cfg_attr(not(stage0), feature(panic_implementation))] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7349745fefe..51788b6063a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -476,8 +476,12 @@ declare_features! ( // 'a: { break 'a; } (active, label_break_value, "1.28.0", Some(48594), None), + // #[panic_implementation] (active, panic_implementation, "1.28.0", Some(44489), None), + + // #[doc(keyword = "...")] + (active, doc_keyword, "1.28.0", Some(51315), None), ); declare_features! ( @@ -1506,6 +1510,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, doc_alias, attr.span, "#[doc(alias = \"...\")] is experimental" ); + } else if content.iter().any(|c| c.check_name("keyword")) { + gate_feature_post!(&self, doc_keyword, attr.span, + "#[doc(keyword = \"...\")] is experimental" + ); } } } diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs index 5682fce7808..06ebf15d364 100644 --- a/src/test/rustdoc/keyword.rs +++ b/src/test/rustdoc/keyword.rs @@ -10,6 +10,8 @@ #![crate_name = "foo"] +#![feature(doc_keyword)] + // @has foo/index.html '//h2[@id="keywords"]' 'Keywords' // @has foo/index.html '//a[@href="keyword.match.html"]' 'match' // @has foo/keyword.match.html '//a[@class="keyword"]' 'match' -- cgit 1.4.1-3-g733a5 From b69724f37cca68249340e7245e5ac2832d8b2c30 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 4 Jun 2018 09:22:07 +0100 Subject: Optimize layout calculations in HashMap This now produces the same assembly code as the previous implementation. --- src/libstd/collections/hash/table.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index c62a409ac02..d997fb28d42 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -15,6 +15,7 @@ use mem::{size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, NonNull}; +use hint; use self::BucketState::*; @@ -655,7 +656,17 @@ impl GapThenFull fn calculate_layout(capacity: usize) -> Result<(Layout, usize), LayoutErr> { let hashes = Layout::array::(capacity)?; let pairs = Layout::array::<(K, V)>(capacity)?; - hashes.extend(pairs) + hashes.extend(pairs).map(|(layout, _)| { + // LLVM seems to have trouble properly const-propagating pairs.align(), + // possibly due to the use of NonZeroUsize. This little hack allows it + // to generate optimal code. + // + // See https://github.com/rust-lang/rust/issues/51346 for more details. + ( + layout, + hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()), + ) + }) } pub(crate) enum Fallibility { @@ -711,7 +722,8 @@ impl RawTable { } fn raw_bucket_at(&self, index: usize) -> RawBucket { - let (_, pairs_offset) = calculate_layout::(self.capacity()).unwrap(); + let (_, pairs_offset) = calculate_layout::(self.capacity()) + .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { @@ -1109,7 +1121,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { } } - let (layout, _) = calculate_layout::(self.capacity()).unwrap(); + let (layout, _) = calculate_layout::(self.capacity()) + .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); unsafe { Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); // Remember how everything was allocated out of one buffer -- cgit 1.4.1-3-g733a5 From e7c122c5b58d4db2262b1f4325d9fe82d1423ad8 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 Jun 2018 12:54:25 +0200 Subject: Revert "Remove TryFrom impls that might become conditionally-infallible with a portability lint" This reverts commit 837d6c70233715a0ae8e15c703d40e3046a2f36a. Fixes https://github.com/rust-lang/rust/issues/49415 --- src/libcore/iter/range.rs | 75 +------------------------ src/libcore/num/mod.rs | 70 ++++++++++++++++++++---- src/libcore/tests/num/mod.rs | 127 +++++++++++++++++++++++++++++++++++++++++++ src/libstd/io/cursor.rs | 20 +------ 4 files changed, 191 insertions(+), 101 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 5896322f111..0b279f66b88 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -91,7 +91,7 @@ macro_rules! step_impl_unsigned { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$t>::private_try_from(n) { + match <$t>::try_from(n) { Ok(n_as_t) => self.checked_add(n_as_t), Err(_) => None, } @@ -123,7 +123,7 @@ macro_rules! step_impl_signed { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$unsigned>::private_try_from(n) { + match <$unsigned>::try_from(n) { Ok(n_as_unsigned) => { // Wrapping in unsigned space handles cases like // `-120_i8.add_usize(200) == Some(80_i8)`, @@ -461,74 +461,3 @@ impl DoubleEndedIterator for ops::RangeInclusive { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} - -/// Compensate removal of some impls per -/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 -trait PrivateTryFromUsize: Sized { - fn private_try_from(n: usize) -> Result; -} - -impl PrivateTryFromUsize for T where T: TryFrom { - #[inline] - fn private_try_from(n: usize) -> Result { - T::try_from(n).map_err(|_| ()) - } -} - -// no possible bounds violation -macro_rules! try_from_unbounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(value: usize) -> Result { - Ok(value as $target) - } - } - )*} -} - -// unsigned to signed (only positive bound) -#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] -macro_rules! try_from_upper_bounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(u: usize) -> Result<$target, ()> { - if u > (<$target>::max_value() as usize) { - Err(()) - } else { - Ok(u as $target) - } - } - } - )*} -} - - -#[cfg(target_pointer_width = "16")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_unbounded!(u16, u32, u64, u128); - try_from_unbounded!(i32, i64, i128); -} - -#[cfg(target_pointer_width = "32")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16); - try_from_unbounded!(u32, u64, u128); - try_from_upper_bounded!(i32); - try_from_unbounded!(i64, i128); -} - -#[cfg(target_pointer_width = "64")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16, u32); - try_from_unbounded!(u64, u128); - try_from_upper_bounded!(i32, i64); - try_from_unbounded!(i128); -} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 26dd08b10b9..2389f6d4e1f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -4413,6 +4413,21 @@ impl From for TryFromIntError { } } +// no possible bounds violation +macro_rules! try_from_unbounded { + ($source:ty, $($target:ty),*) => {$( + #[unstable(feature = "try_from", issue = "33417")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + #[inline] + fn try_from(value: $source) -> Result { + Ok(value as $target) + } + } + )*} +} + // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( @@ -4511,20 +4526,27 @@ try_from_both_bounded!(i128, u64, u32, u16, u8); try_from_upper_bounded!(usize, isize); try_from_lower_bounded!(isize, usize); -try_from_upper_bounded!(usize, u8); -try_from_upper_bounded!(usize, i8, i16); -try_from_both_bounded!(isize, u8); -try_from_both_bounded!(isize, i8); - #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs + try_from_upper_bounded!(usize, u8); + try_from_unbounded!(usize, u16, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16); + try_from_unbounded!(usize, i32, i64, i128); + + try_from_both_bounded!(isize, u8); try_from_lower_bounded!(isize, u16, u32, u64, u128); + try_from_both_bounded!(isize, i8); + try_from_unbounded!(isize, i16, i32, i64, i128); + + rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); + + rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); + rev!(try_from_both_bounded, isize, i32, i64, i128); } #[cfg(target_pointer_width = "32")] @@ -4532,11 +4554,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16); + try_from_upper_bounded!(usize, u8, u16); + try_from_unbounded!(usize, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32); + try_from_unbounded!(usize, i64, i128); + + try_from_both_bounded!(isize, u8, u16); try_from_lower_bounded!(isize, u32, u64, u128); + try_from_both_bounded!(isize, i8, i16); + try_from_unbounded!(isize, i32, i64, i128); + + rev!(try_from_unbounded, usize, u32); + rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); + + rev!(try_from_unbounded, isize, u16); + rev!(try_from_upper_bounded, isize, u32, u64, u128); + rev!(try_from_unbounded, isize, i32); + rev!(try_from_both_bounded, isize, i64, i128); } #[cfg(target_pointer_width = "64")] @@ -4544,11 +4580,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16, u32); + try_from_upper_bounded!(usize, u8, u16, u32); + try_from_unbounded!(usize, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32, i64); + try_from_unbounded!(usize, i128); + + try_from_both_bounded!(isize, u8, u16, u32); try_from_lower_bounded!(isize, u64, u128); + try_from_both_bounded!(isize, i8, i16, i32); + try_from_unbounded!(isize, i64, i128); + + rev!(try_from_unbounded, usize, u32, u64); + rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); + + rev!(try_from_unbounded, isize, u16, u32); + rev!(try_from_upper_bounded, isize, u64, u128); + rev!(try_from_unbounded, isize, i32, i64); + rev!(try_from_both_bounded, isize, i128); } #[doc(hidden)] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index b5e6a019a22..00aed25aa1a 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -37,6 +37,15 @@ mod flt2dec; mod dec2flt; mod bignum; + +/// Adds the attribute to all items in the block. +macro_rules! cfg_block { + ($(#[$attr:meta]{$($it:item)*})*) => {$($( + #[$attr] + $it + )*)*} +} + /// Groups items that assume the pointer width is either 16/32/64, and has to be altered if /// support for larger/smaller pointer widths are added in the future. macro_rules! assume_usize_width { @@ -330,6 +339,42 @@ assume_usize_width! { test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + + test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } + test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } + test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } + + test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } + test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } + test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } + test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } + } + ); } /// Conversions where max of $source can be represented as $target, @@ -378,6 +423,24 @@ assume_usize_width! { test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } + } + ); } /// Conversions where max of $source can not be represented as $target, @@ -419,9 +482,29 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } assume_usize_width! { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } + } + ); } /// Conversions where min/max of $source can not be represented as $target. @@ -481,6 +564,34 @@ test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } assume_usize_width! { test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } + test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } + test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + + test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } + + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } + } + ); } /// Conversions where neither the min nor the max of $source can be represented by @@ -525,6 +636,22 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } assume_usize_width! { test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } + + cfg_block! { + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + } + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + } + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } + } + } } macro_rules! test_float { diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 8ac52572810..aadd33b3954 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -10,6 +10,7 @@ use io::prelude::*; +use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; @@ -259,26 +260,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result Result { - if n <= (::max_value() as u64) { - Ok(n as usize) - } else { - Err(()) - } -} - -#[cfg(any(target_pointer_width = "64"))] -fn try_into(n: u64) -> Result { - Ok(n as usize) -} - // Resizing write implementation fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result { - let pos: usize = try_into(*pos_mut).map_err(|_| { + let pos: usize = (*pos_mut).try_into().map_err(|_| { Error::new(ErrorKind::InvalidInput, "cursor position exceeds maximum possible vector length") })?; -- cgit 1.4.1-3-g733a5 From a6055c885917093faf37bcb834350df7b6ddca82 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 30 May 2018 18:23:10 -0700 Subject: Add Future and task system to the standard library --- src/liballoc/boxed.rs | 93 +++++++ src/liballoc/lib.rs | 6 + src/liballoc/task.rs | 140 +++++++++++ src/libcore/future.rs | 93 +++++++ src/libcore/lib.rs | 5 + src/libcore/task.rs | 513 +++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 16 ++ src/test/run-pass/futures-api.rs | 95 ++++++++ 8 files changed, 961 insertions(+) create mode 100644 src/liballoc/task.rs create mode 100644 src/libcore/future.rs create mode 100644 src/libcore/task.rs create mode 100644 src/test/run-pass/futures-api.rs (limited to 'src/libstd') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index a83ce7f379f..a64b94b6517 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -59,12 +59,14 @@ use core::any::Any; use core::borrow; use core::cmp::Ordering; use core::fmt; +use core::future::Future; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; +use core::task::{Context, Poll, UnsafePoll, TaskObj}; use core::convert::From; use raw_vec::RawVec; @@ -755,6 +757,7 @@ impl Generator for Box /// A pinned, heap allocated reference. #[unstable(feature = "pin", issue = "49150")] #[fundamental] +#[repr(transparent)] pub struct PinBox { inner: Box, } @@ -771,14 +774,72 @@ impl PinBox { #[unstable(feature = "pin", issue = "49150")] impl PinBox { /// Get a pinned reference to the data in this PinBox. + #[inline] pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> { unsafe { PinMut::new_unchecked(&mut *self.inner) } } + /// Constructs a `PinBox` from a raw pointer. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `PinBox`. Specifically, the `PinBox` destructor will call + /// the destructor of `T` and free the allocated memory. Since the + /// way `PinBox` allocates and releases memory is unspecified, the + /// only valid pointer to pass to this function is the one taken + /// from another `PinBox` via the [`PinBox::into_raw`] function. + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// [`PinBox::into_raw`]: struct.PinBox.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(pin)] + /// use std::boxed::PinBox; + /// let x = PinBox::new(5); + /// let ptr = PinBox::into_raw(x); + /// let x = unsafe { PinBox::from_raw(ptr) }; + /// ``` + #[inline] + pub unsafe fn from_raw(raw: *mut T) -> Self { + PinBox { inner: Box::from_raw(raw) } + } + + /// Consumes the `PinBox`, returning the wrapped raw pointer. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `PinBox`. In particular, the + /// caller should properly destroy `T` and release the memory. The + /// proper way to do so is to convert the raw pointer back into a + /// `PinBox` with the [`PinBox::from_raw`] function. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `PinBox::into_raw(b)` instead of `b.into_raw()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// [`PinBox::from_raw`]: struct.PinBox.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(pin)] + /// use std::boxed::PinBox; + /// let x = PinBox::new(5); + /// let ptr = PinBox::into_raw(x); + /// ``` + #[inline] + pub fn into_raw(b: PinBox) -> *mut T { + Box::into_raw(b.inner) + } + /// Get a mutable reference to the data inside this PinBox. /// /// This function is unsafe. Users must guarantee that the data is never /// moved out of this reference. + #[inline] pub unsafe fn get_mut<'a>(this: &'a mut PinBox) -> &'a mut T { &mut *this.inner } @@ -787,6 +848,7 @@ impl PinBox { /// /// This function is unsafe. Users must guarantee that the data is never /// moved out of the box. + #[inline] pub unsafe fn unpin(this: PinBox) -> Box { this.inner } @@ -851,3 +913,34 @@ impl, U: ?Sized> CoerceUnsized> for PinBox {} #[unstable(feature = "pin", issue = "49150")] impl Unpin for PinBox {} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl + Send + 'static> UnsafePoll for PinBox { + fn into_raw(self) -> *mut () { + PinBox::into_raw(self) as *mut () + } + + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { + let ptr = task as *mut F; + let pin: PinMut = PinMut::new_unchecked(&mut *ptr); + pin.poll(cx) + } + + unsafe fn drop(task: *mut ()) { + drop(PinBox::from_raw(task as *mut F)) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl + Send + 'static> From> for TaskObj { + fn from(boxed: PinBox) -> Self { + TaskObj::from_poll_task(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl + Send + 'static> From> for TaskObj { + fn from(boxed: Box) -> Self { + TaskObj::from_poll_task(PinBox::from(boxed)) + } +} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 91de3ad0c39..e0729d3a467 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -95,6 +95,7 @@ #![feature(fmt_internals)] #![feature(from_ref)] #![feature(fundamental)] +#![feature(futures_api)] #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] @@ -103,6 +104,7 @@ #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] +#![feature(repr_transparent)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] #![feature(specialization)] @@ -156,6 +158,10 @@ pub mod heap { pub use alloc::*; } +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod task; // Primitive types using the heaps above diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs new file mode 100644 index 00000000000..7b1947b56b8 --- /dev/null +++ b/src/liballoc/task.rs @@ -0,0 +1,140 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Types and Traits for working with asynchronous tasks. + +pub use core::task::*; + +#[cfg(target_has_atomic = "ptr")] +pub use self::if_arc::*; + +#[cfg(target_has_atomic = "ptr")] +mod if_arc { + use super::*; + use arc::Arc; + use core::marker::PhantomData; + use core::mem; + use core::ptr::{self, NonNull}; + + /// A way of waking up a specific task. + /// + /// Any task executor must provide a way of signaling that a task it owns + /// is ready to be `poll`ed again. Executors do so by implementing this trait. + pub trait Wake: Send + Sync { + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake` should place + /// the associated task onto this queue. + fn wake(arc_self: &Arc); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. This function is like `wake`, but can only be called from the + /// thread on which this `Wake` was created. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place + /// the associated task onto this queue. + #[inline] + unsafe fn wake_local(arc_self: &Arc) { + Self::wake(arc_self); + } + } + + #[cfg(target_has_atomic = "ptr")] + struct ArcWrapped(PhantomData); + + unsafe impl UnsafeWake for ArcWrapped { + #[inline] + unsafe fn clone_raw(&self) -> Waker { + let me: *const ArcWrapped = self; + let arc = (*(&me as *const *const ArcWrapped as *const Arc)).clone(); + Waker::from(arc) + } + + #[inline] + unsafe fn drop_raw(&self) { + let mut me: *const ArcWrapped = self; + let me = &mut me as *mut *const ArcWrapped as *mut Arc; + ptr::drop_in_place(me); + } + + #[inline] + unsafe fn wake(&self) { + let me: *const ArcWrapped = self; + T::wake(&*(&me as *const *const ArcWrapped as *const Arc)) + } + + #[inline] + unsafe fn wake_local(&self) { + let me: *const ArcWrapped = self; + T::wake_local(&*(&me as *const *const ArcWrapped as *const Arc)) + } + } + + impl From> for Waker + where T: Wake + 'static, + { + fn from(rc: Arc) -> Self { + unsafe { + let ptr = mem::transmute::, NonNull>>(rc); + Waker::new(ptr) + } + } + } + + /// Creates a `LocalWaker` from a local `wake`. + /// + /// This function requires that `wake` is "local" (created on the current thread). + /// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and + /// will call `wake.wake()` if awoken after being converted to a `Waker`. + #[inline] + pub unsafe fn local_waker(wake: Arc) -> LocalWaker { + let ptr = mem::transmute::, NonNull>>(wake); + LocalWaker::new(ptr) + } + + struct NonLocalAsLocal(ArcWrapped); + + unsafe impl UnsafeWake for NonLocalAsLocal { + #[inline] + unsafe fn clone_raw(&self) -> Waker { + self.0.clone_raw() + } + + #[inline] + unsafe fn drop_raw(&self) { + self.0.drop_raw() + } + + #[inline] + unsafe fn wake(&self) { + self.0.wake() + } + + #[inline] + unsafe fn wake_local(&self) { + // Since we're nonlocal, we can't call wake_local + self.0.wake() + } + } + + /// Creates a `LocalWaker` from a non-local `wake`. + /// + /// This function is similar to `local_waker`, but does not require that `wake` + /// is local to the current thread. The resulting `LocalWaker` will call + /// `wake.wake()` when awoken. + #[inline] + pub fn local_waker_from_nonlocal(wake: Arc) -> LocalWaker { + unsafe { + let ptr = mem::transmute::, NonNull>>(wake); + LocalWaker::new(ptr) + } + } +} diff --git a/src/libcore/future.rs b/src/libcore/future.rs new file mode 100644 index 00000000000..b4d087f8edb --- /dev/null +++ b/src/libcore/future.rs @@ -0,0 +1,93 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Asynchronous values. + +use mem::PinMut; +use task::{self, Poll}; + +/// A future represents an asychronous computation. +/// +/// A future is a value that may not have finished computing yet. This kind of +/// "asynchronous value" makes it possible for a thread to continue doing useful +/// work while it waits for the value to become available. +/// +/// # The `poll` method +/// +/// The core method of future, `poll`, *attempts* to resolve the future into a +/// final value. This method does not block if the value is not ready. Instead, +/// the current task is scheduled to be woken up when it's possible to make +/// further progress by `poll`ing again. The wake up is performed using +/// `cx.waker()`, a handle for waking up the current task. +/// +/// When using a future, you generally won't call `poll` directly, but instead +/// `await!` the value. +pub trait Future { + /// The result of the `Future`. + type Output; + + /// Attempt to resolve the future to a final value, registering + /// the current task for wakeup if the value is not yet available. + /// + /// # Return value + /// + /// This function returns: + /// + /// - `Poll::Pending` if the future is not ready yet + /// - `Poll::Ready(val)` with the result `val` of this future if it finished + /// successfully. + /// + /// Once a future has finished, clients should not `poll` it again. + /// + /// When a future is not ready yet, `poll` returns + /// [`Poll::Pending`](::task::Poll). The future will *also* register the + /// interest of the current task in the value being produced. For example, + /// if the future represents the availability of data on a socket, then the + /// task is recorded so that when data arrives, it is woken up (via + /// [`cx.waker()`](::task::Context::waker)). Once a task has been woken up, + /// it should attempt to `poll` the future again, which may or may not + /// produce a final value. + /// + /// Note that if `Pending` is returned it only means that the *current* task + /// (represented by the argument `cx`) will receive a notification. Tasks + /// from previous calls to `poll` will *not* receive notifications. + /// + /// # Runtime characteristics + /// + /// Futures alone are *inert*; they must be *actively* `poll`ed to make + /// progress, meaning that each time the current task is woken up, it should + /// actively re-`poll` pending futures that it still has an interest in. + /// + /// The `poll` function is not called repeatedly in a tight loop for + /// futures, but only whenever the future itself is ready, as signaled via + /// the `Waker` inside `task::Context`. If you're familiar with the + /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures + /// typically do *not* suffer the same problems of "all wakeups must poll + /// all events"; they are more like `epoll(4)`. + /// + /// An implementation of `poll` should strive to return quickly, and must + /// *never* block. Returning quickly prevents unnecessarily clogging up + /// threads or event loops. If it is known ahead of time that a call to + /// `poll` may end up taking awhile, the work should be offloaded to a + /// thread pool (or something similar) to ensure that `poll` can return + /// quickly. + /// + /// # Panics + /// + /// Once a future has completed (returned `Ready` from `poll`), + /// then any future calls to `poll` may panic, block forever, or otherwise + /// cause bad behavior. The `Future` trait itself provides no guarantees + /// about the behavior of `poll` after a future has completed. + fn poll(self: PinMut, cx: &mut task::Context) -> Poll; +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 32cf31231c3..38a769cd11a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,6 +100,7 @@ #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] +#![feature(repr_transparent)] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] @@ -206,6 +207,10 @@ pub mod time; pub mod unicode; +/* Async */ +pub mod future; +pub mod task; + /* Heap memory allocator trait */ #[allow(missing_docs)] pub mod alloc; diff --git a/src/libcore/task.rs b/src/libcore/task.rs new file mode 100644 index 00000000000..e46a6d41d7a --- /dev/null +++ b/src/libcore/task.rs @@ -0,0 +1,513 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Types and Traits for working with asynchronous tasks. + +use fmt; +use ptr::NonNull; + +/// Indicates whether a value is available or if the current task has been +/// scheduled to receive a wakeup instead. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Poll { + /// Represents that a value is immediately ready. + Ready(T), + + /// Represents that a value is not ready yet. + /// + /// When a function returns `Pending`, the function *must* also + /// ensure that the current task is scheduled to be awoken when + /// progress can be made. + Pending, +} + +/// A `Waker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This handle contains a trait object pointing to an instance of the `UnsafeWake` +/// trait, allowing notifications to get routed through it. +#[repr(transparent)] +pub struct Waker { + inner: NonNull, +} + +unsafe impl Send for Waker {} +unsafe impl Sync for Waker {} + +impl Waker { + /// Constructs a new `Waker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `Waker::from` function instead which works with the safe + /// `Arc` type and the safe `Wake` trait. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + Waker { inner: inner } + } + + /// Wake up the task associated with this `Waker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake() } + } + + /// Returns whether or not this `Waker` and `other` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `Waker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl Clone for Waker { + #[inline] + fn clone(&self) -> Self { + unsafe { + self.inner.as_ref().clone_raw() + } + } +} + +impl fmt::Debug for Waker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for Waker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This is similar to the `Waker` type, but cannot be sent across threads. +/// Task executors can use this type to implement more optimized singlethreaded wakeup +/// behavior. +#[repr(transparent)] +pub struct LocalWaker { + inner: NonNull, +} + +impl !Send for LocalWaker {} +impl !Sync for LocalWaker {} + +impl LocalWaker { + /// Constructs a new `LocalWaker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `LocalWaker::from` function instead which works with the safe + /// `Rc` type and the safe `LocalWake` trait. + /// + /// For this function to be used safely, it must be sound to call `inner.wake_local()` + /// on the current thread. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + LocalWaker { inner: inner } + } + + /// Wake up the task associated with this `LocalWaker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake_local() } + } + + /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `LocalWaker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &LocalWaker) -> bool { + self.inner == other.inner + } + + /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake_nonlocal(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl From for Waker { + #[inline] + fn from(local_waker: LocalWaker) -> Self { + Waker { inner: local_waker.inner } + } +} + +impl Clone for LocalWaker { + #[inline] + fn clone(&self) -> Self { + unsafe { + LocalWaker { inner: self.inner.as_ref().clone_raw().inner } + } + } +} + +impl fmt::Debug for LocalWaker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for LocalWaker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`. +/// +/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is +/// most often essentially just `Arc`. However, in some contexts +/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some +/// custom memory management strategy. This trait is designed to allow for such +/// customization. +/// +/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for +/// `Arc` where `T: Wake` and `Rc` where `T: LocalWake`. +/// +/// Although the methods on `UnsafeWake` take pointers rather than references, +pub unsafe trait UnsafeWake: Send + Sync { + /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`. + /// + /// This function will create a new uniquely owned handle that under the + /// hood references the same notification instance. In other words calls + /// to `wake` on the returned handle should be equivalent to calls to + /// `wake` on this handle. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn clone_raw(&self) -> Waker; + + /// Drops this instance of `UnsafeWake`, deallocating resources + /// associated with it. + /// + /// FIXME(cramertj) + /// This method is intended to have a signature such as: + /// + /// ```ignore (not-a-doctest) + /// fn drop_raw(self: *mut Self); + /// ``` + /// + /// Unfortunately in Rust today that signature is not object safe. + /// Nevertheless it's recommended to implement this function *as if* that + /// were its signature. As such it is not safe to call on an invalid + /// pointer, nor is the validity of the pointer guaranteed after this + /// function returns. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn drop_raw(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn wake(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. This function is the same as `wake`, but can only be called + /// from the thread that this `UnsafeWake` is "local" to. This allows for + /// implementors to provide specialized wakeup behavior specific to the current + /// thread. This function is called by `LocalWaker::wake`. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped, and that the + /// `UnsafeWake` hasn't moved from the thread on which it was created. + unsafe fn wake_local(&self) { + self.wake() + } +} + +/// Information about the currently-running task. +/// +/// Contexts are always tied to the stack, since they are set up specifically +/// when performing a single `poll` step on a task. +pub struct Context<'a> { + local_waker: &'a LocalWaker, + executor: &'a mut Executor, +} + +impl<'a> fmt::Debug for Context<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Context") + .finish() + } +} + +impl<'a> Context<'a> { + /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. + #[inline] + pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { + Context { + local_waker, + executor, + } + } + + /// Get the `LocalWaker` associated with the current task. + #[inline] + pub fn local_waker(&self) -> &'a LocalWaker { + self.local_waker + } + + /// Get the `Waker` associated with the current task. + #[inline] + pub fn waker(&self) -> &'a Waker { + unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) } + } + + /// Get the default executor associated with this task. + /// + /// This method is useful primarily if you want to explicitly handle + /// spawn failures. + #[inline] + pub fn executor(&mut self) -> &mut Executor { + self.executor + } + + /// Produce a context like the current one, but using the given waker instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task, where you want to provide some customized + /// wakeup logic. + #[inline] + pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> { + Context { + local_waker, + executor: self.executor, + } + } + + /// Produce a context like the current one, but using the given executor + /// instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task. + #[inline] + pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> + where E: Executor + { + Context { + local_waker: self.local_waker, + executor: executor, + } + } +} + +/// A task executor. +/// +/// A *task* is a `()`-producing async value that runs at the top level, and will +/// be `poll`ed until completion. It's also the unit at which wake-up +/// notifications occur. Executors, such as thread pools, allow tasks to be +/// spawned and are responsible for putting tasks onto ready queues when +/// they are woken up, and polling them when they are ready. +pub trait Executor { + /// Spawn the given task, polling it until completion. + /// + /// # Errors + /// + /// The executor may be unable to spawn tasks, either because it has + /// been shut down or is resource-constrained. + fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>; + + /// Determine whether the executor is able to spawn new tasks. + /// + /// # Returns + /// + /// An `Ok` return means the executor is *likely* (but not guaranteed) + /// to accept a subsequent spawn attempt. Likewise, an `Err` return + /// means that `spawn` is likely, but not guaranteed, to yield an error. + #[inline] + fn status(&self) -> Result<(), SpawnErrorKind> { + Ok(()) + } +} + +/// A custom trait object for polling tasks, roughly akin to +/// `Box + Send>`. +pub struct TaskObj { + ptr: *mut (), + poll: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop: unsafe fn(*mut ()), +} + +impl fmt::Debug for TaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TaskObj") + .finish() + } +} + +unsafe impl Send for TaskObj {} +unsafe impl Sync for TaskObj {} + +/// A custom implementation of a task trait object for `TaskObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafePoll: Send + 'static { + /// Convert a owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to `drop`. + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; + + /// Drops the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(task: *mut ()); +} + +impl TaskObj { + /// Create a `TaskObj` from a custom trait object representation. + #[inline] + pub fn from_poll_task(t: T) -> TaskObj { + TaskObj { + ptr: t.into_raw(), + poll: T::poll, + drop: T::drop, + } + } + + /// Poll the task. + /// + /// The semantics here are identical to that for futures, but unlike + /// futures only an `&mut self` reference is needed here. + #[inline] + pub fn poll_task(&mut self, cx: &mut Context) -> Poll<()> { + unsafe { + (self.poll)(self.ptr, cx) + } + } +} + +impl Drop for TaskObj { + fn drop(&mut self) { + unsafe { + (self.drop)(self.ptr) + } + } +} + +/// Provides the reason that an executor was unable to spawn. +pub struct SpawnErrorKind { + _hidden: (), +} + +impl fmt::Debug for SpawnErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SpawnErrorKind") + .field(&"shutdown") + .finish() + } +} + +impl SpawnErrorKind { + /// Spawning is failing because the executor has been shut down. + pub fn shutdown() -> SpawnErrorKind { + SpawnErrorKind { _hidden: () } + } + + /// Check whether this error is the `shutdown` error. + pub fn is_shutdown(&self) -> bool { + true + } +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The task for which spawning was attempted + pub task: TaskObj, +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f7d06852f27..f7ad709e6e7 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -261,6 +261,7 @@ #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] +#![feature(futures_api)] #![feature(hashmap_internals)] #![feature(heap_api)] #![feature(int_error_internals)] @@ -282,6 +283,7 @@ #![feature(panic_internals)] #![feature(panic_unwind)] #![feature(peek)] +#![feature(pin)] #![feature(placement_new_protocol)] #![feature(prelude_import)] #![feature(ptr_internals)] @@ -457,6 +459,20 @@ pub use core::u128; #[stable(feature = "core_hint", since = "1.27.0")] pub use core::hint; +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod task { + //! Types and Traits for working with asynchronous tasks. + pub use core::task::*; + pub use alloc_crate::task::*; +} + +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub use core::future; + pub mod f32; pub mod f64; diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs new file mode 100644 index 00000000000..3b5a1725b66 --- /dev/null +++ b/src/test/run-pass/futures-api.rs @@ -0,0 +1,95 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(arbitrary_self_types, futures_api, pin)] +#![allow(unused)] + +use std::boxed::PinBox; +use std::future::Future; +use std::mem::PinMut; +use std::rc::Rc; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{ + Context, Poll, + Wake, Waker, LocalWaker, + Executor, TaskObj, SpawnObjError, + local_waker, local_waker_from_nonlocal, +}; + +struct Counter { + local_wakes: AtomicUsize, + nonlocal_wakes: AtomicUsize, +} + +impl Wake for Counter { + fn wake(this: &Arc) { + this.nonlocal_wakes.fetch_add(1, atomic::Ordering::SeqCst); + } + + unsafe fn wake_local(this: &Arc) { + this.local_wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct NoopExecutor; + +impl Executor for NoopExecutor { + fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> { + Ok(()) + } +} + +struct MyFuture; + +impl Future for MyFuture { + type Output = (); + fn poll(self: PinMut, cx: &mut Context) -> Poll { + // Ensure all the methods work appropriately + cx.waker().wake(); + cx.waker().wake(); + cx.local_waker().wake(); + cx.executor().spawn_obj(PinBox::new(MyFuture).into()).unwrap(); + Poll::Ready(()) + } +} + +fn test_local_waker() { + let counter = Arc::new(Counter { + local_wakes: AtomicUsize::new(0), + nonlocal_wakes: AtomicUsize::new(0), + }); + let waker = unsafe { local_waker(counter.clone()) }; + let executor = &mut NoopExecutor; + let cx = &mut Context::new(&waker, executor); + assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx)); + assert_eq!(1, counter.local_wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(2, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst)); +} + +fn test_local_as_nonlocal_waker() { + let counter = Arc::new(Counter { + local_wakes: AtomicUsize::new(0), + nonlocal_wakes: AtomicUsize::new(0), + }); + let waker: LocalWaker = local_waker_from_nonlocal(counter.clone()); + let executor = &mut NoopExecutor; + let cx = &mut Context::new(&waker, executor); + assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx)); + assert_eq!(0, counter.local_wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(3, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst)); +} + +fn main() { + test_local_waker(); + test_local_as_nonlocal_waker(); +} -- cgit 1.4.1-3-g733a5 From 0c6cd26aecb7aec3407014c4b0ece7e6278631c4 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Fri, 1 Jun 2018 12:58:30 -0700 Subject: [fuchsia] Migrate from launchpad to fdio_spawn_etc fdio_spawn_etc is the preferred way of creating processes on Fuchsia now. --- src/libstd/build.rs | 1 - src/libstd/sys/unix/process/process_fuchsia.rs | 75 +++++++++-------------- src/libstd/sys/unix/process/zircon.rs | 85 +++++++------------------- 3 files changed, 51 insertions(+), 110 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/build.rs b/src/libstd/build.rs index c34877d369c..c001e4e8ceb 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -74,7 +74,6 @@ fn main() { } println!("cargo:rustc-link-lib=zircon"); println!("cargo:rustc-link-lib=fdio"); - println!("cargo:rustc-link-lib=launchpad"); // for std::process } else if target.contains("cloudabi") { if cfg!(feature = "backtrace") { println!("cargo:rustc-link-lib=unwind"); diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 06c0540fec0..fa48001179e 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -56,68 +56,49 @@ impl Command { -> io::Result { use sys::process::zircon::*; - let job_handle = zx_job_default(); let envp = match maybe_envp { Some(envp) => envp.as_ptr(), None => ptr::null(), }; - // To make sure launchpad_destroy gets called on the launchpad if this function fails - struct LaunchpadDestructor(*mut launchpad_t); - impl Drop for LaunchpadDestructor { - fn drop(&mut self) { unsafe { launchpad_destroy(self.0); } } - } - - // Duplicate the job handle - let mut job_copy: zx_handle_t = ZX_HANDLE_INVALID; - zx_cvt(zx_handle_duplicate(job_handle, ZX_RIGHT_SAME_RIGHTS, &mut job_copy))?; - // Create a launchpad - let mut launchpad: *mut launchpad_t = ptr::null_mut(); - zx_cvt(launchpad_create(job_copy, self.get_argv()[0], &mut launchpad))?; - let launchpad_destructor = LaunchpadDestructor(launchpad); - - // Set the process argv - zx_cvt(launchpad_set_args(launchpad, self.get_argv().len() as i32 - 1, - self.get_argv().as_ptr()))?; - // Setup the environment vars - zx_cvt(launchpad_set_environ(launchpad, envp))?; - zx_cvt(launchpad_add_vdso_vmo(launchpad))?; - // Load the executable - zx_cvt(launchpad_elf_load(launchpad, launchpad_vmo_from_file(self.get_argv()[0])))?; - zx_cvt(launchpad_load_vdso(launchpad, ZX_HANDLE_INVALID))?; - zx_cvt(launchpad_clone(launchpad, LP_CLONE_FDIO_NAMESPACE | LP_CLONE_FDIO_CWD))?; + let transfer_or_clone = |opt_fd, target_fd| if let Some(local_fd) = opt_fd { + fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_TRANSFER_FD, + local_fd, + target_fd, + ..Default::default() + } + } else { + fdio_spawn_action_t { + action: FDIO_SPAWN_ACTION_CLONE_FD, + local_fd: target_fd, + target_fd, + ..Default::default() + } + }; // Clone stdin, stdout, and stderr - if let Some(fd) = stdio.stdin.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 0))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 0, 0))?; - } - if let Some(fd) = stdio.stdout.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 1))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 1, 1))?; - } - if let Some(fd) = stdio.stderr.fd() { - zx_cvt(launchpad_transfer_fd(launchpad, fd, 2))?; - } else { - zx_cvt(launchpad_clone_fd(launchpad, 2, 2))?; - } + let action1 = transfer_or_clone(stdio.stdin.fd(), 0); + let action2 = transfer_or_clone(stdio.stdout.fd(), 1); + let action3 = transfer_or_clone(stdio.stderr.fd(), 2); + let actions = [action1, action2, action3]; - // We don't want FileDesc::drop to be called on any stdio. It would close their fds. The - // fds will be closed once the child process finishes. + // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc + // always consumes transferred file descriptors. mem::forget(stdio); for callback in self.get_closures().iter_mut() { callback()?; } - // `launchpad_go` destroys the launchpad, so we must not - mem::forget(launchpad_destructor); - let mut process_handle: zx_handle_t = 0; - let mut err_msg: *const libc::c_char = ptr::null(); - zx_cvt(launchpad_go(launchpad, &mut process_handle, &mut err_msg))?; + zx_cvt(fdio_spawn_etc( + 0, + FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE, + self.get_argv()[0], self.get_argv().as_ptr(), envp, 3, actions.as_ptr(), + &mut process_handle, + ptr::null_mut(), + ))?; // FIXME: See if we want to do something with that err_msg Ok(process_handle) diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs index 90864e6ef3f..a06c73ee263 100644 --- a/src/libstd/sys/unix/process/zircon.rs +++ b/src/libstd/sys/unix/process/zircon.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_camel_case_types)] +#![allow(non_camel_case_types, unused)] use convert::TryInto; use io; @@ -117,75 +117,36 @@ extern { avail: *mut size_t) -> zx_status_t; } -// From `enum special_handles` in system/ulib/launchpad/launchpad.c -// HND_LOADER_SVC = 0 -// HND_EXEC_VMO = 1 -// HND_SEGMENTS_VMAR = 2 -const HND_SPECIAL_COUNT: c_int = 3; - +#[derive(Default)] #[repr(C)] -pub struct launchpad_t { - argc: u32, - envc: u32, - args: *const c_char, - args_len: size_t, - env: *const c_char, - env_len: size_t, - - handles: *mut zx_handle_t, - handles_info: *mut u32, - handle_count: size_t, - handle_alloc: size_t, - - entry: zx_vaddr_t, - base: zx_vaddr_t, - vdso_base: zx_vaddr_t, - - stack_size: size_t, - - special_handles: [zx_handle_t; HND_SPECIAL_COUNT as usize], - loader_message: bool, +pub struct fdio_spawn_action_t { + pub action: u32, + pub reserved0: u32, + pub local_fd: i32, + pub target_fd: i32, + pub reserved1: u64, } extern { - pub fn launchpad_create(job: zx_handle_t, name: *const c_char, - lp: *mut *mut launchpad_t) -> zx_status_t; - - pub fn launchpad_go(lp: *mut launchpad_t, - proc_handle: *mut zx_handle_t, - err_msg: *mut *const c_char) -> zx_status_t; - - pub fn launchpad_destroy(lp: *mut launchpad_t); - - pub fn launchpad_set_args(lp: *mut launchpad_t, argc: c_int, - argv: *const *const c_char) -> zx_status_t; - - pub fn launchpad_set_environ(lp: *mut launchpad_t, envp: *const *const c_char) -> zx_status_t; - - pub fn launchpad_clone(lp: *mut launchpad_t, what: u32) -> zx_status_t; - - pub fn launchpad_clone_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t; - - pub fn launchpad_transfer_fd(lp: *mut launchpad_t, fd: c_int, target_fd: c_int) -> zx_status_t; - - pub fn launchpad_elf_load(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t; - - pub fn launchpad_add_vdso_vmo(lp: *mut launchpad_t) -> zx_status_t; + pub fn fdio_spawn_etc(job: zx_handle_t, flags: u32, path: *const c_char, + argv: *const *const c_char, envp: *const *const c_char, + action_count: u64, actions: *const fdio_spawn_action_t, + process: *mut zx_handle_t, err_msg: *mut c_char) -> zx_status_t; +} - pub fn launchpad_load_vdso(lp: *mut launchpad_t, vmo: zx_handle_t) -> zx_status_t; +// fdio_spawn_etc flags - pub fn launchpad_vmo_from_file(filename: *const c_char) -> zx_handle_t; -} +pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001; +pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; +pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; +pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; +pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; +pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; -// Launchpad clone constants +// fdio_spawn_etc actions -pub const LP_CLONE_FDIO_NAMESPACE: u32 = 0x0001; -pub const LP_CLONE_FDIO_CWD: u32 = 0x0002; -// LP_CLONE_FDIO_STDIO = 0x0004 -// LP_CLONE_FDIO_ALL = 0x00FF -// LP_CLONE_ENVIRON = 0x0100 -// LP_CLONE_DEFAULT_JOB = 0x0200 -// LP_CLONE_ALL = 0xFFFF +pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001; +pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002; // Errors -- cgit 1.4.1-3-g733a5 From 6e5c18e8dc94a679126d276884a3ad4b9a3e0934 Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 8 Jun 2018 16:45:27 -0400 Subject: add a few blanket future impls to std --- src/liballoc/boxed.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/liballoc/lib.rs | 1 + src/libcore/future.rs | 17 +++++++++++++++++ src/libcore/task.rs | 6 ++++++ src/libstd/lib.rs | 1 + src/libstd/panic.rs | 18 ++++++++++++++++++ 6 files changed, 82 insertions(+) (limited to 'src/libstd') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index a64b94b6517..896d9dee3ee 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -914,6 +914,45 @@ impl, U: ?Sized> CoerceUnsized> for PinBox {} #[unstable(feature = "pin", issue = "49150")] impl Unpin for PinBox {} +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: ?Sized + Future + Unpin> Future for Box { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut Context) -> Poll { + PinMut::new(&mut **self).poll(cx) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: ?Sized + Future> Future for PinBox { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut Context) -> Poll { + self.as_pin_mut().poll(cx) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl + Send + 'static> UnsafePoll for Box { + fn into_raw(self) -> *mut () { + unsafe { + mem::transmute(self) + } + } + + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { + let ptr: *mut F = mem::transmute(task); + let pin: PinMut = PinMut::new_unchecked(&mut *ptr); + pin.poll(cx) + } + + unsafe fn drop(task: *mut ()) { + let ptr: *mut F = mem::transmute(task); + let boxed = Box::from_raw(ptr); + drop(boxed) + } +} + #[unstable(feature = "futures_api", issue = "50547")] unsafe impl + Send + 'static> UnsafePoll for PinBox { fn into_raw(self) -> *mut () { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 242c7d2e70f..a1139189c9a 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -80,6 +80,7 @@ #![cfg_attr(test, feature(rand, test))] #![feature(allocator_api)] #![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types)] #![feature(ascii_ctype)] #![feature(box_into_raw_non_null)] #![feature(box_patterns)] diff --git a/src/libcore/future.rs b/src/libcore/future.rs index b4d087f8edb..a8c8f69411e 100644 --- a/src/libcore/future.rs +++ b/src/libcore/future.rs @@ -15,6 +15,7 @@ //! Asynchronous values. use mem::PinMut; +use marker::Unpin; use task::{self, Poll}; /// A future represents an asychronous computation. @@ -91,3 +92,19 @@ pub trait Future { /// about the behavior of `poll` after a future has completed. fn poll(self: PinMut, cx: &mut task::Context) -> Poll; } + +impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll(PinMut::new(&mut **self), cx) + } +} + +impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll((*self).reborrow(), cx) + } +} diff --git a/src/libcore/task.rs b/src/libcore/task.rs index e46a6d41d7a..ab1c1da5790 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -32,6 +32,12 @@ pub enum Poll { Pending, } +impl From for Poll { + fn from(t: T) -> Poll { + Poll::Ready(t) + } +} + /// A `Waker` is a handle for waking up a task by notifying its executor that it /// is ready to be run. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7bbc99b83be..bb23fe5fa91 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -239,6 +239,7 @@ #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(align_offset)] +#![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(ascii_ctype)] #![feature(asm)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 229034eb779..b70de73991f 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -15,11 +15,14 @@ use any::Any; use cell::UnsafeCell; use fmt; +use future::Future; +use mem::PinMut; use ops::{Deref, DerefMut}; use panicking; use ptr::{Unique, NonNull}; use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; +use task::{self, Poll}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -315,6 +318,21 @@ impl fmt::Debug for AssertUnwindSafe { } } +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future> Future for AssertUnwindSafe { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + unsafe { + let pinned_field = PinMut::new_unchecked( + &mut PinMut::get_mut(self.reborrow()).0 + ); + + pinned_field.poll(cx) + } + } +} + /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// /// This function will return `Ok` with the closure's result if the closure -- cgit 1.4.1-3-g733a5 From 49eb754cc0108d8546eae70cdcebf81aaddbece3 Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 8 Jun 2018 23:16:51 -0400 Subject: addressed nits --- src/liballoc/boxed.rs | 21 --------------------- src/libstd/panic.rs | 6 +++--- 2 files changed, 3 insertions(+), 24 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 896d9dee3ee..c794fb8220a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -932,27 +932,6 @@ impl<'a, F: ?Sized + Future> Future for PinBox { } } -#[unstable(feature = "futures_api", issue = "50547")] -unsafe impl + Send + 'static> UnsafePoll for Box { - fn into_raw(self) -> *mut () { - unsafe { - mem::transmute(self) - } - } - - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> { - let ptr: *mut F = mem::transmute(task); - let pin: PinMut = PinMut::new_unchecked(&mut *ptr); - pin.poll(cx) - } - - unsafe fn drop(task: *mut ()) { - let ptr: *mut F = mem::transmute(task); - let boxed = Box::from_raw(ptr); - drop(boxed) - } -} - #[unstable(feature = "futures_api", issue = "50547")] unsafe impl + Send + 'static> UnsafePoll for PinBox { fn into_raw(self) -> *mut () { diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index b70de73991f..8aee15b5eda 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -326,9 +326,9 @@ impl<'a, F: Future> Future for AssertUnwindSafe { unsafe { let pinned_field = PinMut::new_unchecked( &mut PinMut::get_mut(self.reborrow()).0 - ); - - pinned_field.poll(cx) + ); + + pinned_field.poll(cx) } } } -- cgit 1.4.1-3-g733a5 From fb507cadf32e1eacccc07c1c3511636fd6378f7b Mon Sep 17 00:00:00 2001 From: tinaun Date: Fri, 8 Jun 2018 23:24:52 -0400 Subject: add inherent methods to Poll --- src/libcore/task.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/panic.rs | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libcore/task.rs b/src/libcore/task.rs index ab1c1da5790..bef6d3677d0 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task.rs @@ -32,6 +32,55 @@ pub enum Poll { Pending, } +impl Poll { + /// Change the ready value of this `Poll` with the closure provided + pub fn map(self, f: F) -> Poll + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(t) => Poll::Ready(f(t)), + Poll::Pending => Poll::Pending, + } + } + + /// Returns whether this is `Poll::Ready` + pub fn is_ready(&self) -> bool { + match *self { + Poll::Ready(_) => true, + Poll::Pending => false, + } + } + + /// Returns whether this is `Poll::Pending` + pub fn is_pending(&self) -> bool { + !self.is_ready() + } +} + +impl Poll> { + /// Change the success value of this `Poll` with the closure provided + pub fn map_ok(self, f: F) -> Poll> + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), + Poll::Ready(Err(e)) => Poll::Ready(Err(e)), + Poll::Pending => Poll::Pending, + } + } + + /// Change the error value of this `Poll` with the closure provided + pub fn map_err(self, f: F) -> Poll> + where F: FnOnce(E) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), + Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), + Poll::Pending => Poll::Pending, + } + } +} + impl From for Poll { fn from(t: T) -> Poll { Poll::Ready(t) diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 8aee15b5eda..4b5a063ea73 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -327,7 +327,7 @@ impl<'a, F: Future> Future for AssertUnwindSafe { let pinned_field = PinMut::new_unchecked( &mut PinMut::get_mut(self.reborrow()).0 ); - + pinned_field.poll(cx) } } -- cgit 1.4.1-3-g733a5 From 861c7cb9fd37fc171f80a9f0b58f995ad67c6df0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 26 May 2018 11:11:17 +0200 Subject: Stabilize entry-or-default --- .../unstable-book/src/library-features/entry-or-default.md | 13 ------------- src/liballoc/btree/map.rs | 3 +-- src/librustc/lib.rs | 1 - src/libstd/collections/hash/map.rs | 4 +--- 4 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/entry-or-default.md (limited to 'src/libstd') diff --git a/src/doc/unstable-book/src/library-features/entry-or-default.md b/src/doc/unstable-book/src/library-features/entry-or-default.md deleted file mode 100644 index f8c8a2a7a71..00000000000 --- a/src/doc/unstable-book/src/library-features/entry-or-default.md +++ /dev/null @@ -1,13 +0,0 @@ -# `entry_or_default` - -The tracking issue for this feature is: [#44324] - -[#44324]: https://github.com/rust-lang/rust/issues/44324 - ------------------------- - -The `entry_or_default` feature adds a new method to `hash_map::Entry` -and `btree_map::Entry`, `or_default`, when `V: Default`. This method is -semantically identical to `or_insert_with(Default::default)`, and will -insert the default value for the type if no entry exists for the current -key. diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 9b6f91c039f..e6e454446e2 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -2184,14 +2184,13 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } impl<'a, K: Ord, V: Default> Entry<'a, K, V> { - #[unstable(feature = "entry_or_default", issue = "44324")] + #[stable(feature = "entry_or_default", since = "1.28.0")] /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` - /// #![feature(entry_or_default)] /// # fn main() { /// use std::collections::BTreeMap; /// diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a006856f58b..102efe2bef3 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -45,7 +45,6 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![feature(entry_or_default)] #![feature(from_ref)] #![feature(fs_read_write)] #![feature(iterator_find_map)] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 5cbd8891364..9c77acb83ec 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2161,14 +2161,13 @@ impl<'a, K, V> Entry<'a, K, V> { } impl<'a, K, V: Default> Entry<'a, K, V> { - #[unstable(feature = "entry_or_default", issue = "44324")] + #[stable(feature = "entry_or_default", since = "1.28.0")] /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` - /// #![feature(entry_or_default)] /// # fn main() { /// use std::collections::HashMap; /// @@ -2184,7 +2183,6 @@ impl<'a, K, V: Default> Entry<'a, K, V> { Vacant(entry) => entry.insert(Default::default()), } } - } impl<'a, K, V> OccupiedEntry<'a, K, V> { -- cgit 1.4.1-3-g733a5 From 02c96d4733a2db16d0dd88ada8023da851f7739e Mon Sep 17 00:00:00 2001 From: CrLF0710 Date: Mon, 11 Jun 2018 03:09:30 +0800 Subject: Add #[doc(inline)] in std::task Add #[doc(inline)] in `std::task` to make the doc seem right. --- src/libstd/lib.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7bbc99b83be..4bf52224ae6 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -467,7 +467,9 @@ pub use core::hint; issue = "50547")] pub mod task { //! Types and Traits for working with asynchronous tasks. + #[doc(inline)] pub use core::task::*; + #[doc(inline)] pub use alloc_crate::task::*; } -- cgit 1.4.1-3-g733a5 From f6ab74b8e7efed01c1045773b6693f23f6ebd93c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 31 May 2018 15:57:43 +0900 Subject: Remove alloc::Opaque and use *mut u8 as pointer type for GlobalAlloc --- .../src/language-features/global-allocator.md | 6 +- src/liballoc/alloc.rs | 33 ++++---- src/liballoc/arc.rs | 6 +- src/liballoc/btree/node.rs | 10 +-- src/liballoc/heap.rs | 12 +-- src/liballoc/raw_vec.rs | 19 +++-- src/liballoc/rc.rs | 10 +-- src/liballoc_system/lib.rs | 89 +++++++++++----------- src/libcore/alloc.rs | 65 ++++++---------- src/libcore/ptr.rs | 8 -- src/librustc_allocator/expand.rs | 15 +--- src/libstd/alloc.rs | 10 +-- src/libstd/collections/hash/table.rs | 2 +- src/test/run-make-fulldeps/std-core-cycle/bar.rs | 4 +- src/test/run-pass/allocator/auxiliary/custom.rs | 6 +- src/test/run-pass/allocator/custom.rs | 6 +- src/test/run-pass/realloc-16687.rs | 4 +- 17 files changed, 130 insertions(+), 175 deletions(-) (limited to 'src/libstd') diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index 8f1ba22de8c..7dfdc487731 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -29,17 +29,17 @@ looks like: ```rust #![feature(global_allocator, allocator_api, heap_api)] -use std::alloc::{GlobalAlloc, System, Layout, Opaque}; +use std::alloc::{GlobalAlloc, System, Layout}; use std::ptr::NonNull; struct MyAllocator; unsafe impl GlobalAlloc for MyAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { System.dealloc(ptr, layout) } } diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 8753c495737..102910f4198 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -51,52 +51,49 @@ pub const Heap: Global = Global; unsafe impl GlobalAlloc for Global { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - let ptr = __rust_alloc(layout.size(), layout.align()); - ptr as *mut Opaque + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + __rust_alloc(layout.size(), layout.align()) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - __rust_dealloc(ptr as *mut u8, layout.size(), layout.align()) + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + __rust_dealloc(ptr, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); - ptr as *mut Opaque + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + __rust_realloc(ptr, layout.size(), layout.align(), new_size) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); - ptr as *mut Opaque + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + __rust_alloc_zeroed(layout.size(), layout.align()) } } unsafe impl Alloc for Global { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result, AllocErr> + -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } } @@ -113,7 +110,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); let ptr = Global.alloc(layout); if !ptr.is_null() { - ptr as *mut u8 + ptr } else { oom(layout) } @@ -129,7 +126,7 @@ pub(crate) unsafe fn box_free(ptr: Unique) { // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr as *mut Opaque, layout); + Global.dealloc(ptr as *mut u8, layout); } } diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 4026b3ababa..e3369f0a5b5 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -519,7 +519,7 @@ impl Arc { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } @@ -639,7 +639,7 @@ impl ArcFromSlice for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem.as_opaque(), self.layout.clone()); + Global.dealloc(self.mem.cast(), self.layout.clone()); } } } @@ -1196,7 +1196,7 @@ impl Drop for Weak { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 431695c32ab..19bdcbc6ad6 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -287,7 +287,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::>()); + Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); } } } @@ -478,7 +478,7 @@ impl NodeRef { debug_assert!(!self.is_shared_root()); let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -499,7 +499,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -1321,12 +1321,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 16f0630b911..5ea37ceeb2b 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -10,7 +10,7 @@ #![allow(deprecated)] -pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque}; +pub use alloc::{Layout, AllocErr, CannotReallocInPlace}; use core::alloc::Alloc as CoreAlloc; use core::ptr::NonNull; @@ -54,7 +54,7 @@ unsafe impl Alloc for T where T: CoreAlloc { } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::dealloc(self, ptr, layout) } @@ -70,7 +70,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) } @@ -87,7 +87,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } @@ -96,7 +96,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } @@ -104,7 +104,7 @@ unsafe impl Alloc for T where T: CoreAlloc { ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + let ptr = NonNull::new_unchecked(ptr); CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 07bb7f1a3eb..c09f21eeb92 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -93,7 +93,7 @@ impl RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - NonNull::::dangling().as_opaque() + NonNull::::dangling().cast() } else { let align = mem::align_of::(); let layout = Layout::from_size_align(alloc_size, align).unwrap(); @@ -314,7 +314,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); - let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(), + let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(), cur, new_size); match ptr_res { @@ -373,7 +373,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); - match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { + match self.a.grow_in_place(NonNull::from(self.ptr).cast(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -546,7 +546,7 @@ impl RawVec { // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow()); match self.a.grow_in_place( - NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(), + NonNull::from(self.ptr).cast(), old_layout, new_layout.size(), ) { Ok(_) => { self.cap = new_cap; @@ -607,7 +607,7 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - match self.a.realloc(NonNull::from(self.ptr).as_opaque(), + match self.a.realloc(NonNull::from(self.ptr).cast(), old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), @@ -667,7 +667,7 @@ impl RawVec { let res = match self.current_layout() { Some(layout) => { debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) + self.a.realloc(NonNull::from(self.ptr).cast(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; @@ -710,7 +710,7 @@ impl RawVec { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout); + self.a.dealloc(NonNull::from(self.ptr).cast(), layout); } } } @@ -753,7 +753,6 @@ fn capacity_overflow() -> ! { #[cfg(test)] mod tests { use super::*; - use alloc::Opaque; #[test] fn allocator_param() { @@ -773,7 +772,7 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); @@ -783,7 +782,7 @@ mod tests { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 553c8b5ca32..84a6ecf7103 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, Opaque, box_free, oom}; +use alloc::{Global, Alloc, Layout, box_free, oom}; use string::String; use vec::Vec; @@ -732,7 +732,7 @@ impl RcFromSlice for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard { - mem: NonNull, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -755,7 +755,7 @@ impl RcFromSlice for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut Opaque; + let mem = ptr as *mut _ as *mut u8; let layout = Layout::for_value(&*ptr); // Pointer to first element @@ -839,7 +839,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1263,7 +1263,7 @@ impl Drop for Weak { // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 9490b54e675..82fda8d639e 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -41,7 +41,7 @@ const MIN_ALIGN: usize = 8; #[allow(dead_code)] const MIN_ALIGN: usize = 16; -use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque}; +use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout}; use core::ptr::NonNull; #[unstable(feature = "allocator_api", issue = "32838")] @@ -50,45 +50,45 @@ pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } } #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] mod realloc_fallback { - use core::alloc::{GlobalAlloc, Opaque, Layout}; + use core::alloc::{GlobalAlloc, Layout}; use core::cmp; use core::ptr; impl super::System { - pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout, - new_size: usize) -> *mut Opaque { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout, + new_size: usize) -> *mut u8 { // Docs for GlobalAlloc::realloc require this to be valid: let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); let new_ptr = GlobalAlloc::alloc(self, new_layout); if !new_ptr.is_null() { let size = cmp::min(old_layout.size(), new_size); - ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size); + ptr::copy_nonoverlapping(ptr, new_ptr, size); GlobalAlloc::dealloc(self, ptr, old_layout); } new_ptr @@ -104,21 +104,19 @@ mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Layout, Opaque}; + use core::alloc::{GlobalAlloc, Layout}; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut Opaque + libc::malloc(layout.size()) as *mut u8 } else { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - // FIXME: use Opaque::null_mut - // https://github.com/rust-lang/rust/issues/49659 - return 0 as *mut Opaque + return ptr::null_mut() } } aligned_malloc(&layout) @@ -126,27 +124,27 @@ mod platform { } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut Opaque + libc::calloc(layout.size(), 1) as *mut u8 } else { let ptr = self.alloc(layout.clone()); if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, layout.size()); + ptr::write_bytes(ptr, 0, layout.size()); } ptr } } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { libc::free(ptr as *mut libc::c_void) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } else { self.realloc_fallback(ptr, layout, new_size) } @@ -155,7 +153,7 @@ mod platform { #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -173,19 +171,18 @@ mod platform { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut Opaque + libc::memalign(layout.align(), layout.size()) as *mut u8 } #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { let mut out = ptr::null_mut(); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { - // FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659 - 0 as *mut Opaque + ptr::null_mut() } else { - out as *mut Opaque + out as *mut u8 } } } @@ -195,7 +192,7 @@ mod platform { mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Opaque, Layout}; + use core::alloc::{GlobalAlloc, Layout}; type LPVOID = *mut u8; type HANDLE = LPVOID; @@ -227,7 +224,7 @@ mod platform { } #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque { + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 { let ptr = if layout.align() <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { @@ -239,29 +236,29 @@ mod platform { align_ptr(ptr, layout.align()) } }; - ptr as *mut Opaque + ptr as *mut u8 } #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { allocate_with_flags(layout, 0) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { if layout.align() <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); } else { - let header = get_header(ptr as *mut u8); + let header = get_header(ptr); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); @@ -269,9 +266,9 @@ mod platform { } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8 } else { self.realloc_fallback(ptr, layout, new_size) } @@ -300,7 +297,7 @@ mod platform { mod platform { extern crate dlmalloc; - use core::alloc::{GlobalAlloc, Layout, Opaque}; + use core::alloc::{GlobalAlloc, Layout}; use System; // No need for synchronization here as wasm is currently single-threaded @@ -309,23 +306,23 @@ mod platform { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + DLMALLOC.malloc(layout.size(), layout.align()) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + DLMALLOC.calloc(layout.size(), layout.align()) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + DLMALLOC.free(ptr, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) } } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 229758803c8..2815ef6400d 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -22,30 +22,13 @@ use usize; use ptr::{self, NonNull}; use num::NonZeroUsize; -extern { - /// An opaque, unsized type. Used for pointers to allocated memory. - /// - /// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull`. - /// Such pointers are similar to C’s `void*` type. - pub type Opaque; -} - -impl Opaque { - /// Similar to `std::ptr::null`, which requires `T: Sized`. - pub fn null() -> *const Self { - 0 as _ - } - - /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. - pub fn null_mut() -> *mut Self { - 0 as _ - } -} +#[cfg(stage0)] +pub type Opaque = u8; /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -pub struct Excess(pub NonNull, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -417,7 +400,7 @@ pub unsafe trait GlobalAlloc { /// # Safety /// /// **FIXME:** what are the exact requirements? - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; + unsafe fn alloc(&self, layout: Layout) -> *mut u8; /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. /// @@ -425,13 +408,13 @@ pub unsafe trait GlobalAlloc { /// /// **FIXME:** what are the exact requirements? /// In particular around layout *fit*. (See docs for the `Alloc` trait.) - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); let ptr = self.alloc(layout); if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, size); + ptr::write_bytes(ptr, 0, size); } ptr } @@ -452,13 +435,13 @@ pub unsafe trait GlobalAlloc { /// /// **FIXME:** what are the exact requirements? /// In particular around layout *fit*. (See docs for the `Alloc` trait.) - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_ptr = self.alloc(new_layout); if !new_ptr.is_null() { ptr::copy_nonoverlapping( - ptr as *const u8, - new_ptr as *mut u8, + ptr, + new_ptr, cmp::min(layout.size(), new_size), ); self.dealloc(ptr, layout); @@ -598,7 +581,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -615,7 +598,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == // usable_size @@ -707,9 +690,9 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { let old_size = layout.size(); if new_size >= old_size { @@ -726,8 +709,8 @@ pub unsafe trait Alloc { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let result = self.alloc(new_layout); if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, - new_ptr.as_ptr() as *mut u8, + ptr::copy_nonoverlapping(ptr.as_ptr(), + new_ptr.as_ptr(), cmp::min(old_size, new_size)); self.dealloc(ptr, layout); } @@ -750,11 +733,11 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { - ptr::write_bytes(p.as_ptr() as *mut u8, 0, size); + ptr::write_bytes(p.as_ptr(), 0, size); } p } @@ -799,7 +782,7 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -844,7 +827,7 @@ pub unsafe trait Alloc { /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -899,7 +882,7 @@ pub unsafe trait Alloc { /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. @@ -978,7 +961,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - self.dealloc(ptr.as_opaque(), k); + self.dealloc(ptr.cast(), k); } } @@ -1066,7 +1049,7 @@ pub unsafe trait Alloc { match (Layout::array::(n_old), Layout::array::(n_new)) { (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast) + self.realloc(ptr.cast(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { Err(AllocErr) @@ -1099,7 +1082,7 @@ pub unsafe trait Alloc { { match Layout::array::(n) { Ok(ref k) if k.size() > 0 => { - Ok(self.dealloc(ptr.as_opaque(), k.clone())) + Ok(self.dealloc(ptr.cast(), k.clone())) } _ => { Err(AllocErr) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 39315d8f0c8..81a8b3ef047 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2922,14 +2922,6 @@ impl NonNull { NonNull::new_unchecked(self.as_ptr() as *mut U) } } - - /// Cast to an `Opaque` pointer - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn as_opaque(self) -> NonNull<::alloc::Opaque> { - unsafe { - NonNull::new_unchecked(self.as_ptr() as _) - } - } } #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 497d5fdcac7..ec0676259ef 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -237,7 +237,7 @@ impl<'a> AllocFnFactory<'a> { let ident = ident(); args.push(self.cx.arg(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_opaque()) + self.cx.expr_cast(self.span, arg, self.ptr_u8()) } AllocatorTy::Usize => { @@ -281,17 +281,4 @@ impl<'a> AllocFnFactory<'a> { let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } - - fn ptr_opaque(&self) -> P { - let opaque = self.cx.path( - self.span, - vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("Opaque"), - ], - ); - let ty_opaque = self.cx.ty_path(opaque); - self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable) - } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 3b1a3a439e7..ac7da5e9dba 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -74,7 +74,7 @@ pub extern fn rust_oom(layout: Layout) -> ! { #[doc(hidden)] #[allow(unused_attributes)] pub mod __default_lib_allocator { - use super::{System, Layout, GlobalAlloc, Opaque}; + use super::{System, Layout, GlobalAlloc}; // for symbol names src/librustc/middle/allocator.rs // for signatures src/librustc_allocator/lib.rs @@ -85,7 +85,7 @@ pub mod __default_lib_allocator { #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - System.alloc(layout) as *mut u8 + System.alloc(layout) } #[no_mangle] @@ -93,7 +93,7 @@ pub mod __default_lib_allocator { pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) { - System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align)) + System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) } #[no_mangle] @@ -103,13 +103,13 @@ pub mod __default_lib_allocator { align: usize, new_size: usize) -> *mut u8 { let old_layout = Layout::from_size_align_unchecked(old_size, align); - System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8 + System.realloc(ptr, old_layout, new_size) } #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { let layout = Layout::from_size_align_unchecked(size, align); - System.alloc_zeroed(layout) as *mut u8 + System.alloc_zeroed(layout) } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index d997fb28d42..55f9f4f7cfe 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1124,7 +1124,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { let (layout, _) = calculate_layout::(self.capacity()) .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); unsafe { - Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout); + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/test/run-make-fulldeps/std-core-cycle/bar.rs b/src/test/run-make-fulldeps/std-core-cycle/bar.rs index 62fd2ade1ca..4b885e5e2bb 100644 --- a/src/test/run-make-fulldeps/std-core-cycle/bar.rs +++ b/src/test/run-make-fulldeps/std-core-cycle/bar.rs @@ -16,11 +16,11 @@ use std::alloc::*; pub struct A; unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, _: Layout) -> *mut Opaque { + unsafe fn alloc(&self, _: Layout) -> *mut u8 { loop {} } - unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) { + unsafe fn dealloc(&self, _ptr: *mut u8, _: Layout) { loop {} } } diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs index 91f70aa83e8..02e86fa19f8 100644 --- a/src/test/run-pass/allocator/auxiliary/custom.rs +++ b/src/test/run-pass/allocator/auxiliary/custom.rs @@ -13,18 +13,18 @@ #![feature(heap_api, allocator_api)] #![crate_type = "rlib"] -use std::alloc::{GlobalAlloc, System, Layout, Opaque}; +use std::alloc::{GlobalAlloc, System, Layout}; use std::sync::atomic::{AtomicUsize, Ordering}; pub struct A(pub AtomicUsize); unsafe impl GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { self.0.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { self.0.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index 415d39a593e..5da13bd4cb9 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -15,7 +15,7 @@ extern crate helper; -use std::alloc::{self, Global, Alloc, System, Layout, Opaque}; +use std::alloc::{self, Global, Alloc, System, Layout}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; static HITS: AtomicUsize = ATOMIC_USIZE_INIT; @@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT; struct A; unsafe impl alloc::GlobalAlloc for A { - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { HITS.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index febd249d776..355053858cc 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout); + Global.dealloc(NonNull::new_unchecked(ptr).cast(), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { @@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old, new.size()) + let ret = Global.realloc(NonNull::new_unchecked(ptr).cast(), old, new.size()) .unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align()))); if PRINT { -- cgit 1.4.1-3-g733a5 From 3373204ac49ebdb7194020ea9c556ce87910f7b7 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 31 May 2018 16:10:01 +0900 Subject: Replace `impl GlobalAlloc for Global` with a set of free functions --- src/liballoc/alloc.rs | 48 ++++++++++++++++-------------- src/libstd/alloc.rs | 1 + src/test/run-pass/allocator/xcrate-use2.rs | 6 ++-- 3 files changed, 29 insertions(+), 26 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 102910f4198..8c2dda77226 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -49,37 +49,39 @@ pub type Heap = Global; #[allow(non_upper_case_globals)] pub const Heap: Global = Global; -unsafe impl GlobalAlloc for Global { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - __rust_alloc(layout.size(), layout.align()) - } +#[unstable(feature = "allocator_api", issue = "32838")] +#[inline] +pub unsafe fn alloc(layout: Layout) -> *mut u8 { + __rust_alloc(layout.size(), layout.align()) +} - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - __rust_dealloc(ptr, layout.size(), layout.align()) - } +#[unstable(feature = "allocator_api", issue = "32838")] +#[inline] +pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { + __rust_dealloc(ptr, layout.size(), layout.align()) +} - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - __rust_realloc(ptr, layout.size(), layout.align(), new_size) - } +#[unstable(feature = "allocator_api", issue = "32838")] +#[inline] +pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + __rust_realloc(ptr, layout.size(), layout.align(), new_size) +} - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - __rust_alloc_zeroed(layout.size(), layout.align()) - } +#[unstable(feature = "allocator_api", issue = "32838")] +#[inline] +pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { + __rust_alloc_zeroed(layout.size(), layout.align()) } unsafe impl Alloc for Global { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) + NonNull::new(alloc(layout)).ok_or(AllocErr) } #[inline] unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) + dealloc(ptr.as_ptr(), layout) } #[inline] @@ -89,12 +91,12 @@ unsafe impl Alloc for Global { new_size: usize) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) + NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) + NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr) } } @@ -108,7 +110,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { align as *mut u8 } else { let layout = Layout::from_size_align_unchecked(size, align); - let ptr = Global.alloc(layout); + let ptr = alloc(layout); if !ptr.is_null() { ptr } else { @@ -126,7 +128,7 @@ pub(crate) unsafe fn box_free(ptr: Unique) { // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr as *mut u8, layout); + dealloc(ptr as *mut u8, layout); } } diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index ac7da5e9dba..3f31fa8e1dd 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -14,6 +14,7 @@ #[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; #[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom}; +#[doc(inline)] pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs index b8e844522dc..fbde7e855c2 100644 --- a/src/test/run-pass/allocator/xcrate-use2.rs +++ b/src/test/run-pass/allocator/xcrate-use2.rs @@ -19,7 +19,7 @@ extern crate custom; extern crate custom_as_global; extern crate helper; -use std::alloc::{Global, Alloc, GlobalAlloc, System, Layout}; +use std::alloc::{alloc, dealloc, GlobalAlloc, System, Layout}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT); @@ -30,10 +30,10 @@ fn main() { let layout = Layout::from_size_align(4, 2).unwrap(); // Global allocator routes to the `custom_as_global` global - let ptr = Global.alloc(layout.clone()); + let ptr = alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 1); - Global.dealloc(ptr, layout.clone()); + dealloc(ptr, layout.clone()); assert_eq!(custom_as_global::get(), n + 2); // Usage of the system allocator avoids all globals -- cgit 1.4.1-3-g733a5 From 8c30c5168694b8ee740dade3a0145eef8aba66c6 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 30 May 2018 20:46:59 +0200 Subject: Remove deprecated heap modules The heap.rs file was already unused. --- src/liballoc/heap.rs | 110 ------------------------------------------ src/liballoc/lib.rs | 8 --- src/libcore/lib.rs | 7 --- src/libstd/collections/mod.rs | 2 +- src/libstd/error.rs | 2 +- src/libstd/lib.rs | 7 --- 6 files changed, 2 insertions(+), 134 deletions(-) delete mode 100644 src/liballoc/heap.rs (limited to 'src/libstd') diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs deleted file mode 100644 index 5ea37ceeb2b..00000000000 --- a/src/liballoc/heap.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(deprecated)] - -pub use alloc::{Layout, AllocErr, CannotReallocInPlace}; -use core::alloc::Alloc as CoreAlloc; -use core::ptr::NonNull; - -#[doc(hidden)] -pub mod __core { - pub use core::*; -} - -#[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); - -/// Compatibility with older versions of #[global_allocator] during bootstrap -pub unsafe trait Alloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); - fn oom(&mut self, err: AllocErr) -> !; - fn usable_size(&self, layout: &Layout) -> (usize, usize); - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result; - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result; - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace>; - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace>; -} - -unsafe impl Alloc for T where T: CoreAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::dealloc(self, ptr, layout) - } - - fn oom(&mut self, _: AllocErr) -> ! { - unsafe { ::core::intrinsics::abort() } - } - - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - CoreAlloc::usable_size(self, layout) - } - - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - CoreAlloc::alloc_excess(self, layout) - .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) - } - - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) - .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) - } - - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) - } - - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr); - CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) - } -} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 242c7d2e70f..828461fe8d7 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -150,18 +150,10 @@ pub mod allocator { pub mod alloc; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; -} - #[unstable(feature = "futures_api", reason = "futures in libcore are unstable", issue = "50547")] pub mod task; - // Primitive types using the heaps above // Need to conditionally define the mod from `boxed.rs` to avoid diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a2ee0033872..5ba77edee6e 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -215,13 +215,6 @@ pub mod task; #[allow(missing_docs)] pub mod alloc; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; -} - // note: does not need to be public mod iter_private; mod nonzero; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index d8e79b97970..42113414183 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -438,7 +438,7 @@ pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use heap::CollectionAllocErr; +pub use alloc::CollectionAllocErr; mod hash; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 817eea5eaf1..3160485375f 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -23,13 +23,13 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. +use alloc::{AllocErr, LayoutErr, CannotReallocInPlace}; use any::TypeId; use borrow::Cow; use cell; use char; use core::array; use fmt::{self, Debug, Display}; -use heap::{AllocErr, LayoutErr, CannotReallocInPlace}; use mem::transmute; use num; use str; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4bf52224ae6..3972763a051 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -499,13 +499,6 @@ pub mod process; pub mod sync; pub mod time; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; -} - // Platform-abstraction modules #[macro_use] mod sys_common; -- cgit 1.4.1-3-g733a5 From 11f992c9584f05f56664627ac1ec42e4cd1f0e3e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 30 May 2018 21:15:40 +0200 Subject: Remove the deprecated Heap type/const --- src/liballoc/alloc.rs | 9 --------- src/libstd/alloc.rs | 1 - 2 files changed, 10 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 8c2dda77226..710da9a475b 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -40,15 +40,6 @@ extern "Rust" { #[derive(Copy, Clone, Default, Debug)] pub struct Global; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] -pub type Heap = Global; - -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] -#[allow(non_upper_case_globals)] -pub const Heap: Global = Global; - #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn alloc(layout: Layout) -> *mut u8 { diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 3f31fa8e1dd..9904634f1fa 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -12,7 +12,6 @@ #![unstable(issue = "32838", feature = "allocator_api")] -#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; #[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom}; #[doc(inline)] pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; #[doc(inline)] pub use alloc_system::System; -- cgit 1.4.1-3-g733a5 From e9fd063edb4f6783fbd91a82a0f61626dacf8dad Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 18:23:42 +0200 Subject: Document memory allocation APIs Add some docs where they were missing, attempt to fix them where they were out of date. --- src/liballoc/alloc.rs | 65 +++++++++++++ src/liballoc_system/lib.rs | 1 + src/libcore/alloc.rs | 227 +++++++++++++++++++++++++++++++++++---------- src/libstd/alloc.rs | 2 +- 4 files changed, 245 insertions(+), 50 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 710da9a475b..c9430a29e4c 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Memory allocation APIs + #![unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked \ slightly, especially to possibly take into account the \ @@ -37,27 +39,80 @@ extern "Rust" { fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; } +/// The global memory allocator. +/// +/// This type implements the [`Alloc`] trait by forwarding calls +/// to the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. #[derive(Copy, Clone, Default, Debug)] pub struct Global; +/// Allocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::alloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `alloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::alloc`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn alloc(layout: Layout) -> *mut u8 { __rust_alloc(layout.size(), layout.align()) } +/// Deallocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::dealloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `dealloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::dealloc`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { __rust_dealloc(ptr, layout.size(), layout.align()) } +/// Reallocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::realloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `realloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::realloc`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } +/// Allocate zero-initialized memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `alloc_zeroed` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::alloc_zeroed`]. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { @@ -123,6 +178,16 @@ pub(crate) unsafe fn box_free(ptr: Unique) { } } +/// Abort on memory allocation error or failure. +/// +/// Callers of memory allocation APIs wishing to abort computation +/// in response to an allocation error are encouraged to call this function, +/// rather than directly invoking `panic!` or similar. +/// +/// The default behavior of this function is to print a message to standard error +/// and abort the process. +/// It can be replaced with [`std::alloc::set_oom_hook`] +/// and [`std::alloc::take_oom_hook`]. #[rustc_allocator_nounwind] pub fn oom(layout: Layout) -> ! { #[allow(improper_ctypes)] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 82fda8d639e..85bf43a5429 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -44,6 +44,7 @@ const MIN_ALIGN: usize = 16; use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout}; use core::ptr::NonNull; +/// The default memory allocator provided by the operating system. #[unstable(feature = "allocator_api", issue = "32838")] pub struct System; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 2815ef6400d..8fcd8555cdc 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Memory allocation APIs + #![unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked \ slightly, especially to possibly take into account the \ @@ -315,8 +317,9 @@ impl Layout { } } -/// The parameters given to `Layout::from_size_align` do not satisfy -/// its documented constraints. +/// The parameters given to `Layout::from_size_align` +/// or some other `Layout` constructor +/// do not satisfy its documented constraints. #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutErr { private: () @@ -329,8 +332,8 @@ impl fmt::Display for LayoutErr { } } -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to +/// The `AllocErr` error indicates an allocation failure +/// that may be due to resource exhaustion or to /// something wrong when combining the given input arguments with this /// allocator. #[derive(Clone, PartialEq, Eq, Debug)] @@ -346,6 +349,7 @@ impl fmt::Display for AllocErr { /// The `CannotReallocInPlace` error is used when `grow_in_place` or /// `shrink_in_place` were unable to reuse the given memory block for /// a requested layout. +// FIXME: should this be in libcore or liballoc? #[derive(Clone, PartialEq, Eq, Debug)] pub struct CannotReallocInPlace; @@ -363,6 +367,7 @@ impl fmt::Display for CannotReallocInPlace { } /// Augments `AllocErr` with a CapacityOverflow variant. +// FIXME: should this be in libcore or liballoc? #[derive(Clone, PartialEq, Eq, Debug)] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] pub enum CollectionAllocErr { @@ -389,27 +394,125 @@ impl From for CollectionAllocErr { } } -/// A memory allocator that can be registered to be the one backing `std::alloc::Global` +/// A memory allocator that can be registered as the standard library’s default /// though the `#[global_allocator]` attributes. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method +/// such as `alloc`, and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method such as `dealloc` or by being +/// passed to a reallocation method that returns a non-null pointer. +/// +/// +/// # Example +/// +/// ```no_run +/// use std::alloc::{GlobalAlloc, Layout, alloc}; +/// use std::ptr::null_mut; +/// +/// struct MyAllocator; +/// +/// unsafe impl GlobalAlloc for MyAllocator { +/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() } +/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// } +/// +/// #[global_allocator] +/// static A: MyAllocator = MyAllocator; +/// +/// fn main() { +/// unsafe { +/// assert!(alloc(Layout::new::()).is_null()) +/// } +/// } +/// ``` +/// +/// # Unsafety +/// +/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * Pointers returned from allocation functions must point to valid memory and +/// retain their validity until at least the instance of `GlobalAlloc` is dropped +/// itself. +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. /// /// Returns a pointer to newly-allocated memory, - /// or NULL to indicate allocation failure. + /// or null to indicate allocation failure. /// /// # Safety /// - /// **FIXME:** what are the exact requirements? + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// The allocated block of memory may or may not be initialized. + /// + /// # Errors + /// + /// Returning a null pointer indicates that either memory is exhausted + /// or `layout` does not meet allocator's size or alignment constraints. + /// + /// Implementations are encouraged to return null on memory + /// exhaustion rather than aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc(&self, layout: Layout) -> *mut u8; /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. /// /// # Safety /// - /// **FIXME:** what are the exact requirements? - /// In particular around layout *fit*. (See docs for the `Alloc` trait.) + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must be the same layout that was used + /// to allocated that block of memory, unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// However the allocated block of memory is guaranteed to be initialized. + /// + /// # Errors + /// + /// Returning a null pointer indicates that either memory is exhausted + /// or `layout` does not meet allocator's size or alignment constraints, + /// just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); let ptr = self.alloc(layout); @@ -422,19 +525,51 @@ pub unsafe trait GlobalAlloc { /// Shink or grow a block of memory to the given `new_size`. /// The block is described by the given `ptr` pointer and `layout`. /// - /// Return a new pointer (which may or may not be the same as `ptr`), - /// or NULL to indicate reallocation failure. + /// If this returns a non-null pointer, then ownership of the memory block + /// referenced by `ptr` has been transferred to this alloctor. + /// The memory may or may not have been deallocated, + /// and should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). /// - /// If reallocation is successful, the old `ptr` pointer is considered - /// to have been deallocated. + /// If this method returns null, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. /// /// # Safety /// - /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, - /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must be the same layout that was used + /// to allocated that block of memory, + /// + /// * `new_size` must be greater than zero. + /// + /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns null if the new layout does not meet the size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// Implementations are encouraged to return null on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) /// - /// **FIXME:** what are the exact requirements? - /// In particular around layout *fit*. (See docs for the `Alloc` trait.) + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_ptr = self.alloc(new_layout); @@ -523,27 +658,21 @@ pub unsafe trait GlobalAlloc { /// retain their validity until at least the instance of `Alloc` is dropped /// itself. /// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. Note that as of the time of this -/// writing allocators *not* intending to be global allocators can still panic -/// in their implementation without violating memory safety. -/// /// * `Layout` queries and calculations in general must be correct. Callers of /// this trait are allowed to rely on the contracts defined on each method, /// and implementors must ensure such contracts remain true. /// /// Note that this list may get tweaked over time as clarifications are made in -/// the future. Additionally global allocators may gain unique requirements for -/// how to safely implement one in the future as well. +/// the future. pub unsafe trait Alloc { - // (Note: existing allocators have unspecified but well-defined + // (Note: some existing allocators have unspecified but well-defined // behavior in response to a zero size allocation request ; // e.g. in C, `malloc` of 0 will either return a null pointer or a // unique pointer, but will not have arbitrary undefined - // behavior. Rust should consider revising the alloc::heap crate - // to reflect this reality.) + // behavior. + // However in jemalloc for example, + // `mallocx(0)` is documented as undefined behavior.) /// Returns a pointer meeting the size and alignment guarantees of /// `layout`. @@ -579,8 +708,8 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the `oom` function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. @@ -686,9 +815,9 @@ pub unsafe trait Alloc { /// implement this trait atop an underlying native allocation /// library that aborts on memory exhaustion.) /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, ptr: NonNull, layout: Layout, @@ -731,8 +860,8 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); @@ -757,8 +886,8 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { let usable_size = self.usable_size(&layout); self.alloc(layout).map(|p| Excess(p, usable_size.1)) @@ -778,9 +907,9 @@ pub unsafe trait Alloc { /// `layout` does not meet allocator's size or alignment /// constraints, just as in `realloc`. /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, ptr: NonNull, layout: Layout, @@ -823,7 +952,7 @@ pub unsafe trait Alloc { /// could fit `layout`. /// /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from + /// function; clients are expected either to be able to recover from /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, @@ -878,7 +1007,7 @@ pub unsafe trait Alloc { /// could fit `layout`. /// /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from + /// function; clients are expected either to be able to recover from /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, @@ -926,8 +1055,8 @@ pub unsafe trait Alloc { /// will *not* yield undefined behavior. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. fn alloc_one(&mut self) -> Result, AllocErr> where Self: Sized { @@ -993,8 +1122,8 @@ pub unsafe trait Alloc { /// Always returns `Err` on arithmetic overflow. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. fn alloc_array(&mut self, n: usize) -> Result, AllocErr> where Self: Sized { @@ -1037,9 +1166,9 @@ pub unsafe trait Alloc { /// /// Always returns `Err` on arithmetic overflow. /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`oom`] function, + /// rather than directly invoking `panic!` or similar. unsafe fn realloc_array(&mut self, ptr: NonNull, n_old: usize, diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 9904634f1fa..9126155a7c9 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! dox +//! Memory allocation APIs #![unstable(issue = "32838", feature = "allocator_api")] -- cgit 1.4.1-3-g733a5 From 951bc28fd09f5fed793021c6be1645e034394491 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 18:36:51 +0200 Subject: Stablize the alloc module without changing stability of its contents. --- src/liballoc/alloc.rs | 11 ++++----- src/libcore/alloc.rs | 32 +++++++++++++++++++++----- src/libstd/alloc.rs | 19 ++++++++++----- src/test/compile-fail/lint-stability-fields.rs | 7 ++++++ 4 files changed, 51 insertions(+), 18 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index c9430a29e4c..fc3d0151ec0 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -10,17 +10,13 @@ //! Memory allocation APIs -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] +#![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics::{min_align_of_val, size_of_val}; use core::ptr::{NonNull, Unique}; use core::usize; +#[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; @@ -44,6 +40,7 @@ extern "Rust" { /// This type implements the [`Alloc`] trait by forwarding calls /// to the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crate’s default. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; @@ -119,6 +116,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { __rust_alloc_zeroed(layout.size(), layout.align()) } +#[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for Global { #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { @@ -188,6 +186,7 @@ pub(crate) unsafe fn box_free(ptr: Unique) { /// and abort the process. /// It can be replaced with [`std::alloc::set_oom_hook`] /// and [`std::alloc::take_oom_hook`]. +#[unstable(feature = "allocator_api", issue = "32838")] #[rustc_allocator_nounwind] pub fn oom(layout: Layout) -> ! { #[allow(improper_ctypes)] diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 8fcd8555cdc..ae9f77d35cf 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -10,12 +10,7 @@ //! Memory allocation APIs -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] +#![stable(feature = "alloc_module", since = "1.28.0")] use cmp; use fmt; @@ -24,11 +19,13 @@ use usize; use ptr::{self, NonNull}; use num::NonZeroUsize; +#[unstable(feature = "allocator_api", issue = "32838")] #[cfg(stage0)] pub type Opaque = u8; /// Represents the combination of a starting address and /// a total capacity of the returned block. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Debug)] pub struct Excess(pub NonNull, pub usize); @@ -49,6 +46,7 @@ fn size_align() -> (usize, usize) { /// requests have positive size. A caller to the `Alloc::alloc` /// method must either ensure that conditions like this are met, or /// use specific allocators with looser requirements.) +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Layout { // size of the requested block of memory, measured in bytes. @@ -74,6 +72,7 @@ impl Layout { /// * `size`, when rounded up to the nearest multiple of `align`, /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { @@ -109,20 +108,24 @@ impl Layout { /// /// This function is unsafe as it does not verify the preconditions from /// [`Layout::from_size_align`](#method.from_size_align). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } } /// The minimum size in bytes for a memory block of this layout. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn size(&self) -> usize { self.size_ } /// The minimum byte alignment for a memory block of this layout. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn align(&self) -> usize { self.align_.get() } /// Constructs a `Layout` suitable for holding a value of type `T`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn new() -> Self { let (size, align) = size_align::(); @@ -139,6 +142,7 @@ impl Layout { /// Produces layout describing a record that could be used to /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); @@ -166,6 +170,7 @@ impl Layout { /// Panics if the combination of `self.size()` and the given `align` /// violates the conditions listed in /// [`Layout::from_size_align`](#method.from_size_align). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn align_to(&self, align: usize) -> Self { Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap() @@ -187,6 +192,7 @@ impl Layout { /// to be less than or equal to the alignment of the starting /// address for the whole allocated block of memory. One way to /// satisfy this constraint is to ensure `align <= self.align()`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn padding_needed_for(&self, align: usize) -> usize { let len = self.size(); @@ -223,6 +229,7 @@ impl Layout { /// of each element in the array. /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { let padded_size = self.size().checked_add(self.padding_needed_for(self.align())) @@ -248,6 +255,7 @@ impl Layout { /// (assuming that the record itself starts at offset 0). /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_align = cmp::max(self.align(), next.align()); @@ -274,6 +282,7 @@ impl Layout { /// aligned. /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn repeat_packed(&self, n: usize) -> Result { let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; @@ -295,6 +304,7 @@ impl Layout { /// `extend`.) /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_size = self.size().checked_add(next.size()) @@ -306,6 +316,7 @@ impl Layout { /// Creates a layout describing the record for a `[T; n]`. /// /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn array(n: usize) -> Result { Layout::new::() @@ -320,12 +331,14 @@ impl Layout { /// The parameters given to `Layout::from_size_align` /// or some other `Layout` constructor /// do not satisfy its documented constraints. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutErr { private: () } // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for LayoutErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("invalid parameters to Layout::from_size_align") @@ -336,10 +349,12 @@ impl fmt::Display for LayoutErr { /// that may be due to resource exhaustion or to /// something wrong when combining the given input arguments with this /// allocator. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct AllocErr; // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("memory allocation failed") @@ -350,9 +365,11 @@ impl fmt::Display for AllocErr { /// `shrink_in_place` were unable to reuse the given memory block for /// a requested layout. // FIXME: should this be in libcore or liballoc? +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct CannotReallocInPlace; +#[unstable(feature = "allocator_api", issue = "32838")] impl CannotReallocInPlace { pub fn description(&self) -> &str { "cannot reallocate allocator's memory in place" @@ -360,6 +377,7 @@ impl CannotReallocInPlace { } // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for CannotReallocInPlace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) @@ -449,6 +467,7 @@ impl From for CollectionAllocErr { /// * `Layout` queries and calculations in general must be correct. Callers of /// this trait are allowed to rely on the contracts defined on each method, /// and implementors must ensure such contracts remain true. +#[unstable(feature = "allocator_api", issue = "32838")] pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. /// @@ -664,6 +683,7 @@ pub unsafe trait GlobalAlloc { /// /// Note that this list may get tweaked over time as clarifications are made in /// the future. +#[unstable(feature = "allocator_api", issue = "32838")] pub unsafe trait Alloc { // (Note: some existing allocators have unspecified but well-defined diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 9126155a7c9..1a4869f87c9 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -10,17 +10,20 @@ //! Memory allocation APIs -#![unstable(issue = "32838", feature = "allocator_api")] - -#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom}; -#[doc(inline)] pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; -#[doc(inline)] pub use alloc_system::System; -#[doc(inline)] pub use core::alloc::*; +#![stable(feature = "alloc_module", since = "1.28.0")] use core::sync::atomic::{AtomicPtr, Ordering}; use core::{mem, ptr}; use sys_common::util::dumb_print; +#[stable(feature = "alloc_module", since = "1.28.0")] +#[doc(inline)] +pub use alloc_crate::alloc::*; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[doc(inline)] +pub use alloc_system::System; + static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// Registers a custom OOM hook, replacing any that was previously registered. @@ -34,6 +37,7 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// about the allocation that failed. /// /// The OOM hook is a global resource. +#[unstable(feature = "allocator_api", issue = "32838")] pub fn set_oom_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); } @@ -43,6 +47,7 @@ pub fn set_oom_hook(hook: fn(Layout)) { /// *See also the function [`set_oom_hook`].* /// /// If no custom hook is registered, the default hook will be returned. +#[unstable(feature = "allocator_api", issue = "32838")] pub fn take_oom_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); if hook.is_null() { @@ -59,6 +64,7 @@ fn default_oom_hook(layout: Layout) { #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] +#[unstable(feature = "allocator_api", issue = "32838")] pub extern fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { @@ -73,6 +79,7 @@ pub extern fn rust_oom(layout: Layout) -> ! { #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] +#[unstable(feature = "allocator_api", issue = "32838")] pub mod __default_lib_allocator { use super::{System, Layout, GlobalAlloc}; // for symbol names src/librustc/middle/allocator.rs diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs index 1b605bdb893..b1b1a9a1fbf 100644 --- a/src/test/compile-fail/lint-stability-fields.rs +++ b/src/test/compile-fail/lint-stability-fields.rs @@ -18,6 +18,11 @@ mod cross_crate { extern crate lint_stability_fields; + mod reexport { + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::lint_stability_fields::*; + } + use self::lint_stability_fields::*; pub fn foo() { @@ -73,6 +78,8 @@ mod cross_crate { // the patterns are all fine: { .. } = x; + // Unstable items are still unstable even when used through a stable "pub use". + let x = reexport::Unstable2(1, 2, 3); //~ ERROR use of unstable let x = Unstable2(1, 2, 3); //~ ERROR use of unstable -- cgit 1.4.1-3-g733a5 From 75e17da87358751becc950b9319f5d4aa82744ce Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 18:38:39 +0200 Subject: Mark as permanently-unstable some implementation details --- src/libcore/alloc.rs | 2 +- src/libstd/alloc.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index ae9f77d35cf..97ad55304be 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -19,7 +19,7 @@ use usize; use ptr::{self, NonNull}; use num::NonZeroUsize; -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "alloc_internals", issue = "0")] #[cfg(stage0)] pub type Opaque = u8; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 1a4869f87c9..55325006e74 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -64,7 +64,7 @@ fn default_oom_hook(layout: Layout) { #[cfg(not(test))] #[doc(hidden)] #[lang = "oom"] -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "alloc_internals", issue = "0")] pub extern fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { @@ -79,7 +79,7 @@ pub extern fn rust_oom(layout: Layout) -> ! { #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "alloc_internals", issue = "0")] pub mod __default_lib_allocator { use super::{System, Layout, GlobalAlloc}; // for symbol names src/librustc/middle/allocator.rs -- cgit 1.4.1-3-g733a5 From 90d19728fc93157465c1a586dbd35c6dc4cf78c9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 19:15:11 +0200 Subject: Move set_oom_hook and take_oom_hook to a dedicated tracking issue --- src/libstd/alloc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 55325006e74..fd829bfe753 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -37,7 +37,7 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// about the allocation that failed. /// /// The OOM hook is a global resource. -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "oom_hook", issue = "51245")] pub fn set_oom_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); } @@ -47,7 +47,7 @@ pub fn set_oom_hook(hook: fn(Layout)) { /// *See also the function [`set_oom_hook`].* /// /// If no custom hook is registered, the default hook will be returned. -#[unstable(feature = "allocator_api", issue = "32838")] +#[unstable(feature = "oom_hook", issue = "51245")] pub fn take_oom_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); if hook.is_null() { -- cgit 1.4.1-3-g733a5 From 8111717da1d5854495b001be49346985ac3f208d Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 19:16:24 +0200 Subject: Stabilize the `System` allocator --- src/liballoc_system/lib.rs | 8 ++++---- src/libstd/alloc.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 85bf43a5429..a592868cbef 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -45,7 +45,7 @@ use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout}; use core::ptr::NonNull; /// The default memory allocator provided by the operating system. -#[unstable(feature = "allocator_api", issue = "32838")] +#[stable(feature = "alloc_system_type", since = "1.28.0")] pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] @@ -107,7 +107,7 @@ mod platform { use System; use core::alloc::{GlobalAlloc, Layout}; - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { @@ -240,7 +240,7 @@ mod platform { ptr as *mut u8 } - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { @@ -304,7 +304,7 @@ mod platform { // No need for synchronization here as wasm is currently single-threaded static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT; - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index fd829bfe753..6cae8aaa3db 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -20,7 +20,7 @@ use sys_common::util::dumb_print; #[doc(inline)] pub use alloc_crate::alloc::*; -#[unstable(feature = "allocator_api", issue = "32838")] +#[stable(feature = "alloc_system_type", since = "1.28.0")] #[doc(inline)] pub use alloc_system::System; -- cgit 1.4.1-3-g733a5 From fd6e08a1e6bbccd00e70b23ac72dd9a9a633be30 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 19:31:00 +0200 Subject: Remove some '#[feature]' attributes for stabilized features --- src/doc/unstable-book/src/library-features/alloc-system.md | 1 - src/liballoc_system/lib.rs | 1 - src/librustc_asan/lib.rs | 3 +-- src/librustc_lsan/lib.rs | 5 ++--- src/librustc_msan/lib.rs | 5 ++--- src/librustc_tsan/lib.rs | 3 +-- src/libstd/lib.rs | 1 - src/test/compile-fail/allocator/auxiliary/system-allocator.rs | 1 - src/test/compile-fail/allocator/auxiliary/system-allocator2.rs | 1 - src/test/compile-fail/allocator/function-allocator.rs | 1 - src/test/compile-fail/allocator/not-an-allocator.rs | 2 -- src/test/compile-fail/allocator/two-allocators.rs | 2 -- src/test/compile-fail/allocator/two-allocators2.rs | 2 -- src/test/compile-fail/allocator/two-allocators3.rs | 1 - src/test/run-make-fulldeps/std-core-cycle/foo.rs | 1 - src/test/run-pass-valgrind/issue-44800.rs | 5 +---- src/test/run-pass/allocator/auxiliary/custom-as-global.rs | 1 - src/test/run-pass/allocator/custom.rs | 2 +- src/test/run-pass/allocator/xcrate-use.rs | 2 +- src/test/run-pass/thin-lto-global-allocator.rs | 2 -- 20 files changed, 9 insertions(+), 33 deletions(-) (limited to 'src/libstd') diff --git a/src/doc/unstable-book/src/library-features/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md index 9effab202ca..5663b354ac1 100644 --- a/src/doc/unstable-book/src/library-features/alloc-system.md +++ b/src/doc/unstable-book/src/library-features/alloc-system.md @@ -61,7 +61,6 @@ crate.io’s `jemallocator` crate provides equivalent functionality.) jemallocator = "0.1" ``` ```rust,ignore -#![feature(global_allocator)] #![crate_type = "dylib"] extern crate jemallocator; diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index a592868cbef..2b748c4702d 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -14,7 +14,6 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "32838")] -#![feature(global_allocator)] #![feature(allocator_api)] #![feature(core_intrinsics)] #![feature(staged_api)] diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index 3429e3bda0f..a7aeed76309 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -10,8 +10,7 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![feature(allocator_api)] -#![feature(global_allocator)] +#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs index 81a09e7e21a..a7aeed76309 100644 --- a/src/librustc_lsan/lib.rs +++ b/src/librustc_lsan/lib.rs @@ -9,10 +9,9 @@ // except according to those terms. #![sanitizer_runtime] -#![feature(sanitizer_runtime)] #![feature(alloc_system)] -#![feature(allocator_api)] -#![feature(global_allocator)] +#![cfg_attr(stage0, feature(global_allocator))] +#![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] #![unstable(feature = "sanitizer_runtime_lib", diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs index 81a09e7e21a..a7aeed76309 100644 --- a/src/librustc_msan/lib.rs +++ b/src/librustc_msan/lib.rs @@ -9,10 +9,9 @@ // except according to those terms. #![sanitizer_runtime] -#![feature(sanitizer_runtime)] #![feature(alloc_system)] -#![feature(allocator_api)] -#![feature(global_allocator)] +#![cfg_attr(stage0, feature(global_allocator))] +#![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] #![unstable(feature = "sanitizer_runtime_lib", diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs index 3429e3bda0f..a7aeed76309 100644 --- a/src/librustc_tsan/lib.rs +++ b/src/librustc_tsan/lib.rs @@ -10,8 +10,7 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![feature(allocator_api)] -#![feature(global_allocator)] +#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3972763a051..fa3d39cb1d8 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -263,7 +263,6 @@ #![feature(fnbox)] #![feature(futures_api)] #![feature(hashmap_internals)] -#![feature(heap_api)] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] diff --git a/src/test/compile-fail/allocator/auxiliary/system-allocator.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs index 37e64ba7ea1..e5650d5b7b0 100644 --- a/src/test/compile-fail/allocator/auxiliary/system-allocator.rs +++ b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs @@ -10,7 +10,6 @@ // no-prefer-dynamic -#![feature(global_allocator, allocator_api)] #![crate_type = "rlib"] use std::alloc::System; diff --git a/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs index 37e64ba7ea1..e5650d5b7b0 100644 --- a/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs +++ b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs @@ -10,7 +10,6 @@ // no-prefer-dynamic -#![feature(global_allocator, allocator_api)] #![crate_type = "rlib"] use std::alloc::System; diff --git a/src/test/compile-fail/allocator/function-allocator.rs b/src/test/compile-fail/allocator/function-allocator.rs index 50f82607b53..989c102b86e 100644 --- a/src/test/compile-fail/allocator/function-allocator.rs +++ b/src/test/compile-fail/allocator/function-allocator.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(global_allocator)] #[global_allocator] fn foo() {} //~ ERROR: allocators must be statics diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs index 140cad22f34..6559335960a 100644 --- a/src/test/compile-fail/allocator/not-an-allocator.rs +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(global_allocator, heap_api)] - #[global_allocator] static A: usize = 0; //~^ the trait bound `usize: diff --git a/src/test/compile-fail/allocator/two-allocators.rs b/src/test/compile-fail/allocator/two-allocators.rs index 5aa6b5d6777..7a97a11df20 100644 --- a/src/test/compile-fail/allocator/two-allocators.rs +++ b/src/test/compile-fail/allocator/two-allocators.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(global_allocator, allocator_api)] - use std::alloc::System; #[global_allocator] diff --git a/src/test/compile-fail/allocator/two-allocators2.rs b/src/test/compile-fail/allocator/two-allocators2.rs index ec5d985a943..e747140dfe5 100644 --- a/src/test/compile-fail/allocator/two-allocators2.rs +++ b/src/test/compile-fail/allocator/two-allocators2.rs @@ -12,8 +12,6 @@ // no-prefer-dynamic // error-pattern: the #[global_allocator] in -#![feature(global_allocator, allocator_api)] - extern crate system_allocator; use std::alloc::System; diff --git a/src/test/compile-fail/allocator/two-allocators3.rs b/src/test/compile-fail/allocator/two-allocators3.rs index c310d94f6df..dd86b02bd20 100644 --- a/src/test/compile-fail/allocator/two-allocators3.rs +++ b/src/test/compile-fail/allocator/two-allocators3.rs @@ -13,7 +13,6 @@ // no-prefer-dynamic // error-pattern: the #[global_allocator] in -#![feature(global_allocator)] extern crate system_allocator; extern crate system_allocator2; diff --git a/src/test/run-make-fulldeps/std-core-cycle/foo.rs b/src/test/run-make-fulldeps/std-core-cycle/foo.rs index 04742bba3c8..46047fb835d 100644 --- a/src/test/run-make-fulldeps/std-core-cycle/foo.rs +++ b/src/test/run-make-fulldeps/std-core-cycle/foo.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(global_allocator)] #![crate_type = "cdylib"] extern crate bar; diff --git a/src/test/run-pass-valgrind/issue-44800.rs b/src/test/run-pass-valgrind/issue-44800.rs index cfde6f32f66..29cfae16929 100644 --- a/src/test/run-pass-valgrind/issue-44800.rs +++ b/src/test/run-pass-valgrind/issue-44800.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(global_allocator, alloc_system, allocator_api)] -extern crate alloc_system; - +use std::alloc::System; use std::collections::VecDeque; -use alloc_system::System; #[global_allocator] static ALLOCATOR: System = System; diff --git a/src/test/run-pass/allocator/auxiliary/custom-as-global.rs b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs index 538f36faadf..a3f05a01c5a 100644 --- a/src/test/run-pass/allocator/auxiliary/custom-as-global.rs +++ b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs @@ -10,7 +10,6 @@ // no-prefer-dynamic -#![feature(global_allocator)] #![crate_type = "rlib"] extern crate custom; diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index 5da13bd4cb9..3a7f8fa8620 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -11,7 +11,7 @@ // aux-build:helper.rs // no-prefer-dynamic -#![feature(global_allocator, heap_api, allocator_api)] +#![feature(allocator_api)] extern crate helper; diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs index 78d604a7108..482e3b04aae 100644 --- a/src/test/run-pass/allocator/xcrate-use.rs +++ b/src/test/run-pass/allocator/xcrate-use.rs @@ -12,7 +12,7 @@ // aux-build:helper.rs // no-prefer-dynamic -#![feature(global_allocator, heap_api, allocator_api)] +#![feature(allocator_api)] extern crate custom; extern crate helper; diff --git a/src/test/run-pass/thin-lto-global-allocator.rs b/src/test/run-pass/thin-lto-global-allocator.rs index a0534ff6735..3a0e2fe01db 100644 --- a/src/test/run-pass/thin-lto-global-allocator.rs +++ b/src/test/run-pass/thin-lto-global-allocator.rs @@ -11,8 +11,6 @@ // compile-flags: -Z thinlto -C codegen-units=2 // min-llvm-version 4.0 -#![feature(allocator_api, global_allocator)] - #[global_allocator] static A: std::alloc::System = std::alloc::System; -- cgit 1.4.1-3-g733a5 From a24924f6834ea6e5bd813d006a12aef8e5dbd5e9 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 31 May 2018 20:22:59 +0200 Subject: Move Unstable Book sections for #[global_allocator] and System to std::alloc docs --- .../src/language-features/global-allocator.md | 72 -------------------- .../src/library-features/alloc-system.md | 76 ---------------------- src/liballoc_system/lib.rs | 23 +++++++ src/libstd/alloc.rs | 62 ++++++++++++++++++ 4 files changed, 85 insertions(+), 148 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/global-allocator.md delete mode 100644 src/doc/unstable-book/src/library-features/alloc-system.md (limited to 'src/libstd') diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md deleted file mode 100644 index 7dfdc487731..00000000000 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ /dev/null @@ -1,72 +0,0 @@ -# `global_allocator` - -The tracking issue for this feature is: [#27389] - -[#27389]: https://github.com/rust-lang/rust/issues/27389 - ------------------------- - -Rust programs may need to change the allocator that they're running with from -time to time. This use case is distinct from an allocator-per-collection (e.g. a -`Vec` with a custom allocator) and instead is more related to changing the -global default allocator, e.g. what `Vec` uses by default. - -Currently Rust programs don't have a specified global allocator. The compiler -may link to a version of [jemalloc] on some platforms, but this is not -guaranteed. Libraries, however, like cdylibs and staticlibs are guaranteed -to use the "system allocator" which means something like `malloc` on Unixes and -`HeapAlloc` on Windows. - -[jemalloc]: https://github.com/jemalloc/jemalloc - -The `#[global_allocator]` attribute, however, allows configuring this choice. -You can use this to implement a completely custom global allocator to route all -default allocation requests to a custom object. Defined in [RFC 1974] usage -looks like: - -[RFC 1974]: https://github.com/rust-lang/rfcs/pull/1974 - -```rust -#![feature(global_allocator, allocator_api, heap_api)] - -use std::alloc::{GlobalAlloc, System, Layout}; -use std::ptr::NonNull; - -struct MyAllocator; - -unsafe impl GlobalAlloc for MyAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - System.alloc(layout) - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - System.dealloc(ptr, layout) - } -} - -#[global_allocator] -static GLOBAL: MyAllocator = MyAllocator; - -fn main() { - // This `Vec` will allocate memory through `GLOBAL` above - let mut v = Vec::new(); - v.push(1); -} -``` - -And that's it! The `#[global_allocator]` attribute is applied to a `static` -which implements the `Alloc` trait in the `std::alloc` module. Note, though, -that the implementation is defined for `&MyAllocator`, not just `MyAllocator`. -You may wish, however, to also provide `Alloc for MyAllocator` for other use -cases. - -A crate can only have one instance of `#[global_allocator]` and this instance -may be loaded through a dependency. For example `#[global_allocator]` above -could have been placed in one of the dependencies loaded through `extern crate`. - -Note that `Alloc` itself is an `unsafe` trait, with much documentation on the -trait itself about usage and for implementors. Extra care should be taken when -implementing a global allocator as well as the allocator may be called from many -portions of the standard library, such as the panicking routine. As a result it -is highly recommended to not panic during allocation and work in as many -situations with as few dependencies as possible as well. diff --git a/src/doc/unstable-book/src/library-features/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md deleted file mode 100644 index 5663b354ac1..00000000000 --- a/src/doc/unstable-book/src/library-features/alloc-system.md +++ /dev/null @@ -1,76 +0,0 @@ -# `alloc_system` - -The tracking issue for this feature is: [#32838] - -[#32838]: https://github.com/rust-lang/rust/issues/32838 - -See also [`global_allocator`](language-features/global-allocator.html). - ------------------------- - -The compiler currently ships two default allocators: `alloc_system` and -`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators -are normal Rust crates and contain an implementation of the routines to -allocate and deallocate memory. The standard library is not compiled assuming -either one, and the compiler will decide which allocator is in use at -compile-time depending on the type of output artifact being produced. - -Binaries generated by the compiler will use `alloc_jemalloc` by default (where -available). In this situation the compiler "controls the world" in the sense of -it has power over the final link. Primarily this means that the allocator -decision can be left up the compiler. - -Dynamic and static libraries, however, will use `alloc_system` by default. Here -Rust is typically a 'guest' in another application or another world where it -cannot authoritatively decide what allocator is in use. As a result it resorts -back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing -memory. - -# Switching Allocators - -Although the compiler's default choices may work most of the time, it's often -necessary to tweak certain aspects. Overriding the compiler's decision about -which allocator is in use is done through the `#[global_allocator]` attribute: - -```rust,no_run -#![feature(alloc_system, global_allocator, allocator_api)] - -extern crate alloc_system; - -use alloc_system::System; - -#[global_allocator] -static A: System = System; - -fn main() { - let a = Box::new(4); // Allocates from the system allocator. - println!("{}", a); -} -``` - -In this example the binary generated will not link to jemalloc by default but -instead use the system allocator. Conversely to generate a dynamic library which -uses jemalloc by default one would write: - -(The `alloc_jemalloc` crate cannot be used to control the global allocator, -crate.io’s `jemallocator` crate provides equivalent functionality.) - -```toml -# Cargo.toml -[dependencies] -jemallocator = "0.1" -``` -```rust,ignore -#![crate_type = "dylib"] - -extern crate jemallocator; - -#[global_allocator] -static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; - -pub fn foo() { - let a = Box::new(4); // Allocates from jemalloc. - println!("{}", a); -} -# fn main() {} -``` diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 2b748c4702d..64348e05de7 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -44,6 +44,29 @@ use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout}; use core::ptr::NonNull; /// The default memory allocator provided by the operating system. +/// +/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows, +/// plus related functions. +/// +/// This type can be used in a `static` item +/// with the `#[global_allocator]` attribute +/// to force the global allocator to be the system’s one. +/// (The default is jemalloc for executables, on some platforms.) +/// +/// ```rust +/// use std::alloc::System; +/// +/// #[global_allocator] +/// static A: System = System; +/// +/// fn main() { +/// let a = Box::new(4); // Allocates from the system allocator. +/// println!("{}", a); +/// } +/// ``` +/// +/// It can also be used directly to allocate memory +/// independently of the standard library’s global allocator. #[stable(feature = "alloc_system_type", since = "1.28.0")] pub struct System; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 6cae8aaa3db..ae74a71dd06 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -9,6 +9,68 @@ // except according to those terms. //! Memory allocation APIs +//! +//! In a given program, the standard library has one “global” memory allocator +//! that is used for example by `Box` and `Vec`. +//! +//! Currently the default global allocator is unspecified. +//! The compiler may link to a version of [jemalloc] on some platforms, +//! but this is not guaranteed. +//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed +//! to use the [`System`] by default. +//! +//! [jemalloc]: https://github.com/jemalloc/jemalloc +//! [`System`]: struct.System.html +//! +//! # The `#[global_allocator]` attribute +//! +//! This attribute allows configuring the choice of global allocator. +//! You can use this to implement a completely custom global allocator +//! to route all default allocation requests to a custom object. +//! +//! ```rust +//! use std::alloc::{GlobalAlloc, System, Layout}; +//! +//! struct MyAllocator; +//! +//! unsafe impl GlobalAlloc for MyAllocator { +//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 { +//! System.alloc(layout) +//! } +//! +//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { +//! System.dealloc(ptr, layout) +//! } +//! } +//! +//! #[global_allocator] +//! static GLOBAL: MyAllocator = MyAllocator; +//! +//! fn main() { +//! // This `Vec` will allocate memory through `GLOBAL` above +//! let mut v = Vec::new(); +//! v.push(1); +//! } +//! ``` +//! +//! The attribute is used on a `static` item whose type implements the +//! [`GlobalAlloc`] trait. This type can be provided by an external library: +//! +//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html +//! +//! ```rust,ignore (demonstrates crates.io usage) +//! extern crate jemallocator; +//! +//! use jemallacator::Jemalloc; +//! +//! #[global_allocator] +//! static GLOBAL: Jemalloc = Jemalloc; +//! +//! fn main() {} +//! ``` +//! +//! The `#[global_allocator]` can only be used once in a crate +//! or its recursive dependencies. #![stable(feature = "alloc_module", since = "1.28.0")] -- cgit 1.4.1-3-g733a5 From af75314ecdbc5564f300467e732fdb5c923a873a Mon Sep 17 00:00:00 2001 From: sharkdp Date: Tue, 12 Jun 2018 21:03:27 +0200 Subject: Fix possibly endless loop in ReadDir iterator Certain directories in `/proc` can cause the `ReadDir` iterator to loop indefinitely. We get an error code (22) when calling libc's `readdir_r` on these directories, but `entry_ptr` is `NULL` at the same time, signalling the end of the directory stream. This change introduces an internal state to the iterator such that the `Some(Err(..))` value will only be returned once when calling `next`. Subsequent calls will return `None`. fixes #50619 --- src/libstd/sys/unix/fs.rs | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 774340388e1..6579fee14d8 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -57,7 +57,10 @@ struct InnerReadDir { } #[derive(Clone)] -pub struct ReadDir(Arc); +pub struct ReadDir { + inner: Arc, + end_of_stream: bool, +} struct Dir(*mut libc::DIR); @@ -213,7 +216,7 @@ impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.0.root, f) + fmt::Debug::fmt(&*self.inner.root, f) } } @@ -229,7 +232,7 @@ impl Iterator for ReadDir { // is safe to use in threaded applications and it is generally preferred // over the readdir_r(3C) function. super::os::set_errno(0); - let entry_ptr = libc::readdir(self.0.dirp.0); + let entry_ptr = libc::readdir(self.inner.dirp.0); if entry_ptr.is_null() { // NULL can mean either the end is reached or an error occurred. // So we had to clear errno beforehand to check for an error now. @@ -257,6 +260,10 @@ impl Iterator for ReadDir { #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))] fn next(&mut self) -> Option> { + if self.end_of_stream { + return None; + } + unsafe { let mut ret = DirEntry { entry: mem::zeroed(), @@ -264,7 +271,14 @@ impl Iterator for ReadDir { }; let mut entry_ptr = ptr::null_mut(); loop { - if readdir64_r(self.0.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { + if entry_ptr.is_null() { + // We encountered an error (which will be returned in this iteration), but + // we also reached the end of the directory stream. The `end_of_stream` + // flag is enabled to make sure that we return `None` in the next iteration + // (instead of looping forever) + self.end_of_stream = true; + } return Some(Err(Error::last_os_error())) } if entry_ptr.is_null() { @@ -287,7 +301,7 @@ impl Drop for Dir { impl DirEntry { pub fn path(&self) -> PathBuf { - self.dir.0.root.join(OsStr::from_bytes(self.name_bytes())) + self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes())) } pub fn file_name(&self) -> OsString { @@ -296,7 +310,7 @@ impl DirEntry { #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result { - let fd = cvt(unsafe {dirfd(self.dir.0.dirp.0)})?; + let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { fstatat(fd, @@ -692,7 +706,10 @@ pub fn readdir(p: &Path) -> io::Result { Err(Error::last_os_error()) } else { let inner = InnerReadDir { dirp: Dir(ptr), root }; - Ok(ReadDir(Arc::new(inner))) + Ok(ReadDir{ + inner: Arc::new(inner), + end_of_stream: false, + }) } } } -- cgit 1.4.1-3-g733a5 From 231c61a76bba716ad0a7d571f64825d57be2a75e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 13 Jun 2018 22:28:21 +0200 Subject: Add missing allow_missing_docs --- src/libstd/sys/windows/ext/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index 4b458d293bc..1f10609f32c 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -18,6 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(windows))] +#![allow(missing_docs)] pub mod ffi; pub mod fs; -- cgit 1.4.1-3-g733a5 From 8f0909c9792f01fff4ff8196194d99f59d7e3682 Mon Sep 17 00:00:00 2001 From: Chris Cesare Date: Thu, 14 Jun 2018 11:39:28 -0400 Subject: Removed two unused variables --- src/libstd/sys/redox/os.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 480765b77a0..5822216779b 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -30,9 +30,6 @@ use sys_common::mutex::Mutex; use sys::{cvt, fd, syscall}; use vec; -const TMPBUF_SZ: usize = 128; -static ENV_LOCK: Mutex = Mutex::new(); - extern { #[link_name = "__errno_location"] fn errno_location() -> *mut i32; -- cgit 1.4.1-3-g733a5 From 6a03884ce99df2002ddaa1155de65384f7767cd5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 15 Jun 2018 10:00:57 +0200 Subject: Fix issue on unix --- src/libstd/sys/unix/ext/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index c221f7c8cfe..88e4237f8e2 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -35,6 +35,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(unix))] +#![allow(missing_docs)] pub mod io; pub mod ffi; -- cgit 1.4.1-3-g733a5 From 1dd1f95af835be787231b8609163581c761d974a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 15 Jun 2018 23:23:11 +0200 Subject: Add doc for fn keyword --- src/libstd/keyword_docs.rs | 28 ++++++++++++++++++++++++++++ src/libstd/lib.rs | 5 +++++ 2 files changed, 33 insertions(+) create mode 100644 src/libstd/keyword_docs.rs (limited to 'src/libstd') diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs new file mode 100644 index 00000000000..01bd3edaee9 --- /dev/null +++ b/src/libstd/keyword_docs.rs @@ -0,0 +1,28 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(keyword = "fn")] +// +/// The `fn` keyword. +/// +/// The `fn` keyword is used to declare a function. +/// +/// Example: +/// +/// ```rust +/// fn some_function() { +/// // code goes in here +/// } +/// ``` +/// +/// For more information about functions, take a look at the [Rust Book][book]. +/// +/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html +mod fn_keyword { } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 1bdc1dc2b7c..a6061e96ae5 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -547,3 +547,8 @@ pub use stdsimd::arch; // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. include!("primitive_docs.rs"); + +// Include a number of private modules that exist solely to provide +// the rustdoc documentation for the existing keywords. Using `include!` +// because rustdoc only looks for these modules at the crate level. +include!("keyword_docs.rs"); -- cgit 1.4.1-3-g733a5 From b81da278623d9dcda1776008612bd42e1922e9c3 Mon Sep 17 00:00:00 2001 From: "NODA, Kai" Date: Sat, 9 Jun 2018 21:13:04 +0800 Subject: libstd: add an RAII utility for sys_common::mutex::Mutex Signed-off-by: NODA, Kai --- src/libstd/io/lazy.rs | 21 +++++++++++---------- src/libstd/sync/mutex.rs | 4 ++-- src/libstd/sys/redox/args.rs | 16 ++++++---------- src/libstd/sys/unix/args.rs | 14 +++++--------- src/libstd/sys/unix/os.rs | 26 +++++++++----------------- src/libstd/sys_common/at_exit_imp.rs | 27 ++++++++++++++------------- src/libstd/sys_common/mutex.rs | 26 ++++++++++++++++++++++++-- src/libstd/sys_common/thread_local.rs | 3 +-- src/libstd/thread/mod.rs | 5 +---- 9 files changed, 73 insertions(+), 69 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index 9cef4e3cdf1..d357966be92 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -20,6 +20,9 @@ pub struct Lazy { init: fn() -> Arc, } +#[inline] +const fn done() -> *mut Arc { 1_usize as *mut _ } + unsafe impl Sync for Lazy {} impl Lazy { @@ -33,17 +36,15 @@ impl Lazy { pub fn get(&'static self) -> Option> { unsafe { - self.lock.lock(); + let _guard = self.lock.lock(); let ptr = self.ptr.get(); - let ret = if ptr.is_null() { + if ptr.is_null() { Some(self.init()) - } else if ptr as usize == 1 { + } else if ptr == done() { None } else { Some((*ptr).clone()) - }; - self.lock.unlock(); - return ret + } } } @@ -53,10 +54,10 @@ impl Lazy { // the at exit handler). Otherwise we just return the freshly allocated // `Arc`. let registered = sys_common::at_exit(move || { - self.lock.lock(); - let ptr = self.ptr.get(); - self.ptr.set(1 as *mut _); - self.lock.unlock(); + let ptr = { + let _guard = self.lock.lock(); + self.ptr.replace(done()) + }; drop(Box::from_raw(ptr)) }); let ret = (self.init)(); diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index f3503b0b3a6..e5a410644b9 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -227,7 +227,7 @@ impl Mutex { #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult> { unsafe { - self.inner.lock(); + self.inner.raw_lock(); MutexGuard::new(self) } } @@ -454,7 +454,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { fn drop(&mut self) { unsafe { self.__lock.poison.done(&self.__poison); - self.__lock.inner.unlock(); + self.__lock.inner.raw_unlock(); } } } diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs index 59ae2a74a6d..556ed77372e 100644 --- a/src/libstd/sys/redox/args.rs +++ b/src/libstd/sys/redox/args.rs @@ -73,17 +73,15 @@ mod imp { CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() }).collect(); - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); assert!((*ptr).is_none()); (*ptr) = Some(box args); - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); *get_global_ptr() = None; - LOCK.unlock(); } pub fn args() -> Args { @@ -96,16 +94,14 @@ mod imp { fn clone() -> Option>> { unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); let ptr = get_global_ptr(); - let ret = (*ptr).as_ref().map(|s| (**s).clone()); - LOCK.unlock(); - return ret + (*ptr).as_ref().map(|s| (**s).clone()) } } - fn get_global_ptr() -> *mut Option>>> { - unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } + unsafe fn get_global_ptr() -> *mut Option>>> { + mem::transmute(&GLOBAL_ARGS_PTR) } } diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index e1c7ffc19e5..dc1dba6f2f9 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -82,17 +82,15 @@ mod imp { static LOCK: Mutex = Mutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = argc; ARGV = argv; - LOCK.unlock(); } pub unsafe fn cleanup() { - LOCK.lock(); + let _guard = LOCK.lock(); ARGC = 0; ARGV = ptr::null(); - LOCK.unlock(); } pub fn args() -> Args { @@ -104,13 +102,11 @@ mod imp { fn clone() -> Vec { unsafe { - LOCK.lock(); - let ret = (0..ARGC).map(|i| { + let _guard = LOCK.lock(); + (0..ARGC).map(|i| { let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }).collect(); - LOCK.unlock(); - return ret + }).collect() } } } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 4c86fddee4b..82d05f78850 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -409,10 +409,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { /// environment variables of the current process. pub fn env() -> Env { unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let mut environ = *environ(); if environ == ptr::null() { - ENV_LOCK.unlock(); panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error()); } @@ -423,12 +422,10 @@ pub fn env() -> Env { } environ = environ.offset(1); } - let ret = Env { + return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData, - }; - ENV_LOCK.unlock(); - return ret + } } fn parse(input: &[u8]) -> Option<(OsString, OsString)> { @@ -452,15 +449,14 @@ pub fn getenv(k: &OsStr) -> io::Result> { // always None as well let k = CString::new(k.as_bytes())?; unsafe { - ENV_LOCK.lock(); + let _guard = ENV_LOCK.lock(); let s = libc::getenv(k.as_ptr()) as *const libc::c_char; let ret = if s.is_null() { None } else { Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) }; - ENV_LOCK.unlock(); - return Ok(ret) + Ok(ret) } } @@ -469,10 +465,8 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { let v = CString::new(v.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) } } @@ -480,10 +474,8 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { let nbuf = CString::new(n.as_bytes())?; unsafe { - ENV_LOCK.lock(); - let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()); - ENV_LOCK.unlock(); - return ret + let _guard = ENV_LOCK.lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) } } diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index 26da51c9825..d268d9ad6f9 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -14,6 +14,7 @@ use boxed::FnBox; use ptr; +use mem; use sys_common::mutex::Mutex; type Queue = Vec>; @@ -25,6 +26,8 @@ type Queue = Vec>; static LOCK: Mutex = Mutex::new(); static mut QUEUE: *mut Queue = ptr::null_mut(); +const DONE: *mut Queue = 1_usize as *mut _; + // The maximum number of times the cleanup routines will be run. While running // the at_exit closures new ones may be registered, and this count is the number // of times the new closures will be allowed to register successfully. After @@ -35,7 +38,7 @@ unsafe fn init() -> bool { if QUEUE.is_null() { let state: Box = box Vec::new(); QUEUE = Box::into_raw(state); - } else if QUEUE as usize == 1 { + } else if QUEUE == DONE { // can't re-init after a cleanup return false } @@ -44,18 +47,18 @@ unsafe fn init() -> bool { } pub fn cleanup() { - for i in 0..ITERS { + for i in 1..=ITERS { unsafe { - LOCK.lock(); - let queue = QUEUE; - QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; - LOCK.unlock(); + let queue = { + let _guard = LOCK.lock(); + mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() }) + }; // make sure we're not recursively cleaning up - assert!(queue as usize != 1); + assert!(queue != DONE); // If we never called init, not need to cleanup! - if queue as usize != 0 { + if !queue.is_null() { let queue: Box = Box::from_raw(queue); for to_run in *queue { to_run(); @@ -66,15 +69,13 @@ pub fn cleanup() { } pub fn push(f: Box) -> bool { - let mut ret = true; unsafe { - LOCK.lock(); + let _guard = LOCK.lock(); if init() { (*QUEUE).push(f); + true } else { - ret = false; + false } - LOCK.unlock(); } - ret } diff --git a/src/libstd/sys_common/mutex.rs b/src/libstd/sys_common/mutex.rs index d1a738770d3..608355b7d70 100644 --- a/src/libstd/sys_common/mutex.rs +++ b/src/libstd/sys_common/mutex.rs @@ -37,7 +37,15 @@ impl Mutex { /// Behavior is undefined if the mutex has been moved between this and any /// previous function call. #[inline] - pub unsafe fn lock(&self) { self.0.lock() } + pub unsafe fn raw_lock(&self) { self.0.lock() } + + /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex + /// will be unlocked. + #[inline] + pub unsafe fn lock(&self) -> MutexGuard { + self.raw_lock(); + MutexGuard(&self.0) + } /// Attempts to lock the mutex without blocking, returning whether it was /// successfully acquired or not. @@ -51,8 +59,11 @@ impl Mutex { /// /// Behavior is undefined if the current thread does not actually hold the /// mutex. + /// + /// Consider switching from the pair of raw_lock() and raw_unlock() to + /// lock() whenever possible. #[inline] - pub unsafe fn unlock(&self) { self.0.unlock() } + pub unsafe fn raw_unlock(&self) { self.0.unlock() } /// Deallocates all resources associated with this mutex. /// @@ -64,3 +75,14 @@ impl Mutex { // not meant to be exported to the outside world, just the containing module pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 } + +#[must_use] +/// A simple RAII utility for the above Mutex without the poisoning semantics. +pub struct MutexGuard<'a>(&'a imp::Mutex); + +impl<'a> Drop for MutexGuard<'a> { + #[inline] + fn drop(&mut self) { + unsafe { self.0.unlock(); } + } +} diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index d0d6224de0a..75f6b9ac7fd 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs @@ -162,13 +162,12 @@ impl StaticKey { // we just simplify the whole branch. if imp::requires_synchronized_create() { static INIT_LOCK: Mutex = Mutex::new(); - INIT_LOCK.lock(); + let _guard = INIT_LOCK.lock(); let mut key = self.key.load(Ordering::SeqCst); if key == 0 { key = imp::create(self.dtor) as usize; self.key.store(key, Ordering::SeqCst); } - INIT_LOCK.unlock(); rtassert!(key != 0); return key } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 1b976b79b4c..1dacf99b64b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -935,20 +935,17 @@ impl ThreadId { static mut COUNTER: u64 = 0; unsafe { - GUARD.lock(); + let _guard = GUARD.lock(); // If we somehow use up all our bits, panic so that we're not // covering up subtle bugs of IDs being reused. if COUNTER == ::u64::MAX { - GUARD.unlock(); panic!("failed to generate unique thread ID: bitspace exhausted"); } let id = COUNTER; COUNTER += 1; - GUARD.unlock(); - ThreadId(id) } } -- cgit 1.4.1-3-g733a5 From 01e82f111e618c5907b93504df29aec152821810 Mon Sep 17 00:00:00 2001 From: Kornel Date: Sat, 26 May 2018 12:18:24 +0100 Subject: Prefer use of owned values in examples --- src/libstd/collections/hash/map.rs | 36 +++++++++++++++++++++++++----------- src/libstd/collections/hash/set.rs | 24 ++++++++++++------------ 2 files changed, 37 insertions(+), 23 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 9c77acb83ec..ee8c1dc81ad 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -276,17 +276,31 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// ``` /// use std::collections::HashMap; /// -/// // type inference lets us omit an explicit type signature (which -/// // would be `HashMap<&str, &str>` in this example). +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). /// let mut book_reviews = HashMap::new(); /// -/// // review some books. -/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); -/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); -/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); -/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); /// -/// // check for a specific one. +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). /// if !book_reviews.contains_key("Les Misérables") { /// println!("We've got {} reviews, but Les Misérables ain't one.", /// book_reviews.len()); @@ -295,16 +309,16 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// // oops, this review has a lot of spelling mistakes, let's delete it. /// book_reviews.remove("The Adventures of Sherlock Holmes"); /// -/// // look up the values associated with some keys. +/// // Look up the values associated with some keys. /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; -/// for book in &to_find { +/// for &book in &to_find { /// match book_reviews.get(book) { /// Some(review) => println!("{}: {}", book, review), /// None => println!("{} is unreviewed.", book) /// } /// } /// -/// // iterate over everything. +/// // Iterate over everything. /// for (book, review) in &book_reviews { /// println!("{}: \"{}\"", book, review); /// } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 855563a5cb8..5ac3e8f9cf7 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -49,14 +49,14 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// // Type inference lets us omit an explicit type signature (which -/// // would be `HashSet<&str>` in this example). +/// // would be `HashSet` in this example). /// let mut books = HashSet::new(); /// /// // Add some books. -/// books.insert("A Dance With Dragons"); -/// books.insert("To Kill a Mockingbird"); -/// books.insert("The Odyssey"); -/// books.insert("The Great Gatsby"); +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); /// /// // Check for a specific one. /// if !books.contains("The Winds of Winter") { @@ -80,17 +80,17 @@ use super::map::{self, HashMap, Keys, RandomState}; /// ``` /// use std::collections::HashSet; /// #[derive(Hash, Eq, PartialEq, Debug)] -/// struct Viking<'a> { -/// name: &'a str, +/// struct Viking { +/// name: String, /// power: usize, /// } /// /// let mut vikings = HashSet::new(); /// -/// vikings.insert(Viking { name: "Einar", power: 9 }); -/// vikings.insert(Viking { name: "Einar", power: 9 }); -/// vikings.insert(Viking { name: "Olaf", power: 4 }); -/// vikings.insert(Viking { name: "Harald", power: 8 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); /// /// // Use derived implementation to print the vikings. /// for x in &vikings { @@ -104,7 +104,7 @@ use super::map::{self, HashMap, Keys, RandomState}; /// use std::collections::HashSet; /// /// fn main() { -/// let viking_names: HashSet<&str> = +/// let viking_names: HashSet<&'static str> = /// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); /// // use the values stored in the set /// } -- cgit 1.4.1-3-g733a5 From 65d119cbf631affd08bc7f0934a6bd77ffb709cd Mon Sep 17 00:00:00 2001 From: Tobias Stolzmann Date: Sat, 19 May 2018 17:49:13 +0200 Subject: Stabilize std::path::Path:ancestors --- src/libstd/path.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 13f55e9261f..3dc1e9c3dad 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1042,8 +1042,6 @@ impl<'a> cmp::Ord for Components<'a> { /// # Examples /// /// ``` -/// #![feature(path_ancestors)] -/// /// use std::path::Path; /// /// let path = Path::new("/foo/bar"); @@ -1056,12 +1054,12 @@ impl<'a> cmp::Ord for Components<'a> { /// [`ancestors`]: struct.Path.html#method.ancestors /// [`Path`]: struct.Path.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "path_ancestors", issue = "48581")] +#[stable(feature = "path_ancestors", since = "1.28.0")] pub struct Ancestors<'a> { next: Option<&'a Path>, } -#[unstable(feature = "path_ancestors", issue = "48581")] +#[stable(feature = "path_ancestors", since = "1.28.0")] impl<'a> Iterator for Ancestors<'a> { type Item = &'a Path; @@ -1075,7 +1073,7 @@ impl<'a> Iterator for Ancestors<'a> { } } -#[unstable(feature = "path_ancestors", issue = "48581")] +#[stable(feature = "path_ancestors", since = "1.28.0")] impl<'a> FusedIterator for Ancestors<'a> {} //////////////////////////////////////////////////////////////////////////////// @@ -1890,8 +1888,6 @@ impl Path { /// # Examples /// /// ``` - /// #![feature(path_ancestors)] - /// /// use std::path::Path; /// /// let mut ancestors = Path::new("/foo/bar").ancestors(); @@ -1903,7 +1899,7 @@ impl Path { /// /// [`None`]: ../../std/option/enum.Option.html#variant.None /// [`parent`]: struct.Path.html#method.parent - #[unstable(feature = "path_ancestors", issue = "48581")] + #[stable(feature = "path_ancestors", since = "1.28.0")] pub fn ancestors(&self) -> Ancestors { Ancestors { next: Some(&self), -- cgit 1.4.1-3-g733a5 From 2b789bd0570983e82533f9ed30c80312ac334694 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 14 Jun 2018 00:32:30 +0200 Subject: Rename OOM to allocation error The acronym is not descriptive unless one has seen it before. * Rename the `oom` function to `handle_alloc_error`. It was **stabilized in 1.28**, so if we do this at all we need to land it this cycle. * Rename `set_oom_hook` to `set_alloc_error_hook` * Rename `take_oom_hook` to `take_alloc_error_hook` Bikeshed: `alloc` v.s. `allocator`, `error` v.s. `failure` --- src/liballoc/alloc.rs | 14 ++++----- src/liballoc/arc.rs | 4 +-- src/liballoc/raw_vec.rs | 16 +++++++---- src/liballoc/rc.rs | 4 +-- src/libcore/alloc.rs | 48 +++++++++++++++---------------- src/libstd/alloc.rs | 28 +++++++++--------- src/libstd/collections/hash/table.rs | 4 +-- src/test/run-pass/allocator-alloc-one.rs | 6 ++-- src/test/run-pass/realloc-16687.rs | 8 ++++-- src/test/run-pass/regions-mock-codegen.rs | 4 +-- 10 files changed, 72 insertions(+), 64 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 04c8063ffeb..84bd275df34 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -158,7 +158,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if !ptr.is_null() { ptr } else { - oom(layout) + handle_alloc_error(layout) } } } @@ -184,13 +184,13 @@ pub(crate) unsafe fn box_free(ptr: Unique) { /// /// The default behavior of this function is to print a message to standard error /// and abort the process. -/// It can be replaced with [`set_oom_hook`] and [`take_oom_hook`]. +/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`]. /// -/// [`set_oom_hook`]: ../../std/alloc/fn.set_oom_hook.html -/// [`take_oom_hook`]: ../../std/alloc/fn.take_oom_hook.html +/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html +/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_allocator_nounwind] -pub fn oom(layout: Layout) -> ! { +pub fn handle_alloc_error(layout: Layout) -> ! { #[allow(improper_ctypes)] extern "Rust" { #[lang = "oom"] @@ -204,14 +204,14 @@ mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use alloc::{Global, Alloc, Layout, oom}; + use alloc::{Global, Alloc, Layout, handle_alloc_error}; #[test] fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|_| oom(layout)); + .unwrap_or_else(|_| handle_alloc_error(layout)); let mut i = ptr.cast::().as_ptr(); let end = i.offset(layout.size() as isize); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index e3369f0a5b5..0fbd1408f64 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -32,7 +32,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free, oom}; +use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; use boxed::Box; use string::String; use vec::Vec; @@ -554,7 +554,7 @@ impl Arc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom(layout)); + .unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index d1f140e96a3..2369ce648fd 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -14,7 +14,7 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use alloc::{Alloc, Layout, Global, oom}; +use alloc::{Alloc, Layout, Global, handle_alloc_error}; use alloc::CollectionAllocErr; use alloc::CollectionAllocErr::*; use boxed::Box; @@ -104,7 +104,7 @@ impl RawVec { }; match result { Ok(ptr) => ptr.cast(), - Err(_) => oom(layout), + Err(_) => handle_alloc_error(layout), } }; @@ -319,7 +319,9 @@ impl RawVec { new_size); match ptr_res { Ok(ptr) => (new_cap, ptr.cast().into()), - Err(_) => oom(Layout::from_size_align_unchecked(new_size, cur.align())), + Err(_) => handle_alloc_error( + Layout::from_size_align_unchecked(new_size, cur.align()) + ), } } None => { @@ -328,7 +330,7 @@ impl RawVec { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(_) => oom(Layout::array::(new_cap).unwrap()), + Err(_) => handle_alloc_error(Layout::array::(new_cap).unwrap()), } } }; @@ -611,7 +613,9 @@ impl RawVec { old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), - Err(_) => oom(Layout::from_size_align_unchecked(new_size, align)), + Err(_) => handle_alloc_error( + Layout::from_size_align_unchecked(new_size, align) + ), } } self.cap = amount; @@ -673,7 +677,7 @@ impl RawVec { }; match (&res, fallibility) { - (Err(AllocErr), Infallible) => oom(new_layout), + (Err(AllocErr), Infallible) => handle_alloc_error(new_layout), _ => {} } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 84a6ecf7103..32d624e8fbc 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free, oom}; +use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; use string::String; use vec::Vec; @@ -662,7 +662,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom(layout)); + .unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 353688d1b85..0c074582281 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -492,10 +492,10 @@ pub unsafe trait GlobalAlloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc(&self, layout: Layout) -> *mut u8; @@ -529,10 +529,10 @@ pub unsafe trait GlobalAlloc { /// just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); @@ -589,10 +589,10 @@ pub unsafe trait GlobalAlloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -733,10 +733,10 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. @@ -843,10 +843,10 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc(&mut self, ptr: NonNull, layout: Layout, @@ -889,10 +889,10 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); @@ -917,10 +917,10 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { let usable_size = self.usable_size(&layout); self.alloc(layout).map(|p| Excess(p, usable_size.1)) @@ -941,10 +941,10 @@ pub unsafe trait Alloc { /// constraints, just as in `realloc`. /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc_excess(&mut self, ptr: NonNull, layout: Layout, @@ -986,7 +986,7 @@ pub unsafe trait Alloc { /// unable to assert that the memory block referenced by `ptr` /// could fit `layout`. /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` /// function; clients are expected either to be able to recover from /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. @@ -1041,7 +1041,7 @@ pub unsafe trait Alloc { /// unable to assert that the memory block referenced by `ptr` /// could fit `layout`. /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` /// function; clients are expected either to be able to recover from /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. @@ -1090,10 +1090,10 @@ pub unsafe trait Alloc { /// will *not* yield undefined behavior. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html fn alloc_one(&mut self) -> Result, AllocErr> where Self: Sized { @@ -1159,10 +1159,10 @@ pub unsafe trait Alloc { /// Always returns `Err` on arithmetic overflow. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the [`oom`] function, + /// allocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html fn alloc_array(&mut self, n: usize) -> Result, AllocErr> where Self: Sized { @@ -1206,10 +1206,10 @@ pub unsafe trait Alloc { /// Always returns `Err` on arithmetic overflow. /// /// Clients wishing to abort computation in response to a - /// reallocation error are encouraged to call the [`oom`] function, + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, /// rather than directly invoking `panic!` or similar. /// - /// [`oom`]: ../../alloc/alloc/fn.oom.html + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc_array(&mut self, ptr: NonNull, n_old: usize, diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index ae74a71dd06..f28e91e19b7 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -88,38 +88,38 @@ pub use alloc_system::System; static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); -/// Registers a custom OOM hook, replacing any that was previously registered. +/// Registers a custom allocation error hook, replacing any that was previously registered. /// -/// The OOM hook is invoked when an infallible memory allocation fails, before +/// The allocation error hook is invoked when an infallible memory allocation fails, before /// the runtime aborts. The default hook prints a message to standard error, -/// but this behavior can be customized with the [`set_oom_hook`] and -/// [`take_oom_hook`] functions. +/// but this behavior can be customized with the [`set_alloc_error_hook`] and +/// [`take_alloc_error_hook`] functions. /// /// The hook is provided with a `Layout` struct which contains information /// about the allocation that failed. /// -/// The OOM hook is a global resource. -#[unstable(feature = "oom_hook", issue = "51245")] -pub fn set_oom_hook(hook: fn(Layout)) { +/// The allocation error hook is a global resource. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn set_alloc_error_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); } -/// Unregisters the current OOM hook, returning it. +/// Unregisters the current allocation error hook, returning it. /// -/// *See also the function [`set_oom_hook`].* +/// *See also the function [`set_alloc_error_hook`].* /// /// If no custom hook is registered, the default hook will be returned. -#[unstable(feature = "oom_hook", issue = "51245")] -pub fn take_oom_hook() -> fn(Layout) { +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn take_alloc_error_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); if hook.is_null() { - default_oom_hook + default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } } -fn default_oom_hook(layout: Layout) { +fn default_alloc_error_hook(layout: Layout) { dumb_print(format_args!("memory allocation of {} bytes failed", layout.size())); } @@ -130,7 +130,7 @@ fn default_oom_hook(layout: Layout) { pub extern fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { - default_oom_hook + default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 55f9f4f7cfe..d14b754ddb6 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom}; +use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, handle_alloc_error}; use hash::{BuildHasher, Hash, Hasher}; use marker; use mem::{size_of, needs_drop}; @@ -699,7 +699,7 @@ impl RawTable { // point into it. let (layout, _) = calculate_layout::(capacity)?; let buffer = Global.alloc(layout).map_err(|e| match fallibility { - Infallible => oom(layout), + Infallible => handle_alloc_error(layout), Fallible => e, })?; diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index f1fdbfc702d..f15b013c07b 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -10,11 +10,13 @@ #![feature(allocator_api, nonnull)] -use std::alloc::{Alloc, Global, Layout, oom}; +use std::alloc::{Alloc, Global, Layout, handle_alloc_error}; fn main() { unsafe { - let ptr = Global.alloc_one::().unwrap_or_else(|_| oom(Layout::new::())); + let ptr = Global.alloc_one::().unwrap_or_else(|_| { + handle_alloc_error(Layout::new::()) + }); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); Global.dealloc_one(ptr); diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 7152e721eac..3b4b458bb04 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -15,7 +15,7 @@ #![feature(heap_api, allocator_api)] -use std::alloc::{Global, Alloc, Layout, oom}; +use std::alloc::{Global, Alloc, Layout, handle_alloc_error}; use std::ptr::{self, NonNull}; fn main() { @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Global.alloc(layout).unwrap_or_else(|_| oom(layout)); + let ret = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -73,7 +73,9 @@ unsafe fn test_triangle() -> bool { } let ret = Global.realloc(NonNull::new_unchecked(ptr), old, new.size()) - .unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align()))); + .unwrap_or_else(|_| handle_alloc_error( + Layout::from_size_align_unchecked(new.size(), old.align()) + )); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-codegen.rs b/src/test/run-pass/regions-mock-codegen.rs index 745a19dec4d..b58e837f3bd 100644 --- a/src/test/run-pass/regions-mock-codegen.rs +++ b/src/test/run-pass/regions-mock-codegen.rs @@ -12,7 +12,7 @@ #![feature(allocator_api)] -use std::alloc::{Alloc, Global, Layout, oom}; +use std::alloc::{Alloc, Global, Layout, handle_alloc_error}; use std::ptr::NonNull; struct arena(()); @@ -33,7 +33,7 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let layout = Layout::new::(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| oom(layout)); + let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); &*(ptr.as_ptr() as *const _) } } -- cgit 1.4.1-3-g733a5 From 03a40b31a74d62923ab616bb64e24c7f90ef3daf Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Tue, 19 Jun 2018 09:46:51 -0700 Subject: Update zx_cprng_draw_new on Fuchsia Fuchsia is changing the semantics for zx_cprng_draw and zx_cprng_draw_new is a temporary name for the new semantics. --- src/libstd/sys/unix/rand.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index caa18945765..3f7f0671490 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -183,15 +183,14 @@ mod imp { mod imp { #[link(name = "zircon")] extern { - fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; + fn zx_cprng_draw_new(buffer: *mut u8, len: usize) -> i32; } fn getrandom(buf: &mut [u8]) -> Result { unsafe { - let mut actual = 0; - let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); + let status = zx_cprng_draw_new(buf.as_mut_ptr(), buf.len()); if status == 0 { - Ok(actual) + Ok(buf.len()) } else { Err(status) } -- cgit 1.4.1-3-g733a5 From d259f4364738d911128d6e8ad863d0066733a343 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Jun 2018 00:04:59 +0200 Subject: Fix doc build on unknown windows target --- src/libstd/sys/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index 1231898ed7e..b5bf4044be4 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -67,6 +67,7 @@ cfg_if! { // (missing things in `libc` which is empty) so just omit everything // with an empty module #[unstable(issue = "0", feature = "std_internals")] + #[allow(missing_docs)] pub mod unix_ext {} } else { // On other platforms like Windows document the bare bones of unix @@ -80,6 +81,7 @@ cfg_if! { cfg_if! { if #[cfg(windows)] { // On windows we'll just be documenting what's already available + #[allow(missing_docs)] pub use self::ext as windows_ext; } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] { // On CloudABI and wasm right now the shim below doesn't compile, so -- cgit 1.4.1-3-g733a5 From 776544f011a6a5beccb7923a261b0dcecdd2396a Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 9 Jun 2018 16:53:36 -0700 Subject: Add message to `rustc_on_unimplemented` attributes in core --- src/liballoc/vec.rs | 10 +- src/libcore/cmp.rs | 10 +- src/libcore/iter/traits.rs | 7 +- src/libcore/marker.rs | 10 +- src/libcore/ops/index.rs | 10 +- src/libstd/panic.rs | 15 ++- src/libsyntax/parse/parser.rs | 8 -- src/test/compile-fail/associated-types-unsized.rs | 2 +- src/test/compile-fail/bad-method-typaram-kind.rs | 2 +- src/test/compile-fail/bad-sized.rs | 4 +- .../builtin-superkinds-double-superkind.rs | 2 +- .../compile-fail/builtin-superkinds-in-metadata.rs | 2 +- src/test/compile-fail/builtin-superkinds-simple.rs | 2 +- .../builtin-superkinds-typaram-not-send.rs | 3 +- ...sure-bounds-cant-promote-superkind-in-struct.rs | 2 +- src/test/compile-fail/dst-bad-assign-2.rs | 2 +- src/test/compile-fail/dst-bad-assign-3.rs | 2 +- src/test/compile-fail/dst-bad-assign.rs | 2 +- src/test/compile-fail/dst-bad-deep-2.rs | 2 +- src/test/compile-fail/dst-bad-deep.rs | 2 +- .../compile-fail/dst-object-from-unsized-type.rs | 8 +- src/test/compile-fail/dst-sized-trait-param.rs | 4 +- .../compile-fail/extern-types-not-sync-send.rs | 2 +- src/test/compile-fail/extern-types-unsized.rs | 8 +- src/test/compile-fail/issue-14366.rs | 2 +- src/test/compile-fail/issue-15756.rs | 2 +- src/test/compile-fail/issue-17651.rs | 2 +- src/test/compile-fail/issue-18107.rs | 2 +- src/test/compile-fail/issue-18919.rs | 2 +- src/test/compile-fail/issue-20005.rs | 2 +- src/test/compile-fail/issue-20433.rs | 2 +- src/test/compile-fail/issue-20605.rs | 2 +- src/test/compile-fail/issue-21763.rs | 2 +- src/test/compile-fail/issue-22874.rs | 2 +- src/test/compile-fail/issue-23281.rs | 2 +- src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/issue-27060-2.rs | 2 +- src/test/compile-fail/issue-27078.rs | 2 +- src/test/compile-fail/issue-35988.rs | 2 +- src/test/compile-fail/issue-38954.rs | 2 +- src/test/compile-fail/issue-41229-ref-str.rs | 4 +- src/test/compile-fail/issue-42312.rs | 4 +- src/test/compile-fail/issue-5883.rs | 4 +- src/test/compile-fail/issue-7013.rs | 2 +- src/test/compile-fail/kindck-impl-type-params.rs | 8 +- src/test/compile-fail/kindck-nonsendable-1.rs | 2 +- src/test/compile-fail/kindck-send-object.rs | 3 +- src/test/compile-fail/kindck-send-object1.rs | 2 +- src/test/compile-fail/kindck-send-object2.rs | 3 +- src/test/compile-fail/kindck-send-owned.rs | 3 +- src/test/compile-fail/kindck-send-unsafe.rs | 2 +- src/test/compile-fail/no-send-res-ports.rs | 2 +- src/test/compile-fail/no_send-enum.rs | 2 +- src/test/compile-fail/no_send-rc.rs | 2 +- src/test/compile-fail/no_send-struct.rs | 2 +- src/test/compile-fail/not-panic-safe-2.rs | 4 +- src/test/compile-fail/not-panic-safe-3.rs | 4 +- src/test/compile-fail/not-panic-safe-4.rs | 4 +- src/test/compile-fail/not-panic-safe-6.rs | 4 +- src/test/compile-fail/not-panic-safe.rs | 3 +- src/test/compile-fail/range-1.rs | 2 +- src/test/compile-fail/range_traits-1.rs | 24 ++--- src/test/compile-fail/str-idx.rs | 2 +- src/test/compile-fail/str-mut-idx.rs | 6 +- src/test/compile-fail/substs-ppaux.rs | 4 +- .../compile-fail/trait-bounds-not-on-bare-trait.rs | 2 +- src/test/compile-fail/traits-negative-impls.rs | 14 +-- .../typeck-default-trait-impl-negation-send.rs | 2 +- src/test/compile-fail/union/union-unsized.rs | 6 +- src/test/compile-fail/unsized-bare-typaram.rs | 3 +- src/test/compile-fail/unsized-enum.rs | 2 +- .../unsized-inherent-impl-self-type.rs | 3 +- src/test/compile-fail/unsized-struct.rs | 4 +- .../compile-fail/unsized-trait-impl-self-type.rs | 3 +- .../compile-fail/unsized-trait-impl-trait-arg.rs | 2 +- src/test/compile-fail/unsized3.rs | 12 +-- src/test/compile-fail/unsized5.rs | 18 ++-- src/test/compile-fail/unsized6.rs | 39 ++++--- src/test/compile-fail/unsized7.rs | 2 +- src/test/ui/const-unsized.rs | 8 +- src/test/ui/const-unsized.stderr | 8 +- src/test/ui/error-codes/E0277-2.rs | 2 +- src/test/ui/error-codes/E0277-2.stderr | 2 +- src/test/ui/error-codes/E0277.rs | 2 +- src/test/ui/error-codes/E0277.stderr | 2 +- src/test/ui/feature-gate-trivial_bounds.stderr | 6 +- src/test/ui/generator/sized-yield.rs | 6 +- src/test/ui/generator/sized-yield.stderr | 11 +- src/test/ui/impl-trait/auto-trait-leak.rs | 2 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 2 +- src/test/ui/impl-trait/auto-trait-leak2.rs | 4 +- src/test/ui/impl-trait/auto-trait-leak2.stderr | 4 +- .../ui/interior-mutability/interior-mutability.rs | 3 +- .../interior-mutability/interior-mutability.stderr | 6 +- src/test/ui/mismatched_types/binops.rs | 4 +- src/test/ui/mismatched_types/binops.stderr | 12 +-- src/test/ui/mismatched_types/cast-rfc0401.rs | 4 +- src/test/ui/mismatched_types/cast-rfc0401.stderr | 8 +- src/test/ui/partialeq_help.stderr | 4 +- src/test/ui/resolve/issue-5035-2.rs | 3 +- src/test/ui/resolve/issue-5035-2.stderr | 4 +- src/test/ui/suggestions/str-array-assignment.rs | 2 +- .../ui/suggestions/str-array-assignment.stderr | 2 +- src/test/ui/trait-suggest-where-clause.rs | 8 +- src/test/ui/trait-suggest-where-clause.stderr | 8 +- src/test/ui/trivial-bounds-leak.stderr | 2 +- src/test/ui/type-check-defaults.rs | 14 +-- src/test/ui/type-check-defaults.stderr | 8 +- src/test/ui/union/union-sized-field.rs | 9 +- src/test/ui/union/union-sized-field.stderr | 16 +-- src/test/ui/unsized-enum2.rs | 57 +++++++---- src/test/ui/unsized-enum2.stderr | 112 ++++++++++----------- 112 files changed, 394 insertions(+), 318 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index b5739e1a825..752a6c966d5 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1693,7 +1693,10 @@ impl Hash for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] +#[rustc_on_unimplemented( + message="vector indices are of type `usize` or ranges of `usize`", + label="vector indices are of type `usize` or ranges of `usize`", +)] impl Index for Vec where I: ::core::slice::SliceIndex<[T]>, @@ -1707,7 +1710,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] +#[rustc_on_unimplemented( + message="vector indices are of type `usize` or ranges of `usize`", + label="vector indices are of type `usize` or ranges of `usize`", +)] impl IndexMut for Vec where I: ::core::slice::SliceIndex<[T]>, diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 13e838773a5..3626a266ad5 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -108,7 +108,10 @@ use self::Ordering::*; #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "==")] #[doc(alias = "!=")] -#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] +#[rustc_on_unimplemented( + message="can't compare `{Self}` with `{Rhs}`", + label="no implementation for `{Self} == {Rhs}`", +)] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -611,7 +614,10 @@ impl PartialOrd for Ordering { #[doc(alias = "<")] #[doc(alias = "<=")] #[doc(alias = ">=")] -#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] +#[rustc_on_unimplemented( + message="can't compare `{Self}` with `{Rhs}`", + label="no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`", +)] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. /// diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 3d2ce9e6b10..4b2c1aa551e 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -104,8 +104,11 @@ use super::LoopState; /// assert_eq!(c.0, vec![0, 1, 2, 3, 4]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented="a collection of type `{Self}` cannot be \ - built from an iterator over elements of type `{A}`"] +#[rustc_on_unimplemented( + message="a collection of type `{Self}` cannot be built from an iterator \ + over elements of type `{A}`", + label="a collection of type `{Self}` cannot be built from `std::iter::Iterator`", +)] pub trait FromIterator: Sized { /// Creates a value from an iterator. /// diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3d3f63ecf37..d5416e393f4 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -39,7 +39,10 @@ use hash::Hasher; /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +#[rustc_on_unimplemented( + message="`{Self}` cannot be sent between threads safely", + label="`{Self}` cannot be sent between threads safely" +)] pub unsafe auto trait Send { // empty. } @@ -88,7 +91,10 @@ impl !Send for *mut T { } /// [trait object]: ../../book/first-edition/trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] -#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] +#[rustc_on_unimplemented( + message="`{Self}` does not have a constant size known at compile-time", + label="`{Self}` does not have a constant size known at compile-time" +)] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized { // Empty. diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index 0a0e92a9180..1ac80ecc96f 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -60,7 +60,10 @@ /// assert_eq!(nucleotide_count[Nucleotide::T], 12); /// ``` #[lang = "index"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] +#[rustc_on_unimplemented( + message="the type `{Self}` cannot be indexed by `{Idx}`", + label="`{Self}` cannot be indexed by `{Idx}`", +)] #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "]")] #[doc(alias = "[")] @@ -147,7 +150,10 @@ pub trait Index { /// balance[Side::Left] = Weight::Kilogram(3.0); /// ``` #[lang = "index_mut"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] +#[rustc_on_unimplemented( + message="the type `{Self}` cannot be mutably indexed by `{Idx}`", + label="`{Self}` cannot be mutably indexed by `{Idx}`", +)] #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "[")] #[doc(alias = "]")] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 4b5a063ea73..2c11c262488 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -110,8 +110,10 @@ pub use core::panic::{PanicInfo, Location}; /// /// [`AssertUnwindSafe`]: ./struct.AssertUnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ - across an unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may not be safely transferred across an unwind boundary", + label="`{Self}` may not be safely transferred across an unwind boundary", +)] pub auto trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered @@ -126,9 +128,12 @@ pub auto trait UnwindSafe {} /// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html /// [`UnwindSafe`]: ./trait.UnwindSafe.html #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ - and a reference may not be safely transferrable \ - across a catch_unwind boundary"] +#[rustc_on_unimplemented( + message="the type `{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", + label="`{Self}` may contain interior mutability and a reference may not be safely \ + transferrable across a catch_unwind boundary", +)] pub auto trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index afb0931f950..5d04aa711c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1204,14 +1204,6 @@ impl<'a> Parser<'a> { fn span_fatal_err>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> { err.span_err(sp, self.diagnostic()) } - fn span_fatal_help>(&self, - sp: S, - m: &str, - help: &str) -> DiagnosticBuilder<'a> { - let mut err = self.sess.span_diagnostic.struct_span_fatal(sp, m); - err.help(help); - err - } fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(self.span, m) } diff --git a/src/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs index f1827022964..8c0ce26b294 100644 --- a/src/test/compile-fail/associated-types-unsized.rs +++ b/src/test/compile-fail/associated-types-unsized.rs @@ -14,7 +14,7 @@ trait Get { } fn foo(t: T) { - let x = t.get(); //~ ERROR `::Value: std::marker::Sized` is not + let x = t.get(); //~ ERROR `::Value` does not have a constant size known at compile-time } fn main() { diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs index 5be90f05018..7cef3f13dfc 100644 --- a/src/test/compile-fail/bad-method-typaram-kind.rs +++ b/src/test/compile-fail/bad-method-typaram-kind.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo() { - 1.bar::(); //~ ERROR `T: std::marker::Send` is not satisfied + 1.bar::(); //~ ERROR `T` cannot be sent between threads safely } trait bar { diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index df3da5096bf..55b009aef4f 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -13,6 +13,6 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied - //~| ERROR the trait bound `Trait: std::marker::Sized` is not satisfied + //~| ERROR `Trait` does not have a constant size known at compile-time + //~| ERROR `Trait` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/builtin-superkinds-double-superkind.rs b/src/test/compile-fail/builtin-superkinds-double-superkind.rs index 261881d880b..3f7f2adabdf 100644 --- a/src/test/compile-fail/builtin-superkinds-double-superkind.rs +++ b/src/test/compile-fail/builtin-superkinds-double-superkind.rs @@ -14,7 +14,7 @@ trait Foo : Send+Sync { } impl Foo for (T,) { } -//~^ ERROR the trait bound `T: std::marker::Send` is not satisfied in `(T,)` [E0277] +//~^ ERROR `T` cannot be sent between threads safely [E0277] impl Foo for (T,T) { } //~^ ERROR `T` cannot be shared between threads safely [E0277] diff --git a/src/test/compile-fail/builtin-superkinds-in-metadata.rs b/src/test/compile-fail/builtin-superkinds-in-metadata.rs index de2084c4e81..88b5a3fbb55 100644 --- a/src/test/compile-fail/builtin-superkinds-in-metadata.rs +++ b/src/test/compile-fail/builtin-superkinds-in-metadata.rs @@ -22,6 +22,6 @@ struct X(T); impl RequiresShare for X { } impl RequiresRequiresShareAndSend for X { } -//~^ ERROR `T: std::marker::Send` is not satisfied +//~^ ERROR `T` cannot be sent between threads safely [E0277] fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs index 6dc5f39cb30..22dc9598d29 100644 --- a/src/test/compile-fail/builtin-superkinds-simple.rs +++ b/src/test/compile-fail/builtin-superkinds-simple.rs @@ -14,6 +14,6 @@ trait Foo : Send { } impl Foo for std::rc::Rc { } -//~^ ERROR `std::rc::Rc: std::marker::Send` is not satisfied +//~^ ERROR `std::rc::Rc` cannot be sent between threads safely fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs index d4bb8de13d0..e0b2043c110 100644 --- a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs +++ b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs @@ -12,6 +12,7 @@ trait Foo : Send { } -impl Foo for T { } //~ ERROR `T: std::marker::Send` is not satisfied +impl Foo for T { } +//~^ ERROR `T` cannot be sent between threads safely fn main() { } diff --git a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs index b9224e7be7f..12e9fb30902 100644 --- a/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs +++ b/src/test/compile-fail/closure-bounds-cant-promote-superkind-in-struct.rs @@ -13,7 +13,7 @@ struct X where F: FnOnce() + 'static + Send { } fn foo(blk: F) -> X where F: FnOnce() + 'static { - //~^ ERROR `F: std::marker::Send` is not satisfied + //~^ ERROR `F` cannot be sent between threads safely return X { field: blk }; } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 10c8f1eed00..c3cbc904842 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -43,5 +43,5 @@ pub fn main() { let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = *z; - //~^ ERROR `ToBar: std::marker::Sized` is not satisfied + //~^ ERROR `ToBar` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-assign-3.rs b/src/test/compile-fail/dst-bad-assign-3.rs index ceaa3716232..1cd5b51fe34 100644 --- a/src/test/compile-fail/dst-bad-assign-3.rs +++ b/src/test/compile-fail/dst-bad-assign-3.rs @@ -45,5 +45,5 @@ pub fn main() { //~| expected type `ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR `ToBar: std::marker::Sized` is not satisfied + //~| ERROR `ToBar` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 4f7d07600ad..dcd78ac044c 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -47,5 +47,5 @@ pub fn main() { //~| expected type `ToBar` //~| found type `Bar1` //~| expected trait ToBar, found struct `Bar1` - //~| ERROR `ToBar: std::marker::Sized` is not satisfied + //~| ERROR `ToBar` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-deep-2.rs b/src/test/compile-fail/dst-bad-deep-2.rs index 0c812b1d815..9ed2ec8d98d 100644 --- a/src/test/compile-fail/dst-bad-deep-2.rs +++ b/src/test/compile-fail/dst-bad-deep-2.rs @@ -19,5 +19,5 @@ pub fn main() { let f: ([isize; 3],) = ([5, 6, 7],); let g: &([isize],) = &f; let h: &(([isize],),) = &(*g,); - //~^ ERROR `[isize]: std::marker::Sized` is not satisfied + //~^ ERROR `[isize]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index f508364d751..9b575ae4aad 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -21,5 +21,5 @@ pub fn main() { let f: Fat<[isize; 3]> = Fat { ptr: [5, 6, 7] }; let g: &Fat<[isize]> = &f; let h: &Fat> = &Fat { ptr: *g }; - //~^ ERROR `[isize]: std::marker::Sized` is not satisfied + //~^ ERROR `[isize]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs index 8fafd78d407..678eef76fde 100644 --- a/src/test/compile-fail/dst-object-from-unsized-type.rs +++ b/src/test/compile-fail/dst-object-from-unsized-type.rs @@ -16,22 +16,22 @@ impl Foo for [u8] {} fn test1(t: &T) { let u: &Foo = t; - //~^ ERROR `T: std::marker::Sized` is not satisfied + //~^ ERROR `T` does not have a constant size known at compile-time } fn test2(t: &T) { let v: &Foo = t as &Foo; - //~^ ERROR `T: std::marker::Sized` is not satisfied + //~^ ERROR `T` does not have a constant size known at compile-time } fn test3() { let _: &[&Foo] = &["hi"]; - //~^ ERROR `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time } fn test4(x: &[u8]) { let _: &Foo = x as &Foo; - //~^ ERROR `[u8]: std::marker::Sized` is not satisfied + //~^ ERROR `[u8]` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/dst-sized-trait-param.rs b/src/test/compile-fail/dst-sized-trait-param.rs index bd5fd3ee3b7..cafd67809f8 100644 --- a/src/test/compile-fail/dst-sized-trait-param.rs +++ b/src/test/compile-fail/dst-sized-trait-param.rs @@ -15,9 +15,9 @@ trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized impl Foo<[isize]> for usize { } -//~^ ERROR `[isize]: std::marker::Sized` is not satisfied +//~^ ERROR `[isize]` does not have a constant size known at compile-time impl Foo for [usize] { } -//~^ ERROR `[usize]: std::marker::Sized` is not satisfied +//~^ ERROR `[usize]` does not have a constant size known at compile-time pub fn main() { } diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs index 6a7a515ba5f..10abb80a2f7 100644 --- a/src/test/compile-fail/extern-types-not-sync-send.rs +++ b/src/test/compile-fail/extern-types-not-sync-send.rs @@ -24,5 +24,5 @@ fn main() { //~^ ERROR `A` cannot be shared between threads safely [E0277] assert_send::(); - //~^ ERROR the trait bound `A: std::marker::Send` is not satisfied + //~^ ERROR `A` cannot be sent between threads safely [E0277] } diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs index faa27894806..b3e19899a67 100644 --- a/src/test/compile-fail/extern-types-unsized.rs +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -30,14 +30,14 @@ fn assert_sized() { } fn main() { assert_sized::(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time assert_sized::(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time assert_sized::>(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time assert_sized::>>(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + //~^ ERROR `A` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 84452accc9a..7b4954a2d4e 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -10,5 +10,5 @@ fn main() { let _x = "test" as &::std::any::Any; -//~^ ERROR `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-15756.rs b/src/test/compile-fail/issue-15756.rs index 41349d7d744..0df82de8338 100644 --- a/src/test/compile-fail/issue-15756.rs +++ b/src/test/compile-fail/issue-15756.rs @@ -15,7 +15,7 @@ fn dft_iter<'a, T>(arg1: Chunks<'a,T>, arg2: ChunksMut<'a,T>) { for &mut something -//~^ ERROR `[T]: std::marker::Sized` is not satisfied + //~^ ERROR `[T]` does not have a constant size known at compile-time in arg2 { } diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 4996da057dd..13548b06ea1 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -13,5 +13,5 @@ fn main() { (|| Box::new(*(&[0][..])))(); - //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-18107.rs b/src/test/compile-fail/issue-18107.rs index 33d68c121bf..5faa8885e73 100644 --- a/src/test/compile-fail/issue-18107.rs +++ b/src/test/compile-fail/issue-18107.rs @@ -12,7 +12,7 @@ pub trait AbstractRenderer {} fn _create_render(_: &()) -> AbstractRenderer -//~^ ERROR: `AbstractRenderer + 'static: std::marker::Sized` is not satisfied +//~^ ERROR: `AbstractRenderer + 'static` does not have a constant size known at compile-time { match 0 { _ => unimplemented!() diff --git a/src/test/compile-fail/issue-18919.rs b/src/test/compile-fail/issue-18919.rs index 3e21360721b..14b776cb1ff 100644 --- a/src/test/compile-fail/issue-18919.rs +++ b/src/test/compile-fail/issue-18919.rs @@ -11,7 +11,7 @@ type FuncType<'f> = Fn(&isize) -> isize + 'f; fn ho_func(f: Option) { - //~^ ERROR: `for<'r> std::ops::Fn(&'r isize) -> isize: std::marker::Sized` is not satisfied + //~^ ERROR: `for<'r> std::ops::Fn(&'r isize) -> isize` does not have a constant size known at } fn main() {} diff --git a/src/test/compile-fail/issue-20005.rs b/src/test/compile-fail/issue-20005.rs index b02757fb5a3..ab47f687fc2 100644 --- a/src/test/compile-fail/issue-20005.rs +++ b/src/test/compile-fail/issue-20005.rs @@ -15,7 +15,7 @@ trait From { } trait To { - fn to( //~ ERROR `Self: std::marker::Sized` is not satisfied + fn to( //~ ERROR `Self` does not have a constant size known at compile-time self ) -> >::Result where Dst: From { From::from(self) diff --git a/src/test/compile-fail/issue-20433.rs b/src/test/compile-fail/issue-20433.rs index d1a139e698e..d8ca00d313f 100644 --- a/src/test/compile-fail/issue-20433.rs +++ b/src/test/compile-fail/issue-20433.rs @@ -14,5 +14,5 @@ struct The; impl The { fn iceman(c: Vec<[i32]>) {} - //~^ ERROR the trait bound `[i32]: std::marker::Sized` is not satisfied + //~^ ERROR `[i32]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/issue-20605.rs b/src/test/compile-fail/issue-20605.rs index 5eb0e4360fc..c5a724bba80 100644 --- a/src/test/compile-fail/issue-20605.rs +++ b/src/test/compile-fail/issue-20605.rs @@ -10,7 +10,7 @@ fn changer<'a>(mut things: Box>) { for item in *things { *item = 0 } -//~^ ERROR the trait bound `std::iter::Iterator: std::marker::Sized` is not satisfied +//~^ ERROR `std::iter::Iterator` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-21763.rs b/src/test/compile-fail/issue-21763.rs index cb0baee0a87..b4f952c87d4 100644 --- a/src/test/compile-fail/issue-21763.rs +++ b/src/test/compile-fail/issue-21763.rs @@ -17,5 +17,5 @@ fn foo() {} fn main() { foo::, Rc<()>>>(); - //~^ ERROR: `std::rc::Rc<()>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely } diff --git a/src/test/compile-fail/issue-22874.rs b/src/test/compile-fail/issue-22874.rs index 0df84a436c0..de176486af7 100644 --- a/src/test/compile-fail/issue-22874.rs +++ b/src/test/compile-fail/issue-22874.rs @@ -10,7 +10,7 @@ struct Table { rows: [[String]], - //~^ ERROR the trait bound `[std::string::String]: std::marker::Sized` is not satisfied [E0277] + //~^ ERROR `[std::string::String]` does not have a constant size known at compile-time } fn f(table: &Table) -> &[String] { diff --git a/src/test/compile-fail/issue-23281.rs b/src/test/compile-fail/issue-23281.rs index 5feeb36b1e4..fdab3b59d1b 100644 --- a/src/test/compile-fail/issue-23281.rs +++ b/src/test/compile-fail/issue-23281.rs @@ -14,7 +14,7 @@ pub struct Struct; impl Struct { pub fn function(funs: Vec ()>) {} - //~^ ERROR the trait bound `std::ops::Fn() + 'static: std::marker::Sized` is not satisfied + //~^ ERROR `std::ops::Fn() + 'static` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index acd50bcf9e1..5f36bbcf5fd 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -11,7 +11,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types - //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied + //~| ERROR: `std::ops::Fn() -> u32 + 'static` does not have a constant size known at compile-time 0 }; } diff --git a/src/test/compile-fail/issue-27060-2.rs b/src/test/compile-fail/issue-27060-2.rs index 28180b05c8d..123bbf3358d 100644 --- a/src/test/compile-fail/issue-27060-2.rs +++ b/src/test/compile-fail/issue-27060-2.rs @@ -10,7 +10,7 @@ #[repr(packed)] pub struct Bad { - data: T, //~ ERROR `T: std::marker::Sized` is not satisfied + data: T, //~ ERROR `T` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-27078.rs b/src/test/compile-fail/issue-27078.rs index f34bef62249..32933fa6176 100644 --- a/src/test/compile-fail/issue-27078.rs +++ b/src/test/compile-fail/issue-27078.rs @@ -13,7 +13,7 @@ trait Foo { const BAR: i32; fn foo(self) -> &'static i32 { - //~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied + //~^ ERROR `Self` does not have a constant size known at compile-time &::BAR } } diff --git a/src/test/compile-fail/issue-35988.rs b/src/test/compile-fail/issue-35988.rs index c2e6a88a57b..8f5b68986e5 100644 --- a/src/test/compile-fail/issue-35988.rs +++ b/src/test/compile-fail/issue-35988.rs @@ -10,7 +10,7 @@ enum E { V([Box]), - //~^ ERROR the trait bound `[std::boxed::Box]: std::marker::Sized` is not satisfied [E0277] + //~^ ERROR `[std::boxed::Box]` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/issue-38954.rs b/src/test/compile-fail/issue-38954.rs index 896728b6da0..960099f3193 100644 --- a/src/test/compile-fail/issue-38954.rs +++ b/src/test/compile-fail/issue-38954.rs @@ -9,6 +9,6 @@ // except according to those terms. fn _test(ref _p: str) {} -//~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied [E0277] +//~^ ERROR `str` does not have a constant size known at compile-time fn main() { } diff --git a/src/test/compile-fail/issue-41229-ref-str.rs b/src/test/compile-fail/issue-41229-ref-str.rs index 31bc21c23ba..b1e24c818d8 100644 --- a/src/test/compile-fail/issue-41229-ref-str.rs +++ b/src/test/compile-fail/issue-41229-ref-str.rs @@ -9,8 +9,6 @@ // except according to those terms. pub fn example(ref s: str) {} -//~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied -//~| `str` does not have a constant size known at compile-time -//~| the trait `std::marker::Sized` is not implemented for `str` +//~^ ERROR `str` does not have a constant size known at compile-time fn main() {} diff --git a/src/test/compile-fail/issue-42312.rs b/src/test/compile-fail/issue-42312.rs index 06573b42b59..89eb5c5ebc1 100644 --- a/src/test/compile-fail/issue-42312.rs +++ b/src/test/compile-fail/issue-42312.rs @@ -12,10 +12,10 @@ use std::ops::Deref; pub trait Foo { fn baz(_: Self::Target) where Self: Deref {} - //~^ ERROR `::Target: std::marker::Sized` is not satisfied + //~^ ERROR `::Target` does not have a constant size known at } pub fn f(_: ToString) {} -//~^ ERROR the trait bound `std::string::ToString + 'static: std::marker::Sized` is not satisfied +//~^ ERROR `std::string::ToString + 'static` does not have a constant size known at compile-time fn main() { } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index e14d9f3a35c..580625f4955 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -15,8 +15,8 @@ struct Struct { } fn new_struct(r: A+'static) - -> Struct { //~^ ERROR `A + 'static: std::marker::Sized` is not satisfied - //~^ ERROR `A + 'static: std::marker::Sized` is not satisfied + -> Struct { //~^ ERROR `A + 'static` does not have a constant size known at compile-time + //~^ ERROR `A + 'static` does not have a constant size known at compile-time Struct { r: r } } diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index 95bbd4eccf4..0c19780bcb4 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -34,5 +34,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR `std::rc::Rc>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 2a86cdef981..3a0e66f58e0 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -26,15 +26,15 @@ impl Gettable for S {} fn f(val: T) { let t: S = S(marker::PhantomData); let a = &t as &Gettable; - //~^ ERROR : std::marker::Send` is not satisfied - //~^^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR `T` cannot be sent between threads safely + //~| ERROR : std::marker::Copy` is not satisfied } fn g(val: T) { let t: S = S(marker::PhantomData); let a: &Gettable = &t; - //~^ ERROR : std::marker::Send` is not satisfied - //~^^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR `T` cannot be sent between threads safely + //~| ERROR : std::marker::Copy` is not satisfied } fn foo<'a>() { diff --git a/src/test/compile-fail/kindck-nonsendable-1.rs b/src/test/compile-fail/kindck-nonsendable-1.rs index dd77c2c138f..43c212b2af5 100644 --- a/src/test/compile-fail/kindck-nonsendable-1.rs +++ b/src/test/compile-fail/kindck-nonsendable-1.rs @@ -18,5 +18,5 @@ fn bar(_: F) { } fn main() { let x = Rc::new(3); bar(move|| foo(x)); - //~^ ERROR : std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc` cannot be sent between threads safely } diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index a84eae0bfda..a3eb47be3ee 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -24,7 +24,8 @@ fn object_ref_with_static_bound_not_ok() { } fn box_object_with_no_bound_not_ok<'a>() { - assert_send::>(); //~ ERROR : std::marker::Send` is not satisfied + assert_send::>(); + //~^ ERROR `Dummy` cannot be sent between threads safely } fn object_with_send_bound_ok() { diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index 66865bbcc7e..673a6abc5f0 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -37,7 +37,7 @@ fn test61() { // them not ok fn test_71<'a>() { assert_send::>(); - //~^ ERROR : std::marker::Send` is not satisfied + //~^ ERROR `Dummy + 'a` cannot be sent between threads safely } fn main() { } diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs index 51bc587d74f..3a935af2000 100644 --- a/src/test/compile-fail/kindck-send-object2.rs +++ b/src/test/compile-fail/kindck-send-object2.rs @@ -19,7 +19,8 @@ fn test50() { } fn test53() { - assert_send::>(); //~ ERROR : std::marker::Send` is not satisfied + assert_send::>(); + //~^ ERROR `Dummy` cannot be sent between threads safely } // ...unless they are properly bounded diff --git a/src/test/compile-fail/kindck-send-owned.rs b/src/test/compile-fail/kindck-send-owned.rs index 583381a1c28..e48460a8753 100644 --- a/src/test/compile-fail/kindck-send-owned.rs +++ b/src/test/compile-fail/kindck-send-owned.rs @@ -19,7 +19,8 @@ fn test32() { assert_send:: >(); } // but not if they own a bad thing fn test40() { - assert_send::>(); //~ ERROR : std::marker::Send` is not satisfied + assert_send::>(); + //~^ ERROR `*mut u8` cannot be sent between threads safely } fn main() { } diff --git a/src/test/compile-fail/kindck-send-unsafe.rs b/src/test/compile-fail/kindck-send-unsafe.rs index c717d1a72e0..99b995b0906 100644 --- a/src/test/compile-fail/kindck-send-unsafe.rs +++ b/src/test/compile-fail/kindck-send-unsafe.rs @@ -14,7 +14,7 @@ fn assert_send() { } fn test71<'a>() { assert_send::<*mut &'a isize>(); - //~^ ERROR `*mut &'a isize: std::marker::Send` is not satisfied + //~^ ERROR `*mut &'a isize` cannot be sent between threads safely } fn main() { diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index 334952cefa6..6825963c486 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -33,7 +33,7 @@ fn main() { let x = foo(Port(Rc::new(()))); thread::spawn(move|| { - //~^ ERROR `std::rc::Rc<()>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely let y = x; println!("{:?}", y); }); diff --git a/src/test/compile-fail/no_send-enum.rs b/src/test/compile-fail/no_send-enum.rs index 902710e96e2..83f19ed19ef 100644 --- a/src/test/compile-fail/no_send-enum.rs +++ b/src/test/compile-fail/no_send-enum.rs @@ -24,5 +24,5 @@ fn bar(_: T) {} fn main() { let x = Foo::A(NoSend); bar(x); - //~^ ERROR `NoSend: std::marker::Send` is not satisfied + //~^ ERROR `NoSend` cannot be sent between threads safely } diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index f31d3787334..d3616d14422 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -15,5 +15,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5); bar(x); - //~^ ERROR `std::rc::Rc<{integer}>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<{integer}>` cannot be sent between threads safely } diff --git a/src/test/compile-fail/no_send-struct.rs b/src/test/compile-fail/no_send-struct.rs index b2ca4f9f5db..d38d993e7e8 100644 --- a/src/test/compile-fail/no_send-struct.rs +++ b/src/test/compile-fail/no_send-struct.rs @@ -23,5 +23,5 @@ fn bar(_: T) {} fn main() { let x = Foo { a: 5 }; bar(x); - //~^ ERROR `Foo: std::marker::Send` is not satisfied + //~^ ERROR `Foo` cannot be sent between threads safely } diff --git a/src/test/compile-fail/not-panic-safe-2.rs b/src/test/compile-fail/not-panic-safe-2.rs index 7107211fc91..d750851b719 100644 --- a/src/test/compile-fail/not-panic-safe-2.rs +++ b/src/test/compile-fail/not-panic-safe-2.rs @@ -18,6 +18,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-3.rs b/src/test/compile-fail/not-panic-safe-3.rs index 76c34e4dc0b..cd27b274258 100644 --- a/src/test/compile-fail/not-panic-safe-3.rs +++ b/src/test/compile-fail/not-panic-safe-3.rs @@ -18,6 +18,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-4.rs b/src/test/compile-fail/not-panic-safe-4.rs index 177a43e2a7f..956eca432c5 100644 --- a/src/test/compile-fail/not-panic-safe-4.rs +++ b/src/test/compile-fail/not-panic-safe-4.rs @@ -17,6 +17,6 @@ fn assert() {} fn main() { assert::<&RefCell>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe-6.rs b/src/test/compile-fail/not-panic-safe-6.rs index f03e1d545a8..d0ca1db5212 100644 --- a/src/test/compile-fail/not-panic-safe-6.rs +++ b/src/test/compile-fail/not-panic-safe-6.rs @@ -17,6 +17,6 @@ fn assert() {} fn main() { assert::<*mut RefCell>(); - //~^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied - //~^^ ERROR `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/compile-fail/not-panic-safe.rs b/src/test/compile-fail/not-panic-safe.rs index ece8fa7dc47..0ebf3d3fed7 100644 --- a/src/test/compile-fail/not-panic-safe.rs +++ b/src/test/compile-fail/not-panic-safe.rs @@ -16,5 +16,6 @@ use std::panic::UnwindSafe; fn assert() {} fn main() { - assert::<&mut i32>(); //~ ERROR: UnwindSafe` is not satisfied + assert::<&mut i32>(); + //~^ ERROR the type `&mut i32` may not be safely transferred across an unwind boundary } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 58794e3b35d..3fb62b8d869 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -22,5 +22,5 @@ pub fn main() { // Unsized type. let arr: &[_] = &[1, 2, 3]; let range = *arr..; - //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs index 32f9b83b6e2..78d3702b449 100644 --- a/src/test/compile-fail/range_traits-1.rs +++ b/src/test/compile-fail/range_traits-1.rs @@ -13,23 +13,23 @@ use std::ops::*; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] struct AllTheRanges { a: Range, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord b: RangeTo, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord c: RangeFrom, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord d: RangeFull, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord e: RangeInclusive, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord f: RangeToInclusive, - //~^ ERROR PartialOrd - //~^^ ERROR Ord + //~^ ERROR can't compare + //~| ERROR Ord } fn main() {} diff --git a/src/test/compile-fail/str-idx.rs b/src/test/compile-fail/str-idx.rs index 2b2c23a3ce4..b5f1ffb977e 100644 --- a/src/test/compile-fail/str-idx.rs +++ b/src/test/compile-fail/str-idx.rs @@ -10,5 +10,5 @@ pub fn main() { let s: &str = "hello"; - let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<{integer}>` is not satisfied + let c: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}` } diff --git a/src/test/compile-fail/str-mut-idx.rs b/src/test/compile-fail/str-mut-idx.rs index 219fcdfd702..c25d257d5f8 100644 --- a/src/test/compile-fail/str-mut-idx.rs +++ b/src/test/compile-fail/str-mut-idx.rs @@ -12,10 +12,10 @@ fn bot() -> T { loop {} } fn mutate(s: &mut str) { s[1..2] = bot(); - //~^ ERROR `str: std::marker::Sized` is not satisfied - //~| ERROR `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time + //~| ERROR `str` does not have a constant size known at compile-time s[1usize] = bot(); - //~^ ERROR `str: std::ops::IndexMut` is not satisfied + //~^ ERROR the type `str` cannot be mutably indexed by `usize` } pub fn main() {} diff --git a/src/test/compile-fail/substs-ppaux.rs b/src/test/compile-fail/substs-ppaux.rs index c857790e342..94d2a549a86 100644 --- a/src/test/compile-fail/substs-ppaux.rs +++ b/src/test/compile-fail/substs-ppaux.rs @@ -56,6 +56,6 @@ fn foo<'z>() where &'z (): Sized { //[normal]~| found type `fn() {foo::<'static>}` >::bar; - //[verbose]~^ ERROR `str: std::marker::Sized` is not satisfied - //[normal]~^^ ERROR `str: std::marker::Sized` is not satisfied + //[verbose]~^ ERROR `str` does not have a constant size known at compile-time + //[normal]~^^ ERROR `str` does not have a constant size known at compile-time } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index 983c66ec1c4..effee4a70f3 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -15,7 +15,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ ERROR the trait bound `Foo + std::marker::Send + 'static: std::marker::Sized` is not + //~^ ERROR `Foo + std::marker::Send + 'static` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/traits-negative-impls.rs b/src/test/compile-fail/traits-negative-impls.rs index 8014f92e173..a272686c535 100644 --- a/src/test/compile-fail/traits-negative-impls.rs +++ b/src/test/compile-fail/traits-negative-impls.rs @@ -31,8 +31,8 @@ fn dummy() { impl !Send for TestType {} Outer(TestType); - //~^ ERROR `dummy::TestType: std::marker::Send` is not satisfied - //~| ERROR `dummy::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy::TestType` cannot be sent between threads safely + //~| ERROR `dummy::TestType` cannot be sent between threads safely } fn dummy1b() { @@ -40,7 +40,7 @@ fn dummy1b() { impl !Send for TestType {} is_send(TestType); - //~^ ERROR `dummy1b::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy1b::TestType` cannot be sent between threads safely } fn dummy1c() { @@ -48,7 +48,7 @@ fn dummy1c() { impl !Send for TestType {} is_send((8, TestType)); - //~^ ERROR `dummy1c::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy1c::TestType` cannot be sent between threads safely } fn dummy2() { @@ -56,7 +56,7 @@ fn dummy2() { impl !Send for TestType {} is_send(Box::new(TestType)); - //~^ ERROR `dummy2::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy2::TestType` cannot be sent between threads safely } fn dummy3() { @@ -64,7 +64,7 @@ fn dummy3() { impl !Send for TestType {} is_send(Box::new(Outer2(TestType))); - //~^ ERROR `dummy3::TestType: std::marker::Send` is not satisfied + //~^ ERROR `dummy3::TestType` cannot be sent between threads safely } fn main() { @@ -74,5 +74,5 @@ fn main() { // This will complain about a missing Send impl because `Sync` is implement *just* // for T that are `Send`. Look at #20366 and #19950 is_sync(Outer2(TestType)); - //~^ ERROR `main::TestType: std::marker::Send` is not satisfied + //~^ ERROR `main::TestType` cannot be sent between threads safely } diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs b/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs index 853718f1e77..65438e5df8e 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-negation-send.rs @@ -27,5 +27,5 @@ fn is_send() {} fn main() { is_send::(); is_send::(); - //~^ ERROR `MyNotSendable: std::marker::Send` is not satisfied + //~^ ERROR `MyNotSendable` cannot be sent between threads safely } diff --git a/src/test/compile-fail/union/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs index a238eaf0525..32f22f052c1 100644 --- a/src/test/compile-fail/union/union-unsized.rs +++ b/src/test/compile-fail/union/union-unsized.rs @@ -11,13 +11,15 @@ #![feature(untagged_unions)] union U { - a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + a: str, + //~^ ERROR `str` does not have a constant size known at compile-time b: u8, } union W { a: u8, - b: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + b: str, + //~^ ERROR `str` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index 3dcc7d248d7..be1f1dea28c 100644 --- a/src/test/compile-fail/unsized-bare-typaram.rs +++ b/src/test/compile-fail/unsized-bare-typaram.rs @@ -9,5 +9,6 @@ // except according to those terms. fn bar() { } -fn foo() { bar::() } //~ ERROR `T: std::marker::Sized` is not satisfied +fn foo() { bar::() } +//~^ ERROR `T` does not have a constant size known at compile-time fn main() { } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index 5d791215f36..2041c69da54 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -15,7 +15,7 @@ fn not_sized() { } enum Foo { FooSome(U), FooNone } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR `T: std::marker::Sized` is not satisfied +//~^ ERROR `T` does not have a constant size known at compile-time // // Not OK: `T` is not sized. diff --git a/src/test/compile-fail/unsized-inherent-impl-self-type.rs b/src/test/compile-fail/unsized-inherent-impl-self-type.rs index 4d0774f2ce4..5e5280ff3ea 100644 --- a/src/test/compile-fail/unsized-inherent-impl-self-type.rs +++ b/src/test/compile-fail/unsized-inherent-impl-self-type.rs @@ -14,7 +14,8 @@ struct S5(Y); -impl S5 { //~ ERROR E0277 +impl S5 { + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index bbefb2fcecd..830ac5d6c20 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -15,14 +15,14 @@ fn not_sized() { } struct Foo { data: T } fn foo1() { not_sized::>() } // Hunky dory. fn foo2() { not_sized::>() } -//~^ ERROR `T: std::marker::Sized` is not satisfied +//~^ ERROR `T` does not have a constant size known at compile-time // // Not OK: `T` is not sized. struct Bar { data: T } fn bar1() { not_sized::>() } fn bar2() { is_sized::>() } -//~^ ERROR `T: std::marker::Sized` is not satisfied +//~^ ERROR `T` does not have a constant size known at compile-time // // Not OK: `Bar` is not sized, but it should be. diff --git a/src/test/compile-fail/unsized-trait-impl-self-type.rs b/src/test/compile-fail/unsized-trait-impl-self-type.rs index c919bdf924f..9bf4cf7a0bb 100644 --- a/src/test/compile-fail/unsized-trait-impl-self-type.rs +++ b/src/test/compile-fail/unsized-trait-impl-self-type.rs @@ -17,7 +17,8 @@ trait T3 { struct S5(Y); -impl T3 for S5 { //~ ERROR E0277 +impl T3 for S5 { + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs index ad5e4c2daef..b3a848954d1 100644 --- a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs +++ b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs @@ -16,7 +16,7 @@ trait T2 { } struct S4(Box); impl T2 for S4 { - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index e96e0ea3aec..e08cf8280fd 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -15,7 +15,7 @@ use std::marker; // Unbounded. fn f1(x: &X) { f2::(x); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn f2(x: &X) { } @@ -26,7 +26,7 @@ trait T { } fn f3(x: &X) { f4::(x); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn f4(x: &X) { } @@ -41,20 +41,20 @@ struct S { fn f8(x1: &S, x2: &S) { f5(x1); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time f6(x2); // ok } // Test some tuples. fn f9(x1: Box>) { f5(&(*x1, 34)); - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn f10(x1: Box>) { f5(&(32, *x1)); - //~^ ERROR `X: std::marker::Sized` is not satisfied - //~| ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time + //~| ERROR `X` does not have a constant size known at compile-time } pub fn main() { diff --git a/src/test/compile-fail/unsized5.rs b/src/test/compile-fail/unsized5.rs index 3e6c9cc4061..1fb32da5e31 100644 --- a/src/test/compile-fail/unsized5.rs +++ b/src/test/compile-fail/unsized5.rs @@ -11,27 +11,33 @@ // Test `?Sized` types not allowed in fields (except the last one). struct S1 { - f1: X, //~ ERROR `X: std::marker::Sized` is not satisfied + f1: X, + //~^ ERROR `X` does not have a constant size known at compile-time f2: isize, } struct S2 { f: isize, - g: X, //~ ERROR `X: std::marker::Sized` is not satisfied + g: X, + //~^ ERROR `X` does not have a constant size known at compile-time h: isize, } struct S3 { - f: str, //~ ERROR `str: std::marker::Sized` is not satisfied + f: str, + //~^ ERROR `str` does not have a constant size known at compile-time g: [usize] } struct S4 { - f: [u8], //~ ERROR `[u8]: std::marker::Sized` is not satisfied + f: [u8], + //~^ ERROR `[u8]` does not have a constant size known at compile-time g: usize } enum E { - V1(X, isize), //~ERROR `X: std::marker::Sized` is not satisfied + V1(X, isize), + //~^ ERROR `X` does not have a constant size known at compile-time } enum F { - V2{f1: X, f: isize}, //~ERROR `X: std::marker::Sized` is not satisfied + V2{f1: X, f: isize}, + //~^ ERROR `X` does not have a constant size known at compile-time } pub fn main() { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index dec8699f46e..7ce0e1eb4d8 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,28 +14,41 @@ trait T {} fn f1(x: &X) { let _: W; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie - let y: Y; //~ERROR `Y: std::marker::Sized` is not satisfied - let y: (isize, (Z, usize)); //~ERROR `Z: std::marker::Sized` is not satisfied + let _: (isize, (X, isize)); + //~^ ERROR `X` does not have a constant size known at compile-time + let y: Y; + //~^ ERROR `Y` does not have a constant size known at compile-time + let y: (isize, (Z, usize)); + //~^ ERROR `Z` does not have a constant size known at compile-time } fn f2(x: &X) { - let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (Y, isize)); //~ERROR `Y: std::marker::Sized` is not satisfied + let y: X; + //~^ ERROR `X` does not have a constant size known at compile-time + let y: (isize, (Y, isize)); + //~^ ERROR `Y` does not have a constant size known at compile-time } fn f3(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR `X: std::marker::Sized` is not satisfied - let y = *x2; //~ERROR `X: std::marker::Sized` is not satisfied - let (y, z) = (*x3, 4); //~ERROR `X: std::marker::Sized` is not satisfied + let y: X = *x1; + //~^ ERROR `X` does not have a constant size known at compile-time + let y = *x2; + //~^ ERROR `X` does not have a constant size known at compile-time + let (y, z) = (*x3, 4); + //~^ ERROR `X` does not have a constant size known at compile-time } fn f4(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR `X: std::marker::Sized` is not satisfied - let y = *x2; //~ERROR `X: std::marker::Sized` is not satisfied - let (y, z) = (*x3, 4); //~ERROR `X: std::marker::Sized` is not satisfied + let y: X = *x1; + //~^ ERROR `X` does not have a constant size known at compile-time + let y = *x2; + //~^ ERROR `X` does not have a constant size known at compile-time + let (y, z) = (*x3, 4); + //~^ ERROR `X` does not have a constant size known at compile-time } -fn g1(x: X) {} //~ERROR `X: std::marker::Sized` is not satisfied -fn g2(x: X) {} //~ERROR `X: std::marker::Sized` is not satisfied +fn g1(x: X) {} +//~^ ERROR `X` does not have a constant size known at compile-time +fn g2(x: X) {} +//~^ ERROR `X` does not have a constant size known at compile-time pub fn main() { } diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index 25868c594fe..8a3d78f0827 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -20,7 +20,7 @@ trait T1 { struct S3(Box); impl T1 for S3 { - //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^ ERROR `X` does not have a constant size known at compile-time } fn main() { } diff --git a/src/test/ui/const-unsized.rs b/src/test/ui/const-unsized.rs index c6ce34b60ca..61ee622e21b 100644 --- a/src/test/ui/const-unsized.rs +++ b/src/test/ui/const-unsized.rs @@ -11,16 +11,16 @@ use std::fmt::Debug; const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); -//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at const CONST_FOO: str = *"foo"; -//~^ ERROR `str: std::marker::Sized` is not satisfied +//~^ ERROR `str` does not have a constant size known at compile-time static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); -//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +//~^ ERROR `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at static STATIC_BAR: str = *"bar"; -//~^ ERROR `str: std::marker::Sized` is not satisfied +//~^ ERROR `str` does not have a constant size known at compile-time fn main() { println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); diff --git a/src/test/ui/const-unsized.stderr b/src/test/ui/const-unsized.stderr index 0bbb5debbba..ca434541cc2 100644 --- a/src/test/ui/const-unsized.stderr +++ b/src/test/ui/const-unsized.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +error[E0277]: `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:13:29 | LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); @@ -7,7 +7,7 @@ LL | const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` = note: constant expressions must have a statically known size -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:16:24 | LL | const CONST_FOO: str = *"foo"; @@ -16,7 +16,7 @@ LL | const CONST_FOO: str = *"foo"; = help: the trait `std::marker::Sized` is not implemented for `str` = note: constant expressions must have a statically known size -error[E0277]: the trait bound `std::fmt::Debug + std::marker::Sync + 'static: std::marker::Sized` is not satisfied +error[E0277]: `std::fmt::Debug + std::marker::Sync + 'static` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:19:31 | LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); @@ -25,7 +25,7 @@ LL | static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); = help: the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + std::marker::Sync + 'static` = note: constant expressions must have a statically known size -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/const-unsized.rs:22:26 | LL | static STATIC_BAR: str = *"bar"; diff --git a/src/test/ui/error-codes/E0277-2.rs b/src/test/ui/error-codes/E0277-2.rs index 4d1c50002a3..313aa1f706e 100644 --- a/src/test/ui/error-codes/E0277-2.rs +++ b/src/test/ui/error-codes/E0277-2.rs @@ -24,5 +24,5 @@ fn is_send() { } fn main() { is_send::(); - //~^ ERROR the trait bound `*const u8: std::marker::Send` is not satisfied in `Foo` + //~^ ERROR `*const u8` cannot be sent between threads safely } diff --git a/src/test/ui/error-codes/E0277-2.stderr b/src/test/ui/error-codes/E0277-2.stderr index bbe04cfc6e1..32776f028b4 100644 --- a/src/test/ui/error-codes/E0277-2.stderr +++ b/src/test/ui/error-codes/E0277-2.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `*const u8: std::marker::Send` is not satisfied in `Foo` +error[E0277]: `*const u8` cannot be sent between threads safely --> $DIR/E0277-2.rs:26:5 | LL | is_send::(); diff --git a/src/test/ui/error-codes/E0277.rs b/src/test/ui/error-codes/E0277.rs index b29e4357015..9ff2ef4da90 100644 --- a/src/test/ui/error-codes/E0277.rs +++ b/src/test/ui/error-codes/E0277.rs @@ -21,7 +21,7 @@ fn some_func(foo: T) { } fn f(p: Path) { } -//~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied in `std::path::Path` +//~^ ERROR `[u8]` does not have a constant size known at compile-time fn main() { some_func(5i32); diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index 477128d7d9f..9cfd42b9c19 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied in `std::path::Path` +error[E0277]: `[u8]` does not have a constant size known at compile-time --> $DIR/E0277.rs:23:6 | LL | fn f(p: Path) { } diff --git a/src/test/ui/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gate-trivial_bounds.stderr index 9c2c80600b8..3c6d87e059a 100644 --- a/src/test/ui/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gate-trivial_bounds.stderr @@ -87,7 +87,7 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/feature-gate-trivial_bounds.rs:62:1 | LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR @@ -97,7 +97,7 @@ LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the trait bound `A + 'static: std::marker::Sized` is not satisfied in `Dst` +error[E0277]: `A + 'static` does not have a constant size known at compile-time --> $DIR/feature-gate-trivial_bounds.rs:65:1 | LL | / fn unsized_local() where Dst: Sized { //~ ERROR @@ -110,7 +110,7 @@ LL | | } = help: see issue #48214 = help: add #![feature(trivial_bounds)] to the crate attributes to enable -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/feature-gate-trivial_bounds.rs:69:1 | LL | / fn return_str() -> str where str: Sized { //~ ERROR diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs index a1c8ca77e41..165e2702597 100644 --- a/src/test/ui/generator/sized-yield.rs +++ b/src/test/ui/generator/sized-yield.rs @@ -14,8 +14,10 @@ use std::ops::Generator; fn main() { let s = String::from("foo"); - let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + let mut gen = move || { + //~^ ERROR `str` does not have a constant size known at compile-time yield s[..]; }; - unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied + unsafe { gen.resume(); } + //~^ ERROR `str` does not have a constant size known at compile-time } diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 957fac172c2..45f06659053 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -1,8 +1,9 @@ -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/sized-yield.rs:17:26 | -LL | let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +LL | let mut gen = move || { | __________________________^ +LL | | //~^ ERROR `str` does not have a constant size known at compile-time LL | | yield s[..]; LL | | }; | |____^ `str` does not have a constant size known at compile-time @@ -10,10 +11,10 @@ LL | | }; = help: the trait `std::marker::Sized` is not implemented for `str` = note: the yield type of a generator must have a statically known size -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied - --> $DIR/sized-yield.rs:20:17 +error[E0277]: `str` does not have a constant size known at compile-time + --> $DIR/sized-yield.rs:21:17 | -LL | unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied +LL | unsafe { gen.resume(); } | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index abb3682a498..f6b64b394fc 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -25,7 +25,7 @@ fn cycle1() -> impl Clone { //~^ ERROR cycle detected //~| ERROR cycle detected send(cycle2().clone()); - //~^ ERROR Send` is not satisfied + //~^ ERROR `std::rc::Rc` cannot be sent between threads safely Rc::new(Cell::new(5)) } diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 4537c96c4ab..b34facd2d39 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -47,7 +47,7 @@ LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires processing `cycle1::{{exist-impl-Trait}}`, completing the cycle -error[E0277]: the trait bound `std::rc::Rc: std::marker::Send` is not satisfied in `impl std::clone::Clone` +error[E0277]: `std::rc::Rc` cannot be sent between threads safely --> $DIR/auto-trait-leak.rs:27:5 | LL | send(cycle2().clone()); diff --git a/src/test/ui/impl-trait/auto-trait-leak2.rs b/src/test/ui/impl-trait/auto-trait-leak2.rs index 16310e67f1b..3c61543a711 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.rs +++ b/src/test/ui/impl-trait/auto-trait-leak2.rs @@ -23,10 +23,10 @@ fn send(_: T) {} fn main() { send(before()); - //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely send(after()); - //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely } // Deferred path, main has to wait until typeck finishes, diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index 59623aed3d2..fb00c41f79c 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` +error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:25:5 | LL | send(before()); @@ -13,7 +13,7 @@ note: required by `send` LL | fn send(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied in `impl std::ops::Fn<(i32,)>` +error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:28:5 | LL | send(after()); diff --git a/src/test/ui/interior-mutability/interior-mutability.rs b/src/test/ui/interior-mutability/interior-mutability.rs index a772d1f90cc..b0288463e91 100644 --- a/src/test/ui/interior-mutability/interior-mutability.rs +++ b/src/test/ui/interior-mutability/interior-mutability.rs @@ -12,5 +12,6 @@ use std::cell::Cell; use std::panic::catch_unwind; fn main() { let mut x = Cell::new(22); - catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound + catch_unwind(|| { x.set(23); }); + //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index 4c489c5964b..f2aecc55ccb 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` +error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/interior-mutability.rs:15:5 | -LL | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +LL | catch_unwind(|| { x.set(23); }); + | ^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `std::cell::Cell` diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index 3f2cb59b11d..86785f24f36 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -13,6 +13,6 @@ fn main() { 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{integer}>` from `usize` 3 * (); //~ ERROR cannot multiply `()` to `{integer}` 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` - 5 < String::new(); //~ ERROR is not satisfied - 6 == Ok(1); //~ ERROR is not satisfied + 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::string::String` + 6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>` } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 9d23b256fd3..4c6d95efadb 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -30,19 +30,19 @@ LL | 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` | = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` -error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd` is not satisfied +error[E0277]: can't compare `{integer}` with `std::string::String` --> $DIR/binops.rs:16:7 | -LL | 5 < String::new(); //~ ERROR is not satisfied - | ^ can't compare `{integer}` with `std::string::String` +LL | 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::string::String` + | ^ no implementation for `{integer} < std::string::String` and `{integer} > std::string::String` | = help: the trait `std::cmp::PartialOrd` is not implemented for `{integer}` -error[E0277]: the trait bound `{integer}: std::cmp::PartialEq>` is not satisfied +error[E0277]: can't compare `{integer}` with `std::result::Result<{integer}, _>` --> $DIR/binops.rs:17:7 | -LL | 6 == Ok(1); //~ ERROR is not satisfied - | ^^ can't compare `{integer}` with `std::result::Result<{integer}, _>` +LL | 6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>` + | ^^ no implementation for `{integer} == std::result::Result<{integer}, _>` | = help: the trait `std::cmp::PartialEq>` is not implemented for `{integer}` diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs index 15388b3a764..7ec9593d2de 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.rs +++ b/src/test/ui/mismatched_types/cast-rfc0401.rs @@ -60,7 +60,7 @@ fn main() let _ = 42usize as *const [u8]; //~ ERROR is invalid let _ = v as *const [u8]; //~ ERROR cannot cast - let _ = fat_v as *const Foo; //~ ERROR is not satisfied + let _ = fat_v as *const Foo; //~ ERROR `[u8]` does not have a constant size known at compile-time let _ = foo as *const str; //~ ERROR is invalid let _ = foo as *mut str; //~ ERROR is invalid let _ = main as *mut str; //~ ERROR is invalid @@ -69,7 +69,7 @@ fn main() let _ = fat_sv as usize; //~ ERROR is invalid let a : *const str = "hello"; - let _ = a as *const Foo; //~ ERROR is not satisfied + let _ = a as *const Foo; //~ ERROR `str` does not have a constant size known at compile-time // check no error cascade let _ = main.f as *const u32; //~ ERROR no field diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 7931e7ff07f..2b00c20e201 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -216,19 +216,19 @@ LL | let _ = cf as *const Bar; //~ ERROR is invalid | = note: vtable kinds may not match -error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied +error[E0277]: `[u8]` does not have a constant size known at compile-time --> $DIR/cast-rfc0401.rs:63:13 | -LL | let _ = fat_v as *const Foo; //~ ERROR is not satisfied +LL | let _ = fat_v as *const Foo; //~ ERROR `[u8]` does not have a constant size known at compile-time | ^^^^^ `[u8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: required for the cast to the object type `Foo` -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/cast-rfc0401.rs:72:13 | -LL | let _ = a as *const Foo; //~ ERROR is not satisfied +LL | let _ = a as *const Foo; //~ ERROR `str` does not have a constant size known at compile-time | ^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index c813b64d40b..43f13d45684 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `&T: std::cmp::PartialEq` is not satisfied +error[E0277]: can't compare `&T` with `T` --> $DIR/partialeq_help.rs:12:7 | LL | a == b; //~ ERROR E0277 - | ^^ can't compare `&T` with `T` + | ^^ no implementation for `&T == T` | = help: the trait `std::cmp::PartialEq` is not implemented for `&T` = help: consider adding a `where &T: std::cmp::PartialEq` bound diff --git a/src/test/ui/resolve/issue-5035-2.rs b/src/test/ui/resolve/issue-5035-2.rs index 83ff95cc2ea..f6cdb05394a 100644 --- a/src/test/ui/resolve/issue-5035-2.rs +++ b/src/test/ui/resolve/issue-5035-2.rs @@ -11,6 +11,7 @@ trait I {} type K = I+'static; -fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied +fn foo(_x: K) {} +//~^ ERROR `I + 'static` does not have a constant size known at compile-time fn main() {} diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 92309274e84..554e97a1281 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -1,7 +1,7 @@ -error[E0277]: the trait bound `I + 'static: std::marker::Sized` is not satisfied +error[E0277]: `I + 'static` does not have a constant size known at compile-time --> $DIR/issue-5035-2.rs:14:8 | -LL | fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied +LL | fn foo(_x: K) {} | ^^ `I + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `I + 'static` diff --git a/src/test/ui/suggestions/str-array-assignment.rs b/src/test/ui/suggestions/str-array-assignment.rs index b70028bd926..f6b75981a66 100644 --- a/src/test/ui/suggestions/str-array-assignment.rs +++ b/src/test/ui/suggestions/str-array-assignment.rs @@ -15,7 +15,7 @@ fn main() { let u: &str = if true { s[..2] } else { s }; //~^ ERROR mismatched types let v = s[..2]; - //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied + //~^ ERROR `str` does not have a constant size known at compile-time let w: &str = s[..2]; //~^ ERROR mismatched types } diff --git a/src/test/ui/suggestions/str-array-assignment.stderr b/src/test/ui/suggestions/str-array-assignment.stderr index 76db882742a..91e86e344b4 100644 --- a/src/test/ui/suggestions/str-array-assignment.stderr +++ b/src/test/ui/suggestions/str-array-assignment.stderr @@ -19,7 +19,7 @@ LL | let u: &str = if true { s[..2] } else { s }; = note: expected type `&str` found type `str` -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/str-array-assignment.rs:17:7 | LL | let v = s[..2]; diff --git a/src/test/ui/trait-suggest-where-clause.rs b/src/test/ui/trait-suggest-where-clause.rs index 5dcb4c8a220..7962dbea371 100644 --- a/src/test/ui/trait-suggest-where-clause.rs +++ b/src/test/ui/trait-suggest-where-clause.rs @@ -15,10 +15,10 @@ struct Misc(T); fn check() { // suggest a where-clause, if needed mem::size_of::(); - //~^ ERROR `U: std::marker::Sized` is not satisfied + //~^ ERROR `U` does not have a constant size known at compile-time mem::size_of::>(); - //~^ ERROR `U: std::marker::Sized` is not satisfied + //~^ ERROR `U` does not have a constant size known at compile-time // ... even if T occurs as a type parameter @@ -36,10 +36,10 @@ fn check() { // ... and also not if the error is not related to the type mem::size_of::<[T]>(); - //~^ ERROR `[T]: std::marker::Sized` is not satisfied + //~^ ERROR `[T]` does not have a constant size known at compile-time mem::size_of::<[&U]>(); - //~^ ERROR `[&U]: std::marker::Sized` is not satisfied + //~^ ERROR `[&U]` does not have a constant size known at compile-time } fn main() { diff --git a/src/test/ui/trait-suggest-where-clause.stderr b/src/test/ui/trait-suggest-where-clause.stderr index abd9f5a8b73..d31e9288037 100644 --- a/src/test/ui/trait-suggest-where-clause.stderr +++ b/src/test/ui/trait-suggest-where-clause.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `U: std::marker::Sized` is not satisfied +error[E0277]: `U` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:17:5 | LL | mem::size_of::(); @@ -8,7 +8,7 @@ LL | mem::size_of::(); = help: consider adding a `where U: std::marker::Sized` bound = note: required by `std::mem::size_of` -error[E0277]: the trait bound `U: std::marker::Sized` is not satisfied in `Misc` +error[E0277]: `U` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:20:5 | LL | mem::size_of::>(); @@ -45,7 +45,7 @@ LL | as From>::from; | = note: required by `std::convert::From::from` -error[E0277]: the trait bound `[T]: std::marker::Sized` is not satisfied +error[E0277]: `[T]` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:38:5 | LL | mem::size_of::<[T]>(); @@ -54,7 +54,7 @@ LL | mem::size_of::<[T]>(); = help: the trait `std::marker::Sized` is not implemented for `[T]` = note: required by `std::mem::size_of` -error[E0277]: the trait bound `[&U]: std::marker::Sized` is not satisfied +error[E0277]: `[&U]` does not have a constant size known at compile-time --> $DIR/trait-suggest-where-clause.rs:41:5 | LL | mem::size_of::<[&U]>(); diff --git a/src/test/ui/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds-leak.stderr index df91ba0dd2a..d54414110b1 100644 --- a/src/test/ui/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds-leak.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied +error[E0277]: `str` does not have a constant size known at compile-time --> $DIR/trivial-bounds-leak.rs:22:25 | LL | fn cant_return_str() -> str { //~ ERROR diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index f916df5d32d..92a45db0689 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -14,24 +14,24 @@ use std::ops::Add; struct Foo>(T, U); struct WellFormed>(Z); -//~^ error: the trait bound `i32: std::iter::FromIterator` is not satisfied [E0277] +//~^ ERROR a collection of type `i32` cannot be built from an iterator over elements of type `i32` struct WellFormedNoBounds>(Z); -//~^ error: the trait bound `i32: std::iter::FromIterator` is not satisfied [E0277] +//~^ ERROR a collection of type `i32` cannot be built from an iterator over elements of type `i32` struct Bounds(T); -//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] struct WhereClause(T) where T: Copy; -//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] trait TraitBound {} -//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] trait Super { } trait Base: Super { } -//~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277] trait ProjectionPred> where T::Item : Add {} -//~^ error: cannot add `u8` to `i32` [E0277] +//~^ ERROR cannot add `u8` to `i32` [E0277] fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index a2d6e53df05..aa124110243 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied +error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:16:19 | LL | struct WellFormed>(Z); - | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` + | ^ a collection of type `i32` cannot be built from `std::iter::Iterator` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` note: required by `Foo` @@ -11,11 +11,11 @@ note: required by `Foo` LL | struct Foo>(T, U); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `i32: std::iter::FromIterator` is not satisfied +error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:18:27 | LL | struct WellFormedNoBounds>(Z); - | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32` + | ^ a collection of type `i32` cannot be built from `std::iter::Iterator` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` note: required by `Foo` diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs index 8999f1e0930..e40c6d11cb3 100644 --- a/src/test/ui/union/union-sized-field.rs +++ b/src/test/ui/union/union-sized-field.rs @@ -11,16 +11,19 @@ #![feature(untagged_unions)] union Foo { - value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied + value: T, + //~^ ERROR `T` does not have a constant size known at compile-time } struct Foo2 { - value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied + value: T, + //~^ ERROR `T` does not have a constant size known at compile-time t: u32, } enum Foo3 { - Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied + Value(T), + //~^ ERROR `T` does not have a constant size known at compile-time } fn main() {} diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index ba80af6c7e0..ce6de86cff9 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,27 +1,27 @@ -error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied +error[E0277]: `T` does not have a constant size known at compile-time --> $DIR/union-sized-field.rs:14:5 | -LL | value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied +LL | value: T, | ^^^^^^^^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = help: consider adding a `where T: std::marker::Sized` bound = note: no field of a union may have a dynamically sized type -error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied - --> $DIR/union-sized-field.rs:18:5 +error[E0277]: `T` does not have a constant size known at compile-time + --> $DIR/union-sized-field.rs:19:5 | -LL | value: T, //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied +LL | value: T, | ^^^^^^^^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = help: consider adding a `where T: std::marker::Sized` bound = note: only the last field of a struct may have a dynamically sized type -error[E0277]: the trait bound `T: std::marker::Sized` is not satisfied - --> $DIR/union-sized-field.rs:23:11 +error[E0277]: `T` does not have a constant size known at compile-time + --> $DIR/union-sized-field.rs:25:11 | -LL | Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied +LL | Value(T), | ^ `T` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` diff --git a/src/test/ui/unsized-enum2.rs b/src/test/ui/unsized-enum2.rs index 95fc3243fbe..4e42b92289b 100644 --- a/src/test/ui/unsized-enum2.rs +++ b/src/test/ui/unsized-enum2.rs @@ -30,37 +30,54 @@ struct Path4(PathHelper4); enum E { // parameter - VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied - VB{x: X}, //~ ERROR `X: std::marker::Sized` is not satisfied - VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied - VD{u: isize, x: Z}, //~ ERROR `Z: std::marker::Sized` is not satisfied + VA(W), + //~^ ERROR `W` does not have a constant size known at compile-time + VB{x: X}, + //~^ ERROR `X` does not have a constant size known at compile-time + VC(isize, Y), + //~^ ERROR `Y` does not have a constant size known at compile-time + VD{u: isize, x: Z}, + //~^ ERROR `Z` does not have a constant size known at compile-time // slice / str - VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied - VF{x: str}, //~ ERROR `str: std::marker::Sized` is not satisfied - VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied - VH{u: isize, x: [u32]}, //~ ERROR `[u32]: std::marker::Sized` is not satisfied + VE([u8]), + //~^ ERROR `[u8]` does not have a constant size known at compile-time + VF{x: str}, + //~^ ERROR `str` does not have a constant size known at compile-time + VG(isize, [f32]), + //~^ ERROR `[f32]` does not have a constant size known at compile-time + VH{u: isize, x: [u32]}, + //~^ ERROR `[u32]` does not have a constant size known at compile-time // unsized struct - VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied - VJ{x: Path2}, //~ ERROR `PathHelper2 + 'static: std::marker::Sized` is not satisfied - VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied - VL{u: isize, x: Path4}, //~ ERROR `PathHelper4 + 'static: std::marker::Sized` is not satisfied + VI(Path1), + //~^ ERROR `PathHelper1 + 'static` does not have a constant size known at compile-time + VJ{x: Path2}, + //~^ ERROR `PathHelper2 + 'static` does not have a constant size known at compile-time + VK(isize, Path3), + //~^ ERROR `PathHelper3 + 'static` does not have a constant size known at compile-time + VL{u: isize, x: Path4}, + //~^ ERROR `PathHelper4 + 'static` does not have a constant size known at compile-time // plain trait - VM(Foo), //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied - VN{x: Bar}, //~ ERROR `Bar + 'static: std::marker::Sized` is not satisfied - VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied - VP{u: isize, x: BarFoo}, //~ ERROR `BarFoo + 'static: std::marker::Sized` is not satisfied + VM(Foo), + //~^ ERROR `Foo + 'static` does not have a constant size known at compile-time + VN{x: Bar}, + //~^ ERROR `Bar + 'static` does not have a constant size known at compile-time + VO(isize, FooBar), + //~^ ERROR `FooBar + 'static` does not have a constant size known at compile-time + VP{u: isize, x: BarFoo}, + //~^ ERROR `BarFoo + 'static` does not have a constant size known at compile-time // projected - VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied + VQ(<&'static [i8] as Deref>::Target), + //~^ ERROR `[i8]` does not have a constant size known at compile-time VR{x: <&'static [char] as Deref>::Target}, - //~^ ERROR `[char]: std::marker::Sized` is not satisfied + //~^ ERROR `[char]` does not have a constant size known at compile-time VS(isize, <&'static [f64] as Deref>::Target), - //~^ ERROR `[f64]: std::marker::Sized` is not satisfied + //~^ ERROR `[f64]` does not have a constant size known at compile-time VT{u: isize, x: <&'static [i32] as Deref>::Target}, - //~^ ERROR `[i32]: std::marker::Sized` is not satisfied + //~^ ERROR `[i32]` does not have a constant size known at compile-time } diff --git a/src/test/ui/unsized-enum2.stderr b/src/test/ui/unsized-enum2.stderr index 0e18efbf9da..2784bf5af1b 100644 --- a/src/test/ui/unsized-enum2.stderr +++ b/src/test/ui/unsized-enum2.stderr @@ -1,126 +1,126 @@ -error[E0277]: the trait bound `W: std::marker::Sized` is not satisfied +error[E0277]: `W` does not have a constant size known at compile-time --> $DIR/unsized-enum2.rs:33:8 | -LL | VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied +LL | VA(W), | ^ `W` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `W` = help: consider adding a `where W: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `X: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:34:8 +error[E0277]: `X` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:35:8 | -LL | VB{x: X}, //~ ERROR `X: std::marker::Sized` is not satisfied +LL | VB{x: X}, | ^^^^ `X` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = help: consider adding a `where X: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Y: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:35:15 +error[E0277]: `Y` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:37:15 | -LL | VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied +LL | VC(isize, Y), | ^ `Y` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Y` = help: consider adding a `where Y: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Z: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:36:18 +error[E0277]: `Z` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:39:18 | -LL | VD{u: isize, x: Z}, //~ ERROR `Z: std::marker::Sized` is not satisfied +LL | VD{u: isize, x: Z}, | ^^^^ `Z` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Z` = help: consider adding a `where Z: std::marker::Sized` bound = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:39:8 +error[E0277]: `[u8]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:43:8 | -LL | VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied +LL | VE([u8]), | ^^^^ `[u8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:40:8 +error[E0277]: `str` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:45:8 | -LL | VF{x: str}, //~ ERROR `str: std::marker::Sized` is not satisfied +LL | VF{x: str}, | ^^^^^^ `str` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[f32]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:41:15 +error[E0277]: `[f32]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:47:15 | -LL | VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied +LL | VG(isize, [f32]), | ^^^^^ `[f32]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f32]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[u32]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:42:18 +error[E0277]: `[u32]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:49:18 | -LL | VH{u: isize, x: [u32]}, //~ ERROR `[u32]: std::marker::Sized` is not satisfied +LL | VH{u: isize, x: [u32]}, | ^^^^^^^^ `[u32]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u32]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Foo + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:51:8 +error[E0277]: `Foo + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:63:8 | -LL | VM(Foo), //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied +LL | VM(Foo), | ^^^ `Foo + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Foo + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `Bar + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:52:8 +error[E0277]: `Bar + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:65:8 | -LL | VN{x: Bar}, //~ ERROR `Bar + 'static: std::marker::Sized` is not satisfied +LL | VN{x: Bar}, | ^^^^^^ `Bar + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Bar + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `FooBar + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:53:15 +error[E0277]: `FooBar + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:67:15 | -LL | VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied +LL | VO(isize, FooBar), | ^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `FooBar + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `BarFoo + 'static: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:54:18 +error[E0277]: `BarFoo + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:69:18 | -LL | VP{u: isize, x: BarFoo}, //~ ERROR `BarFoo + 'static: std::marker::Sized` is not satisfied +LL | VP{u: isize, x: BarFoo}, | ^^^^^^^^^ `BarFoo + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `BarFoo + 'static` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[i8]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:57:8 +error[E0277]: `[i8]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:73:8 | -LL | VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied +LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[char]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:58:8 +error[E0277]: `[char]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:75:8 | LL | VR{x: <&'static [char] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[char]` does not have a constant size known at compile-time @@ -128,8 +128,8 @@ LL | VR{x: <&'static [char] as Deref>::Target}, = help: the trait `std::marker::Sized` is not implemented for `[char]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[f64]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:60:15 +error[E0277]: `[f64]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:77:15 | LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time @@ -137,8 +137,8 @@ LL | VS(isize, <&'static [f64] as Deref>::Target), = help: the trait `std::marker::Sized` is not implemented for `[f64]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `[i32]: std::marker::Sized` is not satisfied - --> $DIR/unsized-enum2.rs:62:18 +error[E0277]: `[i32]` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:79:18 | LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i32]` does not have a constant size known at compile-time @@ -146,40 +146,40 @@ LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, = help: the trait `std::marker::Sized` is not implemented for `[i32]` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper1 + 'static: std::marker::Sized` is not satisfied in `Path1` - --> $DIR/unsized-enum2.rs:45:8 +error[E0277]: `PathHelper1 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:53:8 | -LL | VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied +LL | VI(Path1), | ^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time | = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `PathHelper1 + 'static` = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper2 + 'static: std::marker::Sized` is not satisfied in `Path2` - --> $DIR/unsized-enum2.rs:46:8 +error[E0277]: `PathHelper2 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:55:8 | -LL | VJ{x: Path2}, //~ ERROR `PathHelper2 + 'static: std::marker::Sized` is not satisfied +LL | VJ{x: Path2}, | ^^^^^^^^ `PathHelper2 + 'static` does not have a constant size known at compile-time | = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `PathHelper2 + 'static` = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper3 + 'static: std::marker::Sized` is not satisfied in `Path3` - --> $DIR/unsized-enum2.rs:47:15 +error[E0277]: `PathHelper3 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:57:15 | -LL | VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied +LL | VK(isize, Path3), | ^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time | = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `PathHelper3 + 'static` = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type -error[E0277]: the trait bound `PathHelper4 + 'static: std::marker::Sized` is not satisfied in `Path4` - --> $DIR/unsized-enum2.rs:48:18 +error[E0277]: `PathHelper4 + 'static` does not have a constant size known at compile-time + --> $DIR/unsized-enum2.rs:59:18 | -LL | VL{u: isize, x: Path4}, //~ ERROR `PathHelper4 + 'static: std::marker::Sized` is not satisfied +LL | VL{u: isize, x: Path4}, | ^^^^^^^^ `PathHelper4 + 'static` does not have a constant size known at compile-time | = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `PathHelper4 + 'static` -- cgit 1.4.1-3-g733a5 From 0b9c686b479ce337581ba9773481ada8dd8f91d6 Mon Sep 17 00:00:00 2001 From: Sgeo Date: Tue, 19 Jun 2018 18:32:44 -0400 Subject: Remove erroneous example of main as a non-Result function. --- src/libstd/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index eba4e9fe703..2b4644bd013 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -147,7 +147,7 @@ //! ``` //! //! Note that you cannot use the [`?` operator] in functions that do not return -//! a [`Result`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`] +//! a [`Result`][`Result`]. Instead, you can call [`.unwrap()`] //! or `match` on the return value to catch any possible errors: //! //! ```no_run -- cgit 1.4.1-3-g733a5 From cf844b547dbec1f23982fca8e07ec65800ed5d6d Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 6 Jun 2018 15:50:59 -0700 Subject: async await desugaring and tests --- src/librustc/diagnostics.rs | 7 +- src/librustc/hir/lowering.rs | 671 ++++++++++++++++----- src/librustc/hir/map/def_collector.rs | 40 +- src/librustc/hir/mod.rs | 10 + src/librustc/ich/impls_syntax.rs | 1 + src/librustc_metadata/encoder.rs | 5 +- src/librustc_resolve/lib.rs | 90 ++- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/sig.rs | 4 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustdoc/html/render.rs | 3 +- src/libstd/lib.rs | 4 +- src/libstd/macros.rs | 20 + src/libstd/raw.rs | 110 ++++ src/libsyntax/ast.rs | 24 +- src/libsyntax/ext/build.rs | 2 + src/libsyntax/feature_gate.rs | 12 +- src/libsyntax/fold.rs | 25 +- src/libsyntax/parse/parser.rs | 58 +- src/libsyntax/print/pprust.rs | 24 +- src/libsyntax/ptr.rs | 10 + src/libsyntax/test.rs | 12 +- src/libsyntax/util/parser.rs | 2 + src/libsyntax/visit.rs | 7 +- src/libsyntax_pos/hygiene.rs | 2 + src/test/run-pass/async-await.rs | 133 ++++ src/test/ui/async-fn-multiple-lifetimes.rs | 30 + src/test/ui/async-fn-multiple-lifetimes.stderr | 32 + src/test/ui/edition-keywords-2018-2015-parsing.rs | 2 +- .../ui/edition-keywords-2018-2015-parsing.stderr | 8 +- src/test/ui/edition-keywords-2018-2018-parsing.rs | 2 +- .../ui/edition-keywords-2018-2018-parsing.stderr | 8 +- .../ui/feature-gate-async-await-2015-edition.rs | 20 + .../feature-gate-async-await-2015-edition.stderr | 24 + src/test/ui/feature-gate-async-await.rs | 19 + src/test/ui/feature-gate-async-await.stderr | 27 + src/test/ui/no-args-non-move-async-closure.rs | 18 + src/test/ui/no-args-non-move-async-closure.stderr | 11 + 38 files changed, 1282 insertions(+), 199 deletions(-) create mode 100644 src/libstd/raw.rs create mode 100644 src/test/run-pass/async-await.rs create mode 100644 src/test/ui/async-fn-multiple-lifetimes.rs create mode 100644 src/test/ui/async-fn-multiple-lifetimes.stderr create mode 100644 src/test/ui/feature-gate-async-await-2015-edition.rs create mode 100644 src/test/ui/feature-gate-async-await-2015-edition.stderr create mode 100644 src/test/ui/feature-gate-async-await.rs create mode 100644 src/test/ui/feature-gate-async-await.stderr create mode 100644 src/test/ui/no-args-non-move-async-closure.rs create mode 100644 src/test/ui/no-args-non-move-async-closure.stderr (limited to 'src/libstd') diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 1435957a5c1..6e6b15bdff7 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2131,5 +2131,10 @@ register_diagnostics! { E0657, // `impl Trait` can only capture lifetimes bound at the fn level E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders - E0697, // closures cannot be static + + E0906, // closures cannot be static + + E0703, // multiple different lifetimes used in arguments of `async fn` + E0704, // multiple elided lifetimes used in arguments of `async fn` + E0705, // `async` non-`move` closures with arguments are not currently supported } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 16405b602be..d0e6a5e2973 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -449,7 +449,7 @@ impl<'a> LoweringContext<'a> { } } - fn allocate_hir_id_counter(&mut self, owner: NodeId, debug: &T) { + fn allocate_hir_id_counter(&mut self, owner: NodeId, debug: &T) -> LoweredNodeId { if self.item_local_id_counters.insert(owner, 0).is_some() { bug!( "Tried to allocate item_local_id_counter for {:?} twice", @@ -457,7 +457,7 @@ impl<'a> LoweringContext<'a> { ); } // Always allocate the first HirId for the owner itself - self.lower_node_id_with_owner(owner, owner); + self.lower_node_id_with_owner(owner, owner) } fn lower_node_id_generic(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> LoweredNodeId @@ -501,7 +501,7 @@ impl<'a> LoweringContext<'a> { { let counter = self.item_local_id_counters .insert(owner, HIR_ID_COUNTER_LOCKED) - .unwrap(); + .unwrap_or_else(|| panic!("No item_local_id_counters entry for {:?}", owner)); let def_index = self.resolver.definitions().opt_def_index(owner).unwrap(); self.current_hir_id_owner.push((def_index, counter)); let ret = f(self); @@ -840,6 +840,46 @@ impl<'a> LoweringContext<'a> { result } + fn make_async_expr( + &mut self, + capture_clause: CaptureBy, + closure_node_id: NodeId, + ret_ty: Option<&Ty>, + body: impl FnOnce(&mut LoweringContext) -> hir::Expr, + ) -> hir::Expr_ { + let prev_is_generator = mem::replace(&mut self.is_generator, true); + let body_expr = body(self); + let span = body_expr.span; + let output = match ret_ty { + Some(ty) => FunctionRetTy::Ty(P(ty.clone())), + None => FunctionRetTy::Default(span), + }; + let decl = FnDecl { + inputs: vec![], + output, + variadic: false + }; + let body_id = self.record_body(body_expr, Some(&decl)); + self.is_generator = prev_is_generator; + + let capture_clause = self.lower_capture_clause(capture_clause); + let closure_hir_id = self.lower_node_id(closure_node_id).hir_id; + let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, false); + let generator = hir::Expr { + id: closure_node_id, + hir_id: closure_hir_id, + node: hir::ExprClosure(capture_clause, decl, body_id, span, + Some(hir::GeneratorMovability::Static)), + span, + attrs: ThinVec::new(), + }; + + let unstable_span = self.allow_internal_unstable(CompilerDesugaringKind::Async, span); + let gen_future = self.expr_std_path( + unstable_span, &["raw", "future_from_generator"], ThinVec::new()); + hir::ExprCall(P(gen_future), hir_vec![generator]) + } + fn lower_body(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId where F: FnOnce(&mut LoweringContext) -> hir::Expr, @@ -1067,7 +1107,7 @@ impl<'a> LoweringContext<'a> { ), unsafety: this.lower_unsafety(f.unsafety), abi: f.abi, - decl: this.lower_fn_decl(&f.decl, None, false), + decl: this.lower_fn_decl(&f.decl, None, false, false), arg_names: this.lower_fn_args_to_names(&f.decl), })) }, @@ -1132,92 +1172,10 @@ impl<'a> LoweringContext<'a> { let span = t.span; match itctx { ImplTraitContext::Existential(fn_def_id) => { - - // We need to manually repeat the code of `next_id` because the lowering - // needs to happen while the owner_id is pointing to the item itself, - // because items are their own owners - let exist_ty_node_id = self.sess.next_node_id(); - - // Make sure we know that some funky desugaring has been going on here. - // This is a first: there is code in other places like for loop - // desugaring that explicitly states that we don't want to track that. - // Not tracking it makes lints in rustc and clippy very fragile as - // frequently opened issues show. - let exist_ty_span = self.allow_internal_unstable( - CompilerDesugaringKind::ExistentialReturnType, - t.span, - ); - - // Pull a new definition from the ether - let exist_ty_def_index = self - .resolver - .definitions() - .create_def_with_parent( - fn_def_id.index, - exist_ty_node_id, - DefPathData::ExistentialImplTrait, - DefIndexAddressSpace::High, - Mark::root(), - exist_ty_span, - ); - - // the `t` is just for printing debug messages - self.allocate_hir_id_counter(exist_ty_node_id, t); - - let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| { - lctx.lower_param_bounds(bounds, itctx) - }); - - let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds( - exist_ty_node_id, - exist_ty_def_index, - &hir_bounds, - ); - - self.with_hir_id_owner(exist_ty_node_id, |lctx| { - let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy { - generics: hir::Generics { - params: lifetime_defs, - where_clause: hir::WhereClause { - id: lctx.next_id().node_id, - predicates: Vec::new().into(), - }, - span, - }, - bounds: hir_bounds, - impl_trait_fn: Some(fn_def_id), - }); - let exist_ty_id = lctx.lower_node_id(exist_ty_node_id); - // Generate an `existential type Foo: Trait;` declaration - trace!("creating existential type with id {:#?}", exist_ty_id); - // Set the name to `impl Bound1 + Bound2` - let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t)); - - trace!("exist ty def index: {:#?}", exist_ty_def_index); - let exist_ty_item = hir::Item { - id: exist_ty_id.node_id, - hir_id: exist_ty_id.hir_id, - name: exist_ty_name, - attrs: Default::default(), - node: exist_ty_item_kind, - vis: hir::Visibility::Inherited, - span: exist_ty_span, - }; - - // Insert the item into the global list. This usually happens - // automatically for all AST items. But this existential type item - // does not actually exist in the AST. - lctx.items.insert(exist_ty_id.node_id, exist_ty_item); - - // `impl Trait` now just becomes `Foo<'a, 'b, ..>` - hir::TyImplTraitExistential( - hir::ItemId { - id: exist_ty_id.node_id - }, - DefId::local(exist_ty_def_index), - lifetimes, - ) - }) + // Set the name to `impl Bound1 + Bound2` + let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t)); + self.lower_existential_impl_trait( + span, fn_def_id, exist_ty_name, |this| this.lower_bounds(bounds, itctx)) } ImplTraitContext::Universal(def_id) => { let def_node_id = self.next_id().node_id; @@ -1281,6 +1239,95 @@ impl<'a> LoweringContext<'a> { }) } + fn lower_existential_impl_trait( + &mut self, + span: Span, + fn_def_id: DefId, + exist_ty_name: Name, + lower_bounds: impl FnOnce(&mut LoweringContext) -> hir::TyParamBounds, + ) -> hir::Ty_ { + // We need to manually repeat the code of `next_id` because the lowering + // needs to happen while the owner_id is pointing to the item itself, + // because items are their own owners + let exist_ty_node_id = self.sess.next_node_id(); + + // Make sure we know that some funky desugaring has been going on here. + // This is a first: there is code in other places like for loop + // desugaring that explicitly states that we don't want to track that. + // Not tracking it makes lints in rustc and clippy very fragile as + // frequently opened issues show. + let exist_ty_span = self.allow_internal_unstable( + CompilerDesugaringKind::ExistentialReturnType, + span, + ); + + // Pull a new definition from the ether + let exist_ty_def_index = self + .resolver + .definitions() + .create_def_with_parent( + fn_def_id.index, + exist_ty_node_id, + DefPathData::ExistentialImplTrait, + DefIndexAddressSpace::High, + Mark::root(), + exist_ty_span, + ); + + self.allocate_hir_id_counter(exist_ty_node_id, &"existential impl trait"); + + let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, lower_bounds); + + let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds( + exist_ty_node_id, + exist_ty_def_index, + &hir_bounds, + ); + + self.with_hir_id_owner(exist_ty_node_id, |lctx| { + let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy { + generics: hir::Generics { + params: lifetime_defs, + where_clause: hir::WhereClause { + id: lctx.next_id().node_id, + predicates: Vec::new().into(), + }, + span, + }, + bounds: hir_bounds, + impl_trait_fn: Some(fn_def_id), + }); + let exist_ty_id = lctx.lower_node_id(exist_ty_node_id); + // Generate an `existential type Foo: Trait;` declaration + trace!("creating existential type with id {:#?}", exist_ty_id); + + trace!("exist ty def index: {:#?}", exist_ty_def_index); + let exist_ty_item = hir::Item { + id: exist_ty_id.node_id, + hir_id: exist_ty_id.hir_id, + name: exist_ty_name, + attrs: Default::default(), + node: exist_ty_item_kind, + vis: hir::Visibility::Inherited, + span: exist_ty_span, + }; + + // Insert the item into the global list. This usually happens + // automatically for all AST items. But this existential type item + // does not actually exist in the AST. + lctx.items.insert(exist_ty_id.node_id, exist_ty_item); + + // `impl Trait` now just becomes `Foo<'a, 'b, ..>` + hir::TyImplTraitExistential( + hir::ItemId { + id: exist_ty_id.node_id + }, + DefId::local(exist_ty_def_index), + lifetimes, + ) + }) + } + fn lifetimes_from_impl_trait_bounds( &mut self, exist_ty_id: NodeId, @@ -1829,31 +1876,40 @@ impl<'a> LoweringContext<'a> { .collect() } + // Lowers a function declaration. + // + // decl: the unlowered (ast) function declaration. + // fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the + // given DefId, otherwise impl Trait is disallowed. Must be `Some` if + // make_ret_async is true. + // impl_trait_return_allow: determines whether impl Trait can be used in return position. + // This guards against trait declarations and implementations where impl Trait is + // disallowed. + // make_ret_async: if enabled, converts `-> T` into `-> impl Future` in the + // return type. This is used for `async fn` declarations. fn lower_fn_decl( &mut self, decl: &FnDecl, fn_def_id: Option, impl_trait_return_allow: bool, + make_ret_async: bool, ) -> P { - // NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some, - // then impl Trait arguments are lowered into generic parameters on the given - // fn_def_id, otherwise impl Trait is disallowed. (for now) - // - // Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in - // return positions as well. This guards against trait declarations and their impls - // where impl Trait is disallowed. (again for now) - P(hir::FnDecl { - inputs: decl.inputs - .iter() - .map(|arg| { - if let Some(def_id) = fn_def_id { - self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id)) - } else { - self.lower_ty(&arg.ty, ImplTraitContext::Disallowed) - } - }) - .collect(), - output: match decl.output { + let inputs = decl.inputs + .iter() + .map(|arg| { + if let Some(def_id) = fn_def_id { + self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id)) + } else { + self.lower_ty(&arg.ty, ImplTraitContext::Disallowed) + } + }) + .collect::>(); + + let output = if make_ret_async { + self.lower_async_fn_ret_ty( + &inputs, &decl.output, fn_def_id.expect("make_ret_async but no fn_def_id")) + } else { + match decl.output { FunctionRetTy::Ty(ref ty) => match fn_def_id { Some(def_id) if impl_trait_return_allow => { hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id))) @@ -1861,7 +1917,12 @@ impl<'a> LoweringContext<'a> { _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)), }, FunctionRetTy::Default(span) => hir::DefaultReturn(span), - }, + } + }; + + P(hir::FnDecl { + inputs, + output, variadic: decl.variadic, has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node { TyKind::ImplicitSelf => true, @@ -1871,6 +1932,243 @@ impl<'a> LoweringContext<'a> { }) } + // Transform `-> T` into `-> impl Future` for `async fn` + // + // fn_span: the span of the async function declaration. Used for error reporting. + // inputs: lowered types of arguments to the function. Used to collect lifetimes. + // output: unlowered output type (`T` in `-> T`) + // fn_def_id: DefId of the parent function. Used to create child impl trait definition. + fn lower_async_fn_ret_ty( + &mut self, + inputs: &[P], + output: &FunctionRetTy, + fn_def_id: DefId, + ) -> hir::FunctionRetTy { + // Get lifetimes used in the input arguments to the function. Our output type must also + // have the same lifetime. FIXME(cramertj) multiple different lifetimes are not allowed + // because `impl Trait + 'a + 'b` doesn't allow for capture `'a` and `'b` where neither + // is a subset of the other. We really want some new lifetime that is a subset of all input + // lifetimes, but that doesn't exist at the moment. + + struct AsyncFnLifetimeCollector<'r, 'a: 'r> { + context: &'r mut LoweringContext<'a>, + // Lifetimes bound by HRTB + currently_bound_lifetimes: Vec, + // Whether to count elided lifetimes. + // Disabled inside of `Fn` or `fn` syntax. + collect_elided_lifetimes: bool, + // The lifetime found. + // Multiple different or elided lifetimes cannot appear in async fn for now. + output_lifetime: Option<(hir::LifetimeName, Span)>, + } + + impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for AsyncFnLifetimeCollector<'r, 'a> { + fn nested_visit_map<'this>( + &'this mut self, + ) -> hir::intravisit::NestedVisitorMap<'this, 'v> { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_path_parameters(&mut self, span: Span, parameters: &'v hir::PathParameters) { + // Don't collect elided lifetimes used inside of `Fn()` syntax. + if parameters.parenthesized { + let old_collect_elided_lifetimes = self.collect_elided_lifetimes; + self.collect_elided_lifetimes = false; + hir::intravisit::walk_path_parameters(self, span, parameters); + self.collect_elided_lifetimes = old_collect_elided_lifetimes; + } else { + hir::intravisit::walk_path_parameters(self, span, parameters); + } + } + + fn visit_ty(&mut self, t: &'v hir::Ty) { + // Don't collect elided lifetimes used inside of `fn()` syntax + if let &hir::Ty_::TyBareFn(_) = &t.node { + let old_collect_elided_lifetimes = self.collect_elided_lifetimes; + self.collect_elided_lifetimes = false; + + // Record the "stack height" of `for<'a>` lifetime bindings + // to be able to later fully undo their introduction. + let old_len = self.currently_bound_lifetimes.len(); + hir::intravisit::walk_ty(self, t); + self.currently_bound_lifetimes.truncate(old_len); + + self.collect_elided_lifetimes = old_collect_elided_lifetimes; + } else { + hir::intravisit::walk_ty(self, t); + } + } + + fn visit_poly_trait_ref( + &mut self, + trait_ref: &'v hir::PolyTraitRef, + modifier: hir::TraitBoundModifier, + ) { + // Record the "stack height" of `for<'a>` lifetime bindings + // to be able to later fully undo their introduction. + let old_len = self.currently_bound_lifetimes.len(); + hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + self.currently_bound_lifetimes.truncate(old_len); + } + + fn visit_generic_param(&mut self, param: &'v hir::GenericParam) { + // Record the introduction of 'a in `for<'a> ...` + if let hir::GenericParam::Lifetime(ref lt_def) = *param { + // Introduce lifetimes one at a time so that we can handle + // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>` + self.currently_bound_lifetimes.push(lt_def.lifetime.name); + } + + hir::intravisit::walk_generic_param(self, param); + } + + fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { + let name = match lifetime.name { + hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { + if self.collect_elided_lifetimes { + // Use `'_` for both implicit and underscore lifetimes in + // `abstract type Foo<'_>: SomeTrait<'_>;` + hir::LifetimeName::Underscore + } else { + return; + } + } + name @ hir::LifetimeName::Fresh(_) => name, + name @ hir::LifetimeName::Name(_) => name, + hir::LifetimeName::Static => return, + }; + + if !self.currently_bound_lifetimes.contains(&name) { + if let Some((current_lt_name, current_lt_span)) = self.output_lifetime { + // We don't currently have a reliable way to desugar `async fn` with + // multiple potentially unrelated input lifetimes into + // `-> impl Trait + 'lt`, so we report an error in this case. + if current_lt_name != name { + struct_span_err!( + self.context.sess, + current_lt_span.between(lifetime.span), + E0703, + "multiple different lifetimes used in arguments of `async fn`", + ) + .span_label(current_lt_span, "first lifetime here") + .span_label(lifetime.span, "different lifetime here") + .help("`async fn` can only accept borrowed values \ + identical lifetimes") + .emit() + } else if current_lt_name.is_elided() && name.is_elided() { + struct_span_err!( + self.context.sess, + current_lt_span.between(lifetime.span), + E0704, + "multiple elided lifetimes used in arguments of `async fn`", + ) + .span_label(current_lt_span, "first lifetime here") + .span_label(lifetime.span, "different lifetime here") + .help("consider giving these arguments named lifetimes") + .emit() + } + } else { + self.output_lifetime = Some((name, lifetime.span)); + } + } + } + } + + let bound_lifetime = { + let mut lifetime_collector = AsyncFnLifetimeCollector { + context: self, + currently_bound_lifetimes: Vec::new(), + collect_elided_lifetimes: true, + output_lifetime: None, + }; + + for arg in inputs { + hir::intravisit::walk_ty(&mut lifetime_collector, arg); + } + lifetime_collector.output_lifetime + }; + + let output_ty_name_owned; + let (output_ty_name, span) = match output { + FunctionRetTy::Ty(ty) => { + output_ty_name_owned = pprust::ty_to_string(ty); + (&*output_ty_name_owned, ty.span) + }, + FunctionRetTy::Default(span) => ("()", *span), + }; + + // FIXME(cramertj) add lifetimes (see FIXME below) to the name + let exist_ty_name = Symbol::intern(&format!("impl Future", output_ty_name)); + let impl_trait_ty = self.lower_existential_impl_trait( + span, fn_def_id, exist_ty_name, |this| { + let output_ty = match output { + FunctionRetTy::Ty(ty) => + this.lower_ty(ty, ImplTraitContext::Existential(fn_def_id)), + FunctionRetTy::Default(span) => { + let LoweredNodeId { node_id, hir_id } = this.next_id(); + P(hir::Ty { + id: node_id, + hir_id: hir_id, + node: hir::TyTup(hir_vec![]), + span: *span, + }) + } + }; + + let hir::Path { def, segments, .. } = this.std_path(span, &["future", "Future"], false); + let future_path = hir::Path { + segments: segments.map_slice(|mut v| { + v.last_mut().unwrap().parameters = Some(P(hir::PathParameters { + lifetimes: hir_vec![], + types: hir_vec![], + bindings: hir_vec![hir::TypeBinding { + name: Symbol::intern(FN_OUTPUT_NAME), + ty: output_ty, + id: this.next_id().node_id, + span, + }], + parenthesized: false, + })); + v + }), + def, span + }; + + // FIXME(cramertj) collect input lifetimes to function and add them to + // the output `impl Trait` type here. + let mut bounds = vec![ + hir::TyParamBound::TraitTyParamBound( + hir::PolyTraitRef { + trait_ref: hir::TraitRef { + path: future_path, + ref_id: this.next_id().node_id, + }, + bound_generic_params: hir_vec![], + span, + }, + hir::TraitBoundModifier::None + ), + ]; + + if let Some((name, span)) = bound_lifetime { + bounds.push(hir::RegionTyParamBound( + hir::Lifetime { id: this.next_id().node_id, name, span })); + } + + hir::HirVec::from(bounds) + }); + + let LoweredNodeId { node_id, hir_id } = self.next_id(); + let impl_trait_ty = P(hir::Ty { + id: node_id, + node: impl_trait_ty, + span, + hir_id, + }); + + hir::FunctionRetTy::Return(impl_trait_ty) + } + fn lower_param_bound( &mut self, tpb: &GenericBound, @@ -2286,16 +2584,32 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); + self.with_new_scopes(|this| { + // Note: we can use non-async decl here because lower_body + // only cares about the input argument patterns, + // not the return types. let body_id = this.lower_body(Some(decl), |this| { - let body = this.lower_block(body, false); - this.expr_block(body, ThinVec::new()) + if let IsAsync::Async(async_node_id) = header.asyncness { + let async_expr = this.make_async_expr( + CaptureBy::Value, async_node_id, None, + |this| { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + }); + this.expr(body.span, async_expr, ThinVec::new()) + } else { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + } }); + let (generics, fn_decl) = this.add_in_band_defs( generics, fn_def_id, AnonymousLifetimeMode::PassThrough, - |this| this.lower_fn_decl(decl, Some(fn_def_id), true), + |this| this.lower_fn_decl( + decl, Some(fn_def_id), true, header.asyncness.is_async()) ); hir::ItemFn( @@ -2863,7 +3177,7 @@ impl<'a> LoweringContext<'a> { |this| { ( // Disallow impl Trait in foreign items - this.lower_fn_decl(fdec, None, false), + this.lower_fn_decl(fdec, None, false, false), this.lower_fn_args_to_names(fdec), ) }, @@ -2890,7 +3204,7 @@ impl<'a> LoweringContext<'a> { ) -> hir::MethodSig { hir::MethodSig { header: self.lower_fn_header(sig.header), - decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow), + decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, false), } } @@ -2926,7 +3240,7 @@ impl<'a> LoweringContext<'a> { fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync { match a { - IsAsync::Async => hir::IsAsync::Async, + IsAsync::Async(_) => hir::IsAsync::Async, IsAsync::NotAsync => hir::IsAsync::NotAsync, } } @@ -3218,46 +3532,101 @@ impl<'a> LoweringContext<'a> { arms.iter().map(|x| self.lower_arm(x)).collect(), hir::MatchSource::Normal, ), - ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => { + ExprKind::Async(capture_clause, closure_node_id, ref block) => { + self.make_async_expr(capture_clause, closure_node_id, None, |this| { + this.with_new_scopes(|this| { + let block = this.lower_block(block, false); + this.expr_block(block, ThinVec::new()) + }) + }) + }, + ExprKind::Closure( + capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span) => + { self.with_new_scopes(|this| { - let mut is_generator = false; - let body_id = this.lower_body(Some(decl), |this| { - let e = this.lower_expr(body); - is_generator = this.is_generator; - e - }); - let generator_option = if is_generator { - if !decl.inputs.is_empty() { - span_err!( + if let IsAsync::Async(async_closure_node_id) = asyncness { + // FIXME(cramertj) allow `async` non-`move` closures with + if capture_clause == CaptureBy::Ref && + !decl.inputs.is_empty() + { + struct_span_err!( this.sess, fn_decl_span, - E0628, - "generators cannot have explicit arguments" - ); - this.sess.abort_if_errors(); + E0705, + "`async` non-`move` closures with arguments \ + are not currently supported", + ) + .help("consider using `let` statements to manually capture \ + variables by reference before entering an \ + `async move` closure") + .emit(); } - Some(match movability { - Movability::Movable => hir::GeneratorMovability::Movable, - Movability::Static => hir::GeneratorMovability::Static, - }) + + // Transform `async |x: u8| -> X { ... }` into + // `|x: u8| future_from_generator(|| -> X { ... })` + let outer_decl = FnDecl { + inputs: decl.inputs.clone(), + output: FunctionRetTy::Default(fn_decl_span), + variadic: false, + }; + let body_id = this.lower_body(Some(&outer_decl), |this| { + let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output { + Some(&**ty) + } else { None }; + let async_body = this.make_async_expr( + capture_clause, async_closure_node_id, async_ret_ty, + |this| { + this.with_new_scopes(|this| this.lower_expr(body)) + }); + this.expr(fn_decl_span, async_body, ThinVec::new()) + }); + hir::ExprClosure( + this.lower_capture_clause(capture_clause), + this.lower_fn_decl(&outer_decl, None, false, false), + body_id, + fn_decl_span, + None, + ) } else { - if movability == Movability::Static { - span_err!( - this.sess, - fn_decl_span, - E0697, - "closures cannot be static" - ); - } - None - }; - hir::ExprClosure( - this.lower_capture_clause(capture_clause), - this.lower_fn_decl(decl, None, false), - body_id, - fn_decl_span, - generator_option, - ) + let mut is_generator = false; + let body_id = this.lower_body(Some(decl), |this| { + let e = this.lower_expr(body); + is_generator = this.is_generator; + e + }); + let generator_option = if is_generator { + if !decl.inputs.is_empty() { + span_err!( + this.sess, + fn_decl_span, + E0628, + "generators cannot have explicit arguments" + ); + this.sess.abort_if_errors(); + } + Some(match movability { + Movability::Movable => hir::GeneratorMovability::Movable, + Movability::Static => hir::GeneratorMovability::Static, + }) + } else { + if movability == Movability::Static { + span_err!( + this.sess, + fn_decl_span, + E0906, + "closures cannot be static" + ); + } + None + }; + hir::ExprClosure( + this.lower_capture_clause(capture_clause), + this.lower_fn_decl(decl, None, false, false), + body_id, + fn_decl_span, + generator_option, + ) + } }) } ExprKind::Block(ref blk, opt_label) => { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 8aa5dd4ad80..335e38bbe7e 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -99,6 +99,21 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } + ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => { + // For async functions, we need to create their inner defs inside of a + // closure to match their desugared representation. + let fn_def_data = DefPathData::ValueNs(i.ident.name.as_interned_str()); + let fn_def = self.create_def(i.id, fn_def_data, ITEM_LIKE_SPACE, i.span); + return self.with_parent(fn_def, |this| { + let closure_def = this.create_def(async_node_id, + DefPathData::ClosureExpr, + REGULAR_SPACE, + i.span); + this.with_parent(closure_def, |this| { + visit::walk_item(this, i); + }) + }); + } ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.name.as_interned_str()), @@ -227,15 +242,32 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { match expr.node { ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id), - ExprKind::Closure(..) => { - let def = self.create_def(expr.id, + ExprKind::Closure(_, asyncness, ..) => { + let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, REGULAR_SPACE, expr.span); - self.parent_def = Some(def); + self.parent_def = Some(closure_def); + + // Async closures desugar to closures inside of closures, so + // we must create two defs. + if let IsAsync::Async(async_id) = asyncness { + let async_def = self.create_def(async_id, + DefPathData::ClosureExpr, + REGULAR_SPACE, + expr.span); + self.parent_def = Some(async_def); + } + } + ExprKind::Async(_, async_id, _) => { + let async_def = self.create_def(async_id, + DefPathData::ClosureExpr, + REGULAR_SPACE, + expr.span); + self.parent_def = Some(async_def); } _ => {} - } + }; visit::walk_expr(self, expr); self.parent_def = parent_def; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 9479234cf11..bd6bef29c29 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -245,6 +245,16 @@ pub enum LifetimeName { } impl LifetimeName { + pub fn is_elided(self) -> bool { + match self { + LifetimeName::Implicit + | LifetimeName::Underscore => true, + LifetimeName::Fresh(_) + | LifetimeName::Static + | LifetimeName::Name(_) => false, + } + } + pub fn name(&self) -> Name { use self::LifetimeName::*; match *self { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 7b14831cf95..0f4603be39d 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -409,6 +409,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { + Async, DotFill, QuestionMark, ExistentialReturnType, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 7ed3abe66c2..ce270006a9d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1245,7 +1245,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { (has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) && !self.metadata_output_only(); let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; - if needs_inline || header.constness == hir::Constness::Const || always_encode_mir { + if needs_inline + || header.constness == hir::Constness::Const + || always_encode_mir + { self.encode_optimized_mir(def_id) } else { None diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e311701ac05..d3c19291594 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::{self, FnKind, Visitor}; use syntax::attr; -use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; +use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind, FnHeader}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path}; @@ -2054,13 +2054,54 @@ impl<'a> Resolver<'a> { self.check_proc_macro_attrs(&item.attrs); match item.node { + ItemKind::Fn(ref declaration, + FnHeader { asyncness: IsAsync::Async(async_closure_id), .. }, + ref generics, + ref body) => { + // Async functions are desugared from `async fn foo() { .. }` + // to `fn foo() { future_from_generator(move || ... ) }`, + // so we have to visit the body inside the closure scope + self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| { + this.visit_vis(&item.vis); + this.visit_ident(item.ident); + this.visit_generics(generics); + let rib_kind = ItemRibKind; + this.ribs[ValueNS].push(Rib::new(rib_kind)); + this.label_ribs.push(Rib::new(rib_kind)); + let mut bindings_list = FxHashMap(); + for argument in &declaration.inputs { + this.resolve_pattern( + &argument.pat, PatternSource::FnParam, &mut bindings_list); + this.visit_ty(&*argument.ty); + } + visit::walk_fn_ret_ty(this, &declaration.output); + + // Now resolve the inner closure + { + let rib_kind = ClosureRibKind(async_closure_id); + this.ribs[ValueNS].push(Rib::new(rib_kind)); + this.label_ribs.push(Rib::new(rib_kind)); + // No need to resolve either arguments nor return type, + // as this closure has neither + + // Resolve the body + this.visit_block(body); + this.label_ribs.pop(); + this.ribs[ValueNS].pop(); + } + this.label_ribs.pop(); + this.ribs[ValueNS].pop(); + + walk_list!(this, visit_attribute, &item.attrs); + }) + } ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) | ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) | - ItemKind::Fn(.., ref generics, _) => { + ItemKind::Fn(_, _, ref generics, _) => { self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), - |this| visit::walk_item(this, item)); + |this| visit::walk_item(this, item)); } ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => @@ -3888,6 +3929,49 @@ impl<'a> Resolver<'a> { visit::walk_expr(self, expr); self.current_type_ascription.pop(); } + // Resolve the body of async exprs inside the async closure to which they desugar + ExprKind::Async(_, async_closure_id, ref block) => { + let rib_kind = ClosureRibKind(async_closure_id); + self.ribs[ValueNS].push(Rib::new(rib_kind)); + self.label_ribs.push(Rib::new(rib_kind)); + self.visit_block(&block); + self.label_ribs.pop(); + self.ribs[ValueNS].pop(); + } + // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to + // resolve the arguments within the proper scopes so that usages of them inside the + // closure are detected as upvars rather than normal closure arg usages. + ExprKind::Closure( + _, IsAsync::Async(inner_closure_id), _, ref fn_decl, ref body, _span) => + { + let rib_kind = ClosureRibKind(expr.id); + self.ribs[ValueNS].push(Rib::new(rib_kind)); + self.label_ribs.push(Rib::new(rib_kind)); + // Resolve arguments: + let mut bindings_list = FxHashMap(); + for argument in &fn_decl.inputs { + self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + self.visit_ty(&argument.ty); + } + // No need to resolve return type-- the outer closure return type is + // FunctionRetTy::Default + + // Now resolve the inner closure + { + let rib_kind = ClosureRibKind(inner_closure_id); + self.ribs[ValueNS].push(Rib::new(rib_kind)); + self.label_ribs.push(Rib::new(rib_kind)); + // No need to resolve arguments: the inner closure has none. + // Resolve the return type: + visit::walk_fn_ret_ty(self, &fn_decl.output); + // Resolve the body + self.visit_expr(body); + self.label_ribs.pop(); + self.ribs[ValueNS].pop(); + } + self.label_ribs.pop(); + self.ribs[ValueNS].pop(); + } _ => { visit::walk_expr(self, expr); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 7da5b1668b3..262c0e40abc 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1555,7 +1555,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } } } - ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => { + ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => { let mut id = String::from("$"); id.push_str(&ex.id.to_string()); diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index b532aaf90df..9f2ca20276c 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -385,7 +385,7 @@ impl Sig for ast::Item { if header.constness.node == ast::Constness::Const { text.push_str("const "); } - if header.asyncness == ast::IsAsync::Async { + if header.asyncness.is_async() { text.push_str("async "); } if header.unsafety == ast::Unsafety::Unsafe { @@ -920,7 +920,7 @@ fn make_method_signature( if m.header.constness.node == ast::Constness::Const { text.push_str("const "); } - if m.header.asyncness == ast::IsAsync::Async { + if m.header.asyncness.is_async() { text.push_str("async "); } if m.header.unsafety == ast::Unsafety::Unsafe { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 366420cfcab..f149a9fe571 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1164,7 +1164,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, } if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) { - if let Item_::ItemFn(_, _, _, _, ref generics, _) = item.node { + if let Item_::ItemFn(_, _, ref generics, _) = item.node { if !generics.params.is_empty() { fcx.tcx.sess.span_err( span, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5989694116c..a0f29f5918e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2585,7 +2585,8 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "{}

    ", render_spotlight_traits(it)?)?;
         render_attributes(w, it)?;
         write!(w,
    -           "{vis}{constness}{asyncness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}
    ", + "{vis}{constness}{asyncness}{unsafety}{abi}fn \ + {name}{generics}{decl}{where_clause}", vis = VisSpace(&it.visibility), constness = ConstnessSpace(f.header.constness), asyncness = AsyncSpace(f.header.asyncness), diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a6061e96ae5..c74cd3feca3 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -263,6 +263,7 @@ #![feature(fn_traits)] #![feature(fnbox)] #![feature(futures_api)] +#![feature(generator_trait)] #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(integer_atomics)] @@ -410,8 +411,6 @@ pub use core::ops; #[stable(feature = "rust1", since = "1.0.0")] pub use core::ptr; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::raw; -#[stable(feature = "rust1", since = "1.0.0")] pub use core::result; #[stable(feature = "rust1", since = "1.0.0")] pub use core::option; @@ -496,6 +495,7 @@ pub mod os; pub mod panic; pub mod path; pub mod process; +pub mod raw; pub mod sync; pub mod time; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 8da70f5717e..812b0b9fdda 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -213,6 +213,26 @@ macro_rules! eprintln { ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); } +#[macro_export] +#[unstable(feature = "await_macro", issue = "50547")] +#[allow_internal_unstable] +macro_rules! await { + ($e:expr) => { { + let mut pinned = $e; + let mut pinned = unsafe { ::core::mem::PinMut::new_unchecked(&mut pinned) }; + loop { + match ::std::raw::with_get_cx(|cx| + ::core::future::Future::poll(pinned.reborrow(), cx)) + { + // FIXME(cramertj) prior to stabilizing await, we have to ensure that this + // can't be used to create a generator on stable via `|| await!()`. + ::core::task::Poll::Pending => yield, + ::core::task::Poll::Ready(x) => break x, + } + } + } } +} + /// A macro to select an event from a number of receivers. /// /// This macro is used to wait for the first event to occur on a number of diff --git a/src/libstd/raw.rs b/src/libstd/raw.rs new file mode 100644 index 00000000000..62fd42c4de7 --- /dev/null +++ b/src/libstd/raw.rs @@ -0,0 +1,110 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_docs)] +#![unstable(feature = "raw", issue = "27751")] + +//! Contains struct definitions for the layout of compiler built-in types. +//! +//! They can be used as targets of transmutes in unsafe code for manipulating +//! the raw representations directly. +//! +//! Their definition should always match the ABI defined in `rustc::back::abi`. + +use core::cell::Cell; +use core::future::Future; +use core::marker::Unpin; +use core::mem::PinMut; +use core::option::Option; +use core::ptr::NonNull; +use core::task::{self, Poll}; +use core::ops::{Drop, Generator, GeneratorState}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::raw::*; + +/// Wrap a future in a generator. +/// +/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give +/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). +#[unstable(feature = "gen_future", issue = "50547")] +pub fn future_from_generator>(x: T) -> impl Future { + GenFuture(x) +} + +/// A wrapper around generators used to implement `Future` for `async`/`await` code. +#[unstable(feature = "gen_future", issue = "50547")] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +struct GenFuture>(T); + +// We rely on the fact that async/await futures are immovable in order to create +// self-referential borrows in the underlying generator. +impl> !Unpin for GenFuture {} + +#[unstable(feature = "gen_future", issue = "50547")] +impl> Future for GenFuture { + type Output = T::Return; + fn poll(self: PinMut, cx: &mut task::Context) -> Poll { + with_set_cx(cx, || match unsafe { PinMut::get_mut(self).0.resume() } { + GeneratorState::Yielded(()) => Poll::Pending, + GeneratorState::Complete(x) => Poll::Ready(x), + }) + } +} + +thread_local! { + static TLS_CX: Cell>>> = Cell::new(None); +} + +struct SetOnDrop(Option>>); + +impl Drop for SetOnDrop { + fn drop(&mut self) { + TLS_CX.with(|tls_cx| { + tls_cx.set(self.0.take()); + }); + } +} + +#[unstable(feature = "gen_future", issue = "50547")] +pub fn with_set_cx(cx: &mut task::Context, f: F) -> R +where + F: FnOnce() -> R +{ + let old_cx = TLS_CX.with(|tls_cx| { + let old_cx = tls_cx.get(); + tls_cx.set(NonNull::new( + cx as *mut task::Context as *mut () as *mut task::Context<'static>)); + old_cx + }); + let _reset_cx = SetOnDrop(old_cx); + let res = f(); + res +} + +#[unstable(feature = "gen_future", issue = "50547")] +pub fn with_get_cx(f: F) -> R +where + F: FnOnce(&mut task::Context) -> R +{ + let cx_ptr = TLS_CX.with(|tls_cx| { + let cx_ptr = tls_cx.get(); + // Clear the entry so that nested `with_get_cx` calls + // will fail or set their own value. + tls_cx.set(None); + cx_ptr + }); + let _reset_cx = SetOnDrop(cx_ptr); + + let mut cx_ptr = cx_ptr.expect( + "TLS task::Context not set. This is a rustc bug. \ + Please file an issue on https://github.com/rust-lang/rust."); + unsafe { f(cx_ptr.as_mut()) } +} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 55c21c64c83..a57a9b95e5f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -987,6 +987,7 @@ impl Expr { ExprKind::Closure(..) => ExprPrecedence::Closure, ExprKind::Block(..) => ExprPrecedence::Block, ExprKind::Catch(..) => ExprPrecedence::Catch, + ExprKind::Async(..) => ExprPrecedence::Async, ExprKind::Assign(..) => ExprPrecedence::Assign, ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, ExprKind::Field(..) => ExprPrecedence::Field, @@ -1094,9 +1095,18 @@ pub enum ExprKind { /// A closure (for example, `move |a, b, c| a + b + c`) /// /// The final span is the span of the argument block `|...|` - Closure(CaptureBy, Movability, P, P, Span), + Closure(CaptureBy, IsAsync, Movability, P, P, Span), /// A block (`'label: { ... }`) Block(P, Option::B>::C; //~ ERROR cannot find type `A` in this scope let _ = <::B>::C; //~ ERROR cannot find type `A` in this scope let <::B>::C; //~ ERROR cannot find type `A` in this scope - let 0 ... <::B>::C; //~ ERROR cannot find type `A` in this scope + let 0 ..= <::B>::C; //~ ERROR cannot find type `A` in this scope //~^ ERROR only char and numeric types are allowed in range patterns <::B>::C; //~ ERROR cannot find type `A` in this scope } diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs index be76796c5c4..6063755c04f 100644 --- a/src/test/compile-fail/issue-27895.rs +++ b/src/test/compile-fail/issue-27895.rs @@ -13,7 +13,7 @@ fn main() { let index = 6; match i { - 0...index => println!("winner"), + 0..=index => println!("winner"), //~^ ERROR runtime values cannot be referenced in patterns _ => println!("hello"), } diff --git a/src/test/compile-fail/issue-41255.rs b/src/test/compile-fail/issue-41255.rs index bdd502d4420..29912de37eb 100644 --- a/src/test/compile-fail/issue-41255.rs +++ b/src/test/compile-fail/issue-41255.rs @@ -27,7 +27,7 @@ fn main() { //~| WARNING hard error //~| ERROR floating-point types cannot be used in patterns //~| WARNING hard error - 39.0 ... 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns + 39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns //~| WARNING hard error //~| ERROR floating-point types cannot be used in patterns //~| WARNING hard error diff --git a/src/test/compile-fail/match-range-fail-2.rs b/src/test/compile-fail/match-range-fail-2.rs index 91ad2b3507a..b42e2ff919a 100644 --- a/src/test/compile-fail/match-range-fail-2.rs +++ b/src/test/compile-fail/match-range-fail-2.rs @@ -12,7 +12,7 @@ fn main() { match 5 { - 6 ... 1 => { } + 6 ..= 1 => { } _ => { } }; //~^^^ ERROR lower range bound must be less than or equal to upper @@ -24,7 +24,7 @@ fn main() { //~^^^ ERROR lower range bound must be less than upper match 5u64 { - 0xFFFF_FFFF_FFFF_FFFF ... 1 => { } + 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } _ => { } }; //~^^^ ERROR lower range bound must be less than or equal to upper diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index f89b3e39390..ca99b0c7b89 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -10,21 +10,21 @@ fn main() { match "wow" { - "bar" ... "foo" => { } + "bar" ..= "foo" => { } }; //~^^ ERROR only char and numeric types are allowed in range //~| start type: &'static str //~| end type: &'static str match "wow" { - 10 ... "what" => () + 10 ..= "what" => () }; //~^^ ERROR only char and numeric types are allowed in range //~| start type: {integer} //~| end type: &'static str match 5 { - 'c' ... 100 => { } + 'c' ..= 100 => { } _ => { } }; //~^^^ ERROR mismatched types diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs index fe88ab4e117..1aae25105a8 100644 --- a/src/test/compile-fail/non-constant-in-const-path.rs +++ b/src/test/compile-fail/non-constant-in-const-path.rs @@ -11,7 +11,7 @@ fn main() { let x = 0; match 1 { - 0 ... x => {} + 0 ..= x => {} //~^ ERROR runtime values cannot be referenced in patterns }; } diff --git a/src/test/compile-fail/patkind-litrange-no-expr.rs b/src/test/compile-fail/patkind-litrange-no-expr.rs index d57a23f26c4..8fef98f815f 100644 --- a/src/test/compile-fail/patkind-litrange-no-expr.rs +++ b/src/test/compile-fail/patkind-litrange-no-expr.rs @@ -17,7 +17,7 @@ macro_rules! enum_number { fn foo(value: i32) -> Option<$name> { match value { $( $value => Some($name::$variant), )* // PatKind::Lit - $( $value ... 42 => Some($name::$variant), )* // PatKind::Range + $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range _ => None } } @@ -32,4 +32,3 @@ enum_number!(Change { }); fn main() {} - diff --git a/src/test/compile-fail/qualified-path-params.rs b/src/test/compile-fail/qualified-path-params.rs index a7bc27e1749..018a3b2ae32 100644 --- a/src/test/compile-fail/qualified-path-params.rs +++ b/src/test/compile-fail/qualified-path-params.rs @@ -29,6 +29,6 @@ fn main() { match 10 { ::A::f:: => {} //~^ ERROR expected unit struct/variant or constant, found method `<::A>::f` - 0 ... ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range + 0 ..= ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range } } diff --git a/src/test/compile-fail/refutable-pattern-errors.rs b/src/test/compile-fail/refutable-pattern-errors.rs index ce93e1875ae..7b4009481ab 100644 --- a/src/test/compile-fail/refutable-pattern-errors.rs +++ b/src/test/compile-fail/refutable-pattern-errors.rs @@ -9,10 +9,10 @@ // except according to those terms. -fn func((1, (Some(1), 2...3)): (isize, (Option, isize))) { } +fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } //~^ ERROR refutable pattern in function argument: `(_, _)` not covered fn main() { - let (1, (Some(1), 2...3)) = (1, (None, 2)); + let (1, (Some(1), 2..=3)) = (1, (None, 2)); //~^ ERROR refutable pattern in local binding: `(_, _)` not covered } diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index 62cb870c7bb..f9d1ce34535 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -286,16 +286,16 @@ fn run() { // would require parens in patterns to allow disambiguation... reject_expr_parse("match 0 { - 0...#[attr] 10 => () + 0..=#[attr] 10 => () }"); reject_expr_parse("match 0 { - 0...#[attr] -10 => () + 0..=#[attr] -10 => () }"); reject_expr_parse("match 0 { - 0...-#[attr] 10 => () + 0..=-#[attr] 10 => () }"); reject_expr_parse("match 0 { - 0...#[attr] FOO => () + 0..=#[attr] FOO => () }"); // make sure we don't catch this bug again... diff --git a/src/test/run-pass/byte-literals.rs b/src/test/run-pass/byte-literals.rs index ad779d26f9e..f5acb72429a 100644 --- a/src/test/run-pass/byte-literals.rs +++ b/src/test/run-pass/byte-literals.rs @@ -36,7 +36,7 @@ pub fn main() { } match 100 { - b'a' ... b'z' => {}, + b'a' ..= b'z' => {}, _ => panic!() } diff --git a/src/test/run-pass/inferred-suffix-in-pattern-range.rs b/src/test/run-pass/inferred-suffix-in-pattern-range.rs index 22369c77ed3..89d26aade2e 100644 --- a/src/test/run-pass/inferred-suffix-in-pattern-range.rs +++ b/src/test/run-pass/inferred-suffix-in-pattern-range.rs @@ -12,21 +12,21 @@ pub fn main() { let x = 2; let x_message = match x { - 0 ... 1 => { "not many".to_string() } + 0 ..= 1 => { "not many".to_string() } _ => { "lots".to_string() } }; assert_eq!(x_message, "lots".to_string()); let y = 2; let y_message = match y { - 0 ... 1 => { "not many".to_string() } + 0 ..= 1 => { "not many".to_string() } _ => { "lots".to_string() } }; assert_eq!(y_message, "lots".to_string()); let z = 1u64; let z_message = match z { - 0 ... 1 => { "not many".to_string() } + 0 ..= 1 => { "not many".to_string() } _ => { "lots".to_string() } }; assert_eq!(z_message, "not many".to_string()); diff --git a/src/test/run-pass/issue-12582.rs b/src/test/run-pass/issue-12582.rs index 7bab2ddfed0..b89964d968e 100644 --- a/src/test/run-pass/issue-12582.rs +++ b/src/test/run-pass/issue-12582.rs @@ -16,7 +16,7 @@ pub fn main() { assert_eq!(3, match (x, y) { (1, 1) => 1, (2, 2) => 2, - (1...2, 2) => 3, + (1..=2, 2) => 3, _ => 4, }); @@ -24,7 +24,7 @@ pub fn main() { assert_eq!(3, match ((x, y),) { ((1, 1),) => 1, ((2, 2),) => 2, - ((1...2, 2),) => 3, + ((1..=2, 2),) => 3, _ => 4, }); } diff --git a/src/test/run-pass/issue-13027.rs b/src/test/run-pass/issue-13027.rs index d28ea94ec1a..2c460900ef6 100644 --- a/src/test/run-pass/issue-13027.rs +++ b/src/test/run-pass/issue-13027.rs @@ -30,7 +30,7 @@ pub fn main() { fn lit_shadow_range() { assert_eq!(2, match 1 { 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); @@ -38,34 +38,34 @@ fn lit_shadow_range() { assert_eq!(2, match x+1 { 0 => 0, 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); assert_eq!(2, match val() { 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); assert_eq!(2, match CONST { 0 => 0, 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); // value is out of the range of second arm, should match wildcard pattern assert_eq!(3, match 3 { 1 if false => 1, - 1...2 => 2, + 1..=2 => 2, _ => 3 }); } fn range_shadow_lit() { assert_eq!(2, match 1 { - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); @@ -73,27 +73,27 @@ fn range_shadow_lit() { let x = 0; assert_eq!(2, match x+1 { 0 => 0, - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); assert_eq!(2, match val() { - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); assert_eq!(2, match CONST { 0 => 0, - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); // ditto assert_eq!(3, match 3 { - 1...2 if false => 1, + 1..=2 if false => 1, 1 => 2, _ => 3 }); @@ -101,36 +101,36 @@ fn range_shadow_lit() { fn range_shadow_range() { assert_eq!(2, match 1 { - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); let x = 0; assert_eq!(2, match x+1 { 100 => 0, - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); assert_eq!(2, match val() { - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); assert_eq!(2, match CONST { 100 => 0, - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); // ditto assert_eq!(3, match 5 { - 0...2 if false => 1, - 1...3 => 2, + 0..=2 if false => 1, + 1..=3 => 2, _ => 3, }); } @@ -138,7 +138,7 @@ fn range_shadow_range() { fn multi_pats_shadow_lit() { assert_eq!(2, match 1 { 100 => 0, - 0 | 1...10 if false => 1, + 0 | 1..=10 if false => 1, 1 => 2, _ => 3, }); @@ -147,8 +147,8 @@ fn multi_pats_shadow_lit() { fn multi_pats_shadow_range() { assert_eq!(2, match 1 { 100 => 0, - 0 | 1...10 if false => 1, - 1...3 => 2, + 0 | 1..=10 if false => 1, + 1..=3 => 2, _ => 3, }); } @@ -157,7 +157,7 @@ fn lit_shadow_multi_pats() { assert_eq!(2, match 1 { 100 => 0, 1 if false => 1, - 0 | 1...10 => 2, + 0 | 1..=10 => 2, _ => 3, }); } @@ -165,8 +165,8 @@ fn lit_shadow_multi_pats() { fn range_shadow_multi_pats() { assert_eq!(2, match 1 { 100 => 0, - 1...3 if false => 1, - 0 | 1...10 => 2, + 1..=3 if false => 1, + 0 | 1..=10 => 2, _ => 3, }); } diff --git a/src/test/run-pass/issue-13867.rs b/src/test/run-pass/issue-13867.rs index e21070e2eaf..bc28dc54de6 100644 --- a/src/test/run-pass/issue-13867.rs +++ b/src/test/run-pass/issue-13867.rs @@ -19,14 +19,14 @@ enum Foo { fn main() { let r = match (Foo::FooNullary, 'a') { - (Foo::FooUint(..), 'a'...'z') => 1, + (Foo::FooUint(..), 'a'..='z') => 1, (Foo::FooNullary, 'x') => 2, _ => 0 }; assert_eq!(r, 0); let r = match (Foo::FooUint(0), 'a') { - (Foo::FooUint(1), 'a'...'z') => 1, + (Foo::FooUint(1), 'a'..='z') => 1, (Foo::FooUint(..), 'x') => 2, (Foo::FooNullary, 'a') => 3, _ => 0 @@ -34,7 +34,7 @@ fn main() { assert_eq!(r, 0); let r = match ('a', Foo::FooUint(0)) { - ('a'...'z', Foo::FooUint(1)) => 1, + ('a'..='z', Foo::FooUint(1)) => 1, ('x', Foo::FooUint(..)) => 2, ('a', Foo::FooNullary) => 3, _ => 0 @@ -42,15 +42,15 @@ fn main() { assert_eq!(r, 0); let r = match ('a', 'a') { - ('a'...'z', 'b') => 1, - ('x', 'a'...'z') => 2, + ('a'..='z', 'b') => 1, + ('x', 'a'..='z') => 2, _ => 0 }; assert_eq!(r, 0); let r = match ('a', 'a') { - ('a'...'z', 'b') => 1, - ('x', 'a'...'z') => 2, + ('a'..='z', 'b') => 1, + ('x', 'a'..='z') => 2, ('a', 'a') => 3, _ => 0 }; diff --git a/src/test/run-pass/issue-18060.rs b/src/test/run-pass/issue-18060.rs index d6c9a92ca02..322a3d8c9bb 100644 --- a/src/test/run-pass/issue-18060.rs +++ b/src/test/run-pass/issue-18060.rs @@ -11,7 +11,7 @@ // Regression test for #18060: match arms were matching in the wrong order. fn main() { - assert_eq!(2, match (1, 3) { (0, 2...5) => 1, (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); - assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); - assert_eq!(2, match (1, 7) { (0, 2...5) => 1, (1, 7) => 2, (_, 2...5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 7) { (0, 2..=5) => 1, (1, 7) => 2, (_, 2..=5) => 3, (_, _) => 4 }); } diff --git a/src/test/run-pass/issue-18464.rs b/src/test/run-pass/issue-18464.rs index dff86bc1b45..f4faab5e468 100644 --- a/src/test/run-pass/issue-18464.rs +++ b/src/test/run-pass/issue-18464.rs @@ -15,7 +15,7 @@ const HIGH_RANGE: char = '9'; fn main() { match '5' { - LOW_RANGE...HIGH_RANGE => (), + LOW_RANGE..=HIGH_RANGE => (), _ => () }; } diff --git a/src/test/run-pass/issue-21475.rs b/src/test/run-pass/issue-21475.rs index 0666a1f133f..99839b56506 100644 --- a/src/test/run-pass/issue-21475.rs +++ b/src/test/run-pass/issue-21475.rs @@ -14,9 +14,9 @@ use m::{START, END}; fn main() { match 42 { - m::START...m::END => {}, - 0...m::END => {}, - m::START...59 => {}, + m::START..=m::END => {}, + 0..=m::END => {}, + m::START..=59 => {}, _ => {}, } } diff --git a/src/test/run-pass/issue-26251.rs b/src/test/run-pass/issue-26251.rs index 1e77d54fbf9..3735d36147d 100644 --- a/src/test/run-pass/issue-26251.rs +++ b/src/test/run-pass/issue-26251.rs @@ -12,9 +12,9 @@ fn main() { let x = 'a'; let y = match x { - 'a'...'b' if false => "one", + 'a'..='b' if false => "one", 'a' => "two", - 'a'...'b' => "three", + 'a'..='b' => "three", _ => panic!("what?"), }; diff --git a/src/test/run-pass/issue-35423.rs b/src/test/run-pass/issue-35423.rs index 35d0c305ed8..34cb2930db0 100644 --- a/src/test/run-pass/issue-35423.rs +++ b/src/test/run-pass/issue-35423.rs @@ -12,7 +12,7 @@ fn main () { let x = 4; match x { ref r if *r < 0 => println!("got negative num {} < 0", r), - e @ 1 ... 100 => println!("got number within range [1,100] {}", e), + e @ 1 ..= 100 => println!("got number within range [1,100] {}", e), _ => println!("no"), } } diff --git a/src/test/run-pass/issue-7222.rs b/src/test/run-pass/issue-7222.rs index 1bf343e23f0..3eb39ad6aad 100644 --- a/src/test/run-pass/issue-7222.rs +++ b/src/test/run-pass/issue-7222.rs @@ -14,7 +14,7 @@ pub fn main() { const FOO: f64 = 10.0; match 0.0 { - 0.0 ... FOO => (), + 0.0 ..= FOO => (), _ => () } } diff --git a/src/test/run-pass/macro-literal.rs b/src/test/run-pass/macro-literal.rs index 0bcda7bc144..6d5e8bc97c0 100644 --- a/src/test/run-pass/macro-literal.rs +++ b/src/test/run-pass/macro-literal.rs @@ -41,18 +41,18 @@ macro_rules! mtester_dbg { } macro_rules! catch_range { - ($s:literal ... $e:literal) => { - &format!("macro caught literal: {} ... {}", $s, $e) + ($s:literal ..= $e:literal) => { + &format!("macro caught literal: {} ..= {}", $s, $e) }; - (($s:expr) ... ($e:expr)) => { // Must use ')' before '...' - &format!("macro caught expr: {} ... {}", $s, $e) + (($s:expr) ..= ($e:expr)) => { // Must use ')' before '..=' + &format!("macro caught expr: {} ..= {}", $s, $e) }; } macro_rules! pat_match { - ($s:literal ... $e:literal) => { + ($s:literal ..= $e:literal) => { match 3 { - $s ... $e => "literal, in range", + $s ..= $e => "literal, in range", _ => "literal, other", } }; @@ -115,22 +115,22 @@ pub fn main() { assert_eq!(mtester!('c'), "macro caught literal: c"); assert_eq!(mtester!(-1.2), "macro caught literal: -1.2"); assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3"); - assert_eq!(catch_range!(2 ... 3), "macro caught literal: 2 ... 3"); + assert_eq!(catch_range!(2 ..= 3), "macro caught literal: 2 ..= 3"); assert_eq!(match_attr!(#[attr] 1), "attr matched literal"); assert_eq!(test_user!(10, 20), "literal"); assert_eq!(mtester!(false), "macro caught literal: false"); assert_eq!(mtester!(true), "macro caught literal: true"); match_produced_attr!("a"); let _a = LiteralProduced; - assert_eq!(pat_match!(1 ... 3), "literal, in range"); - assert_eq!(pat_match!(4 ... 6), "literal, other"); + assert_eq!(pat_match!(1 ..= 3), "literal, in range"); + assert_eq!(pat_match!(4 ..= 6), "literal, other"); // Cases where 'expr' catches assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2"); assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2"); assert_eq!(mtester!((1 + 3)), "macro caught expr: 4"); assert_eq!(mtester_dbg!(()), "macro caught expr: ()"); - assert_eq!(catch_range!((1 + 1) ... (2 + 2)), "macro caught expr: 2 ... 4"); + assert_eq!(catch_range!((1 + 1) ..= (2 + 2)), "macro caught expr: 2 ..= 4"); assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr"); assert_eq!(test_user!(10, (20 + 2)), "expr"); diff --git a/src/test/run-pass/match-range-infer.rs b/src/test/run-pass/match-range-infer.rs index 74f513ef081..cf07345d343 100644 --- a/src/test/run-pass/match-range-infer.rs +++ b/src/test/run-pass/match-range-infer.rs @@ -12,15 +12,15 @@ pub fn main() { match 1 { - 1 ... 3 => {} + 1 ..= 3 => {} _ => panic!("should match range") } match 1 { - 1 ... 3u16 => {} + 1 ..= 3u16 => {} _ => panic!("should match range with inferred start type") } match 1 { - 1u16 ... 3 => {} + 1u16 ..= 3 => {} _ => panic!("should match range with inferred end type") } } diff --git a/src/test/run-pass/match-range-static.rs b/src/test/run-pass/match-range-static.rs index 9aafcda1b02..b63ca7defd6 100644 --- a/src/test/run-pass/match-range-static.rs +++ b/src/test/run-pass/match-range-static.rs @@ -15,7 +15,7 @@ const e: isize = 42; pub fn main() { match 7 { - s...e => (), + s..=e => (), _ => (), } } diff --git a/src/test/run-pass/match-range.rs b/src/test/run-pass/match-range.rs index cf695a77ce1..859edb80a07 100644 --- a/src/test/run-pass/match-range.rs +++ b/src/test/run-pass/match-range.rs @@ -12,7 +12,7 @@ pub fn main() { match 5_usize { - 1_usize...5_usize => {} + 1_usize..=5_usize => {} _ => panic!("should match range"), } match 1_usize { @@ -20,7 +20,7 @@ pub fn main() { _ => panic!("should match range start"), } match 5_usize { - 6_usize...7_usize => panic!("shouldn't match range"), + 6_usize..=7_usize => panic!("shouldn't match range"), _ => {} } match 7_usize { @@ -29,23 +29,23 @@ pub fn main() { } match 5_usize { 1_usize => panic!("should match non-first range"), - 2_usize...6_usize => {} + 2_usize..=6_usize => {} _ => panic!("math is broken") } match 'c' { - 'a'...'z' => {} + 'a'..='z' => {} _ => panic!("should suppport char ranges") } match -3 { - -7...5 => {} + -7..=5 => {} _ => panic!("should match signed range") } match 3.0f64 { - 1.0...5.0 => {} + 1.0..=5.0 => {} _ => panic!("should match float range") } match -1.5f64 { - -3.6...3.6 => {} + -3.6..=3.6 => {} _ => panic!("should match negative float range") } match 3.5 { diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/range.rs b/src/test/run-pass/rfc-2005-default-binding-mode/range.rs index 2292d97eaf4..f38bd2de869 100644 --- a/src/test/run-pass/rfc-2005-default-binding-mode/range.rs +++ b/src/test/run-pass/rfc-2005-default-binding-mode/range.rs @@ -11,8 +11,8 @@ pub fn main() { let i = 5; match &&&&i { - 1 ... 3 => panic!(), - 3 ... 8 => {}, + 1 ..= 3 => panic!(), + 3 ..= 8 => {}, _ => panic!(), } } diff --git a/src/test/ui/check_match/issue-43253.rs b/src/test/ui/check_match/issue-43253.rs index a01ebb768b4..aace8c0c02b 100644 --- a/src/test/ui/check_match/issue-43253.rs +++ b/src/test/ui/check_match/issue-43253.rs @@ -23,13 +23,13 @@ fn main() { match 10 { 1..10 => {}, - 9...10 => {}, + 9..=10 => {}, _ => {}, } match 10 { 1..10 => {}, - 10...10 => {}, + 10..=10 => {}, _ => {}, } @@ -42,13 +42,13 @@ fn main() { match 10 { 1..10 => {}, - 8...9 => {}, + 8..=9 => {}, _ => {}, } match 10 { 1..10 => {}, - 9...9 => {}, + 9..=9 => {}, _ => {}, } } diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr index 111f4e44ee9..2af6a2a6368 100644 --- a/src/test/ui/check_match/issue-43253.stderr +++ b/src/test/ui/check_match/issue-43253.stderr @@ -13,12 +13,12 @@ LL | #![warn(unreachable_patterns)] warning: unreachable pattern --> $DIR/issue-43253.rs:45:9 | -LL | 8...9 => {}, +LL | 8..=9 => {}, | ^^^^^ warning: unreachable pattern --> $DIR/issue-43253.rs:51:9 | -LL | 9...9 => {}, +LL | 9..=9 => {}, | ^^^^^ diff --git a/src/test/ui/const-eval/const_signed_pat.rs b/src/test/ui/const-eval/const_signed_pat.rs index f53d6f3fa0a..008ebf13c63 100644 --- a/src/test/ui/const-eval/const_signed_pat.rs +++ b/src/test/ui/const-eval/const_signed_pat.rs @@ -13,7 +13,7 @@ fn main() { const MIN: i8 = -5; match 5i8 { - MIN...-1 => {}, + MIN..=-1 => {}, _ => {}, } } diff --git a/src/test/ui/const-eval/ref_to_int_match.rs b/src/test/ui/const-eval/ref_to_int_match.rs index 4c5fc6c3797..8ad7f11f0ce 100644 --- a/src/test/ui/const-eval/ref_to_int_match.rs +++ b/src/test/ui/const-eval/ref_to_int_match.rs @@ -11,8 +11,8 @@ fn main() { let n: Int = 40; match n { - 0...10 => {}, - 10...BAR => {}, //~ ERROR lower range bound must be less than or equal to upper + 0..=10 => {}, + 10..=BAR => {}, //~ ERROR lower range bound must be less than or equal to upper _ => {}, } } diff --git a/src/test/ui/const-eval/ref_to_int_match.stderr b/src/test/ui/const-eval/ref_to_int_match.stderr index eef7b6df252..64ea57702d7 100644 --- a/src/test/ui/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/const-eval/ref_to_int_match.stderr @@ -1,7 +1,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/ref_to_int_match.rs:15:9 | -LL | 10...BAR => {}, //~ ERROR lower range bound must be less than or equal to upper +LL | 10..=BAR => {}, //~ ERROR lower range bound must be less than or equal to upper | ^^ lower bound larger than upper bound error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0029-teach.rs b/src/test/ui/error-codes/E0029-teach.rs index 1bc2c2d58b1..328c46311af 100644 --- a/src/test/ui/error-codes/E0029-teach.rs +++ b/src/test/ui/error-codes/E0029-teach.rs @@ -14,7 +14,7 @@ fn main() { let s = "hoho"; match s { - "hello" ... "world" => {} + "hello" ..= "world" => {} //~^ ERROR only char and numeric types are allowed in range patterns _ => {} } diff --git a/src/test/ui/error-codes/E0029-teach.stderr b/src/test/ui/error-codes/E0029-teach.stderr index 4bb71f68a98..bb4fac9a4cb 100644 --- a/src/test/ui/error-codes/E0029-teach.stderr +++ b/src/test/ui/error-codes/E0029-teach.stderr @@ -1,7 +1,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/E0029-teach.rs:17:9 | -LL | "hello" ... "world" => {} +LL | "hello" ..= "world" => {} | ^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types | = note: start type: &'static str diff --git a/src/test/ui/error-codes/E0029.rs b/src/test/ui/error-codes/E0029.rs index 29b6fe44113..c89b4f5b377 100644 --- a/src/test/ui/error-codes/E0029.rs +++ b/src/test/ui/error-codes/E0029.rs @@ -12,7 +12,7 @@ fn main() { let s = "hoho"; match s { - "hello" ... "world" => {} + "hello" ..= "world" => {} //~^ ERROR only char and numeric types are allowed in range patterns _ => {} } diff --git a/src/test/ui/error-codes/E0029.stderr b/src/test/ui/error-codes/E0029.stderr index bcdfa387111..d25666f9cf8 100644 --- a/src/test/ui/error-codes/E0029.stderr +++ b/src/test/ui/error-codes/E0029.stderr @@ -1,7 +1,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/E0029.rs:15:9 | -LL | "hello" ... "world" => {} +LL | "hello" ..= "world" => {} | ^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types | = note: start type: &'static str diff --git a/src/test/ui/error-codes/E0030-teach.rs b/src/test/ui/error-codes/E0030-teach.rs index 2af32eda62b..cf860cea24c 100644 --- a/src/test/ui/error-codes/E0030-teach.rs +++ b/src/test/ui/error-codes/E0030-teach.rs @@ -12,7 +12,7 @@ fn main() { match 5u32 { - 1000 ... 5 => {} + 1000 ..= 5 => {} //~^ ERROR lower range bound must be less than or equal to upper } } diff --git a/src/test/ui/error-codes/E0030-teach.stderr b/src/test/ui/error-codes/E0030-teach.stderr index 8b262d5b296..2a7243a9569 100644 --- a/src/test/ui/error-codes/E0030-teach.stderr +++ b/src/test/ui/error-codes/E0030-teach.stderr @@ -1,7 +1,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030-teach.rs:15:9 | -LL | 1000 ... 5 => {} +LL | 1000 ..= 5 => {} | ^^^^ lower bound larger than upper bound | = note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. diff --git a/src/test/ui/error-codes/E0030.rs b/src/test/ui/error-codes/E0030.rs index ef3bded4bef..e147dd932b0 100644 --- a/src/test/ui/error-codes/E0030.rs +++ b/src/test/ui/error-codes/E0030.rs @@ -11,7 +11,7 @@ fn main() { match 5u32 { - 1000 ... 5 => {} + 1000 ..= 5 => {} //~^ ERROR lower range bound must be less than or equal to upper } } diff --git a/src/test/ui/error-codes/E0030.stderr b/src/test/ui/error-codes/E0030.stderr index 0949cfb50b6..020655ee45b 100644 --- a/src/test/ui/error-codes/E0030.stderr +++ b/src/test/ui/error-codes/E0030.stderr @@ -1,7 +1,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030.rs:14:9 | -LL | 1000 ... 5 => {} +LL | 1000 ..= 5 => {} | ^^^^ lower bound larger than upper bound error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0308-4.rs b/src/test/ui/error-codes/E0308-4.rs index bb4cd143416..106c55817c1 100644 --- a/src/test/ui/error-codes/E0308-4.rs +++ b/src/test/ui/error-codes/E0308-4.rs @@ -11,7 +11,7 @@ fn main() { let x = 1u8; match x { - 0u8...3i8 => (), //~ ERROR E0308 + 0u8..=3i8 => (), //~ ERROR E0308 _ => () } } diff --git a/src/test/ui/error-codes/E0308-4.stderr b/src/test/ui/error-codes/E0308-4.stderr index 31875349bac..8943c7332e9 100644 --- a/src/test/ui/error-codes/E0308-4.stderr +++ b/src/test/ui/error-codes/E0308-4.stderr @@ -1,7 +1,7 @@ error[E0308]: mismatched types --> $DIR/E0308-4.rs:14:9 | -LL | 0u8...3i8 => (), //~ ERROR E0308 +LL | 0u8..=3i8 => (), //~ ERROR E0308 | ^^^^^^^^^ expected u8, found i8 error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 2394549af5fafa0eb7e52ff291970be5b35af7cf Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 14 Jun 2018 08:42:13 +0200 Subject: Unix sockets on redox! --- src/libstd/sys/redox/ext/mod.rs | 1 + src/libstd/sys/redox/ext/net.rs | 728 ++++++++++++++++++++++++++++++++++++++++ src/libstd/sys/redox/fd.rs | 5 +- 3 files changed, 733 insertions(+), 1 deletion(-) create mode 100644 src/libstd/sys/redox/ext/net.rs (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs index 9fd8d6c9186..cb2c75ae0bf 100644 --- a/src/libstd/sys/redox/ext/mod.rs +++ b/src/libstd/sys/redox/ext/mod.rs @@ -33,6 +33,7 @@ pub mod ffi; pub mod fs; pub mod io; +pub mod net; pub mod process; pub mod thread; diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs new file mode 100644 index 00000000000..78ed8194088 --- /dev/null +++ b/src/libstd/sys/redox/ext/net.rs @@ -0,0 +1,728 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "unix_socket", since = "1.10.0")] + +//! Unix-specific networking functionality + +use fmt; +use io::{self, Error, ErrorKind, Initializer}; +use net::Shutdown; +use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; +use path::Path; +use time::Duration; +use sys::{cvt, fd::FileDesc, syscall}; + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +#[derive(Clone)] +pub struct SocketAddr; + +impl SocketAddr { + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + None + } +} +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SocketAddr") + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); +/// stream.write_all(b"hello world").unwrap(); +/// let mut response = String::new(); +/// stream.read_to_string(&mut response).unwrap(); +/// println!("{}", response); +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(FileDesc); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixStream) + } else { + Err(Error::new(ErrorKind::Other, "UnixStream::connect: non-utf8 paths not supported on redox")) + } + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)).map(FileDesc::new)?; + let client = server.duplicate_path(b"connect")?; + let stream = server.duplicate_path(b"listen")?; + Ok((UnixStream(client), UnixStream(stream))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::take_error unimplemented on redox")) + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(FileDesc); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixListener) + } else { + Err(Error::new(ErrorKind::Other, "UnixListener::bind: non-utf8 paths not supported on redox")) + } + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr)) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/tmp/sock").unwrap(); + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixListener::take_error unimplemented on redox")) + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: struct.SocketAddr.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming<'a>(&'a self) -> Incoming<'a> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// [`None`]: ../../../../std/option/enum.Option.html#variant.None +/// [`UnixListener`]: struct.UnixListener.html +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) + } +} diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index ba7bbdc657f..e04e2791b23 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -47,7 +47,10 @@ impl FileDesc { } pub fn duplicate(&self) -> io::Result { - let new_fd = cvt(syscall::dup(self.fd, &[]))?; + self.duplicate_path(&[]) + } + pub fn duplicate_path(&self, path: &[u8]) -> io::Result { + let new_fd = cvt(syscall::dup(self.fd, path))?; Ok(FileDesc::new(new_fd)) } -- cgit 1.4.1-3-g733a5 From 3b866b0ea44a27e8fa1f7bedabb42c92b670d467 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 14 Jun 2018 11:17:08 +0200 Subject: Make UnixStream::take_error return None on redox --- src/libstd/sys/redox/ext/net.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 78ed8194088..abfbfaa8dbb 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -352,7 +352,7 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::take_error unimplemented on redox")) + Ok(None) } /// Shuts down the read, write, or both halves of this connection. @@ -373,7 +373,7 @@ impl UnixStream { /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } @@ -607,7 +607,7 @@ impl UnixListener { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixListener::take_error unimplemented on redox")) + Ok(None) } /// Returns an iterator over incoming connections. -- cgit 1.4.1-3-g733a5 From 419500710d40d49eadc2dbea37aa83a64b2bf6d3 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 14 Jun 2018 16:24:01 +0200 Subject: Trim all lines to 100 --- src/libstd/sys/redox/ext/net.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index abfbfaa8dbb..21c3903e623 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -132,7 +132,10 @@ impl UnixStream { .map(FileDesc::new) .map(UnixStream) } else { - Err(Error::new(ErrorKind::Other, "UnixStream::connect: non-utf8 paths not supported on redox")) + Err(Error::new( + ErrorKind::Other, + "UnixStream::connect: non-utf8 paths not supported on redox" + )) } } @@ -155,7 +158,8 @@ impl UnixStream { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)).map(FileDesc::new)?; + let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new)?; let client = server.duplicate_path(b"connect")?; let stream = server.duplicate_path(b"listen")?; Ok((UnixStream(client), UnixStream(stream))) @@ -511,7 +515,10 @@ impl UnixListener { .map(FileDesc::new) .map(UnixListener) } else { - Err(Error::new(ErrorKind::Other, "UnixListener::bind: non-utf8 paths not supported on redox")) + Err(Error::new( + ErrorKind::Other, + "UnixListener::bind: non-utf8 paths not supported on redox" + )) } } -- cgit 1.4.1-3-g733a5 From c5977e3ea7e7c4f901e6c089294e0986373d41f8 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 14 Jun 2018 18:21:21 +0200 Subject: Custom feature gate (I think?) --- src/libstd/sys/redox/ext/net.rs | 80 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 21c3903e623..b95f0dd02f1 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "unix_socket", since = "1.10.0")] +#![stable(feature = "unix_socket_redox", since = "1.27.0")] //! Unix-specific networking functionality @@ -36,7 +36,7 @@ use sys::{cvt, fd::FileDesc, syscall}; /// }; /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] #[derive(Clone)] pub struct SocketAddr; @@ -65,12 +65,12 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.as_pathname(), None); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn as_pathname(&self) -> Option<&Path> { None } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "SocketAddr") @@ -91,10 +91,10 @@ impl fmt::Debug for SocketAddr { /// stream.read_to_string(&mut response).unwrap(); /// println!("{}", response); /// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] pub struct UnixStream(FileDesc); -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); @@ -125,7 +125,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn connect>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) @@ -156,7 +156,7 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new)?; @@ -180,7 +180,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } @@ -195,7 +195,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) } @@ -210,7 +210,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.peer_addr().expect("Couldn't get peer address"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn peer_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) } @@ -249,7 +249,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) } @@ -288,7 +288,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) } @@ -305,7 +305,7 @@ impl UnixStream { /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn read_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) } @@ -322,7 +322,7 @@ impl UnixStream { /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn write_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) } @@ -337,7 +337,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -354,7 +354,7 @@ impl UnixStream { /// println!("Got error: {:?}", err); /// } /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -376,13 +376,13 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl io::Read for UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) @@ -394,7 +394,7 @@ impl io::Read for UnixStream { } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> io::Read for &'a UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -406,7 +406,7 @@ impl<'a> io::Read for &'a UnixStream { } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl io::Write for UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { io::Write::write(&mut &*self, buf) @@ -417,7 +417,7 @@ impl io::Write for UnixStream { } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -428,21 +428,21 @@ impl<'a> io::Write for &'a UnixStream { } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl AsRawFd for UnixStream { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl FromRawFd for UnixStream { unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl IntoRawFd for UnixStream { fn into_raw_fd(self) -> RawFd { self.0.into_raw() @@ -477,10 +477,10 @@ impl IntoRawFd for UnixStream { /// } /// } /// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] pub struct UnixListener(FileDesc); -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); @@ -508,7 +508,7 @@ impl UnixListener { /// } /// }; /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn bind>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) @@ -542,7 +542,7 @@ impl UnixListener { /// Err(e) => println!("accept function failed: {:?}", e), /// } /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr)) } @@ -562,7 +562,7 @@ impl UnixListener { /// /// let listener_copy = listener.try_clone().expect("try_clone failed"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } @@ -578,7 +578,7 @@ impl UnixListener { /// /// let addr = listener.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) } @@ -594,7 +594,7 @@ impl UnixListener { /// /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -612,7 +612,7 @@ impl UnixListener { /// println!("Got error: {:?}", err); /// } /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -648,34 +648,34 @@ impl UnixListener { /// } /// } /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] + #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn incoming<'a>(&'a self) -> Incoming<'a> { Incoming { listener: self } } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl AsRawFd for UnixListener { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl FromRawFd for UnixListener { unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl IntoRawFd for UnixListener { fn into_raw_fd(self) -> RawFd { self.0.into_raw() } } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; @@ -716,12 +716,12 @@ impl<'a> IntoIterator for &'a UnixListener { /// } /// ``` #[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] pub struct Incoming<'a> { listener: &'a UnixListener, } -#[stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; -- cgit 1.4.1-3-g733a5 From 2161254d8a211e9e5caecf259ac9fbcad6479030 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 18 Jun 2018 06:30:38 +0200 Subject: Make feature unstable --- src/libstd/sys/redox/ext/net.rs | 41 +---------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index b95f0dd02f1..396a140fa1b 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "unix_socket_redox", since = "1.27.0")] +#![unstable(feature = "unix_socket_redox", reason = "new feature", issue="51553")] //! Unix-specific networking functionality @@ -36,7 +36,6 @@ use sys::{cvt, fd::FileDesc, syscall}; /// }; /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` -#[stable(feature = "unix_socket_redox", since = "1.27.0")] #[derive(Clone)] pub struct SocketAddr; @@ -65,12 +64,10 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.as_pathname(), None); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn as_pathname(&self) -> Option<&Path> { None } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "SocketAddr") @@ -91,10 +88,8 @@ impl fmt::Debug for SocketAddr { /// stream.read_to_string(&mut response).unwrap(); /// println!("{}", response); /// ``` -#[stable(feature = "unix_socket_redox", since = "1.27.0")] pub struct UnixStream(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); @@ -125,7 +120,6 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn connect>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) @@ -156,7 +150,6 @@ impl UnixStream { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new)?; @@ -180,7 +173,6 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } @@ -195,7 +187,6 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) } @@ -210,7 +201,6 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.peer_addr().expect("Couldn't get peer address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn peer_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) } @@ -249,7 +239,6 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) } @@ -288,7 +277,6 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) } @@ -305,7 +293,6 @@ impl UnixStream { /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn read_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) } @@ -322,7 +309,6 @@ impl UnixStream { /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn write_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) } @@ -337,7 +323,6 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -354,7 +339,6 @@ impl UnixStream { /// println!("Got error: {:?}", err); /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -376,13 +360,11 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl io::Read for UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) @@ -394,7 +376,6 @@ impl io::Read for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> io::Read for &'a UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -406,7 +387,6 @@ impl<'a> io::Read for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl io::Write for UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { io::Write::write(&mut &*self, buf) @@ -417,7 +397,6 @@ impl io::Write for UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -428,21 +407,18 @@ impl<'a> io::Write for &'a UnixStream { } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl AsRawFd for UnixStream { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl FromRawFd for UnixStream { unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl IntoRawFd for UnixStream { fn into_raw_fd(self) -> RawFd { self.0.into_raw() @@ -477,10 +453,8 @@ impl IntoRawFd for UnixStream { /// } /// } /// ``` -#[stable(feature = "unix_socket_redox", since = "1.27.0")] pub struct UnixListener(FileDesc); -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); @@ -508,7 +482,6 @@ impl UnixListener { /// } /// }; /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn bind>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) @@ -542,7 +515,6 @@ impl UnixListener { /// Err(e) => println!("accept function failed: {:?}", e), /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr)) } @@ -562,7 +534,6 @@ impl UnixListener { /// /// let listener_copy = listener.try_clone().expect("try_clone failed"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } @@ -578,7 +549,6 @@ impl UnixListener { /// /// let addr = listener.local_addr().expect("Couldn't get local address"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) } @@ -594,7 +564,6 @@ impl UnixListener { /// /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -612,7 +581,6 @@ impl UnixListener { /// println!("Got error: {:?}", err); /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -648,34 +616,29 @@ impl UnixListener { /// } /// } /// ``` - #[stable(feature = "unix_socket_redox", since = "1.27.0")] pub fn incoming<'a>(&'a self) -> Incoming<'a> { Incoming { listener: self } } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl AsRawFd for UnixListener { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl FromRawFd for UnixListener { unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(FileDesc::new(fd)) } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl IntoRawFd for UnixListener { fn into_raw_fd(self) -> RawFd { self.0.into_raw() } } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; @@ -716,12 +679,10 @@ impl<'a> IntoIterator for &'a UnixListener { /// } /// ``` #[derive(Debug)] -#[stable(feature = "unix_socket_redox", since = "1.27.0")] pub struct Incoming<'a> { listener: &'a UnixListener, } -#[stable(feature = "unix_socket_redox", since = "1.27.0")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; -- cgit 1.4.1-3-g733a5 From 4286ad7f0d3e1c39ac31205e43011e29b1486dcf Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 18 Jun 2018 07:15:59 +0200 Subject: Disallow constructing SocketAddr from third-party code --- src/libstd/sys/redox/ext/net.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 396a140fa1b..2ae7803378e 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -37,7 +37,7 @@ use sys::{cvt, fd::FileDesc, syscall}; /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` #[derive(Clone)] -pub struct SocketAddr; +pub struct SocketAddr(()); impl SocketAddr { /// Returns the contents of this address if it is a `pathname` address. @@ -516,7 +516,7 @@ impl UnixListener { /// } /// ``` pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr)) + self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) } /// Creates a new independently owned handle to the underlying socket. -- cgit 1.4.1-3-g733a5 From 4bebd24fcaa2a16ee9afcf51a7baca2a4b98b230 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 18 Jun 2018 07:23:51 +0200 Subject: Remove functions that always error --- src/libstd/sys/redox/ext/net.rs | 181 ---------------------------------------- 1 file changed, 181 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 2ae7803378e..0dab7db9a93 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -94,12 +94,6 @@ impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } builder.finish() } } @@ -177,142 +171,6 @@ impl UnixStream { self.0.duplicate().map(UnixStream) } - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// ``` - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// ``` - pub fn peer_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - pub fn read_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - pub fn write_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) - } - /// Moves the socket into or out of nonblocking mode. /// /// # Examples @@ -342,27 +200,6 @@ impl UnixStream { pub fn take_error(&self) -> io::Result> { Ok(None) } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// ``` - pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) - } } impl io::Read for UnixStream { @@ -459,9 +296,6 @@ impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } builder.finish() } } @@ -538,21 +372,6 @@ impl UnixListener { self.0.duplicate().map(UnixListener) } - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// ``` - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) - } - /// Moves the socket into or out of nonblocking mode. /// /// # Examples -- cgit 1.4.1-3-g733a5 From c86a7a01e27f78474ff5ce2fe7f88aa2cb14caad Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 26 Jun 2018 08:23:16 +0200 Subject: Mention redox' behavior in doc comments --- src/libstd/sys/redox/ext/net.rs | 6 ++++++ src/libstd/sys/unix/ext/net.rs | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 0dab7db9a93..2d791fa75cf 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -197,6 +197,9 @@ impl UnixStream { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -400,6 +403,9 @@ impl UnixListener { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. pub fn take_error(&self) -> io::Result> { Ok(None) } diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index e277b1aa7b5..55f43ccd7db 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -524,6 +524,9 @@ impl UnixStream { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() @@ -846,6 +849,9 @@ impl UnixListener { /// println!("Got error: {:?}", err); /// } /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. #[stable(feature = "unix_socket", since = "1.10.0")] pub fn take_error(&self) -> io::Result> { self.0.take_error() -- cgit 1.4.1-3-g733a5 From 916f7c864a1da3bb822a282a9f7386c78bdc2c69 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 26 Jun 2018 19:21:55 +0200 Subject: Revert "Remove functions that always error" This reverts commit 21d09b983de87fec2e98832f4c30b52f12d6342f. --- src/libstd/sys/redox/ext/net.rs | 181 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 2d791fa75cf..d29d28c8427 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -94,6 +94,12 @@ impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } builder.finish() } } @@ -171,6 +177,142 @@ impl UnixStream { self.0.duplicate().map(UnixStream) } + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// ``` + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// ``` + pub fn peer_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + pub fn read_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + pub fn write_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) + } + /// Moves the socket into or out of nonblocking mode. /// /// # Examples @@ -203,6 +345,27 @@ impl UnixStream { pub fn take_error(&self) -> io::Result> { Ok(None) } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// ``` + pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) + } } impl io::Read for UnixStream { @@ -299,6 +462,9 @@ impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } builder.finish() } } @@ -375,6 +541,21 @@ impl UnixListener { self.0.duplicate().map(UnixListener) } + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// ``` + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) + } + /// Moves the socket into or out of nonblocking mode. /// /// # Examples -- cgit 1.4.1-3-g733a5 From 771748d0ba2fd956a5bddaa2c265115c47f49343 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Tue, 26 Jun 2018 22:58:25 +0200 Subject: Fix the error reference for LocalKey::try_with --- src/libstd/thread/local.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 40d3280baa6..a170abb2628 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -276,7 +276,7 @@ impl LocalKey { /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. If the key has been destroyed (which may happen if this is called - /// in a destructor), this function will return a `ThreadLocalError`. + /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html). /// /// # Panics /// -- cgit 1.4.1-3-g733a5 From a4e190546c9aaa06630577adb7310a8674bbac06 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Wed, 27 Jun 2018 10:11:46 +0200 Subject: Horrible attempt at cleaning things up that probably just made it worse --- src/libstd/sys/redox/ext/mod.rs | 1 + src/libstd/sys/redox/ext/net.rs | 705 +------------------------- src/libstd/sys/redox/ext/unixsocket.rs | 250 ++++++++++ src/libstd/sys/unix/ext/mod.rs | 1 + src/libstd/sys/unix/ext/net.rs | 869 +-------------------------------- src/libstd/sys/unix/ext/unixsocket.rs | 366 ++++++++++++++ src/libstd/sys_common/mod.rs | 1 + src/libstd/sys_common/unixsocket.rs | 704 ++++++++++++++++++++++++++ 8 files changed, 1348 insertions(+), 1549 deletions(-) create mode 100644 src/libstd/sys/redox/ext/unixsocket.rs create mode 100644 src/libstd/sys/unix/ext/unixsocket.rs create mode 100644 src/libstd/sys_common/unixsocket.rs (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs index cb2c75ae0bf..c86b5d78524 100644 --- a/src/libstd/sys/redox/ext/mod.rs +++ b/src/libstd/sys/redox/ext/mod.rs @@ -36,6 +36,7 @@ pub mod io; pub mod net; pub mod process; pub mod thread; +pub(crate) mod unixsocket; /// A prelude for conveniently writing platform-specific code. /// diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index d29d28c8427..eb256885155 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -1,702 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![unstable(feature = "unix_socket_redox", reason = "new feature", issue="51553")] - -//! Unix-specific networking functionality - -use fmt; -use io::{self, Error, ErrorKind, Initializer}; -use net::Shutdown; -use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; -use path::Path; -use time::Duration; -use sys::{cvt, fd::FileDesc, syscall}; - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -pub struct SocketAddr(()); - -impl SocketAddr { - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// ``` - pub fn as_pathname(&self) -> Option<&Path> { - None - } -} -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "SocketAddr") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); -/// stream.write_all(b"hello world").unwrap(); -/// let mut response = String::new(); -/// stream.read_to_string(&mut response).unwrap(); -/// println!("{}", response); -/// ``` -pub struct UnixStream(FileDesc); - -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - pub fn connect>(path: P) -> io::Result { - if let Some(s) = path.as_ref().to_str() { - cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) - .map(FileDesc::new) - .map(UnixStream) - } else { - Err(Error::new( - ErrorKind::Other, - "UnixStream::connect: non-utf8 paths not supported on redox" - )) - } - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) - .map(FileDesc::new)?; - let client = server.duplicate_path(b"connect")?; - let stream = server.duplicate_path(b"listen")?; - Ok((UnixStream(client), UnixStream(stream))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// ``` - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// ``` - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// ``` - pub fn peer_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - pub fn read_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - pub fn write_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// ``` - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - pub fn take_error(&self) -> io::Result> { - Ok(None) - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// ``` - pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) - } -} - -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - self.0.raw() - } -} - -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(FileDesc::new(fd)) - } -} - -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// ``` -pub struct UnixListener(FileDesc); - -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - pub fn bind>(path: P) -> io::Result { - if let Some(s) = path.as_ref().to_str() { - cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) - .map(FileDesc::new) - .map(UnixListener) - } else { - Err(Error::new( - ErrorKind::Other, - "UnixListener::bind: non-utf8 paths not supported on redox" - )) - } - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// ``` - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// ``` - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// ``` - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// ``` - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/tmp/sock").unwrap(); - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - pub fn take_error(&self) -> io::Result> { - Ok(None) - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`SocketAddr`]: struct.SocketAddr.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// ``` - pub fn incoming<'a>(&'a self) -> Incoming<'a> { - Incoming { listener: self } - } -} - -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - self.0.raw() - } -} - -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(FileDesc::new(fd)) - } -} - -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw() - } -} - -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// [`None`]: ../../../../std/option/enum.Option.html#variant.None -/// [`UnixListener`]: struct.UnixListener.html -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// ``` -#[derive(Debug)] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} +#![stable(feature = "unix_socket", since = "1.10.0")] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use sys_common::unixsocket::*; diff --git a/src/libstd/sys/redox/ext/unixsocket.rs b/src/libstd/sys/redox/ext/unixsocket.rs new file mode 100644 index 00000000000..78ca0f16af4 --- /dev/null +++ b/src/libstd/sys/redox/ext/unixsocket.rs @@ -0,0 +1,250 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "unix_socket", since = "1.10.0")] + +use fmt; +use io::{self, Error, ErrorKind, Initializer}; +use net::Shutdown; +use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; +use path::Path; +use time::Duration; +use sys::{cvt, fd::FileDesc, syscall}; + +#[stable(feature = "unix_socket", since = "1.10.0")] +#[derive(Clone)] +pub(crate) struct SocketAddr(()); + +impl SocketAddr { + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn as_pathname(&self) -> Option<&Path> { + None + } +} +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SocketAddr") + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub(crate) struct UnixStream(FileDesc); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn connect(path: &Path) -> io::Result { + if let Some(s) = path.to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixStream) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixStream::connect: non-utf8 paths not supported on redox" + )) + } + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn pair() -> io::Result<(UnixStream, UnixStream)> { + let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new)?; + let client = server.duplicate_path(b"connect")?; + let stream = server.duplicate_path(b"listen")?; + Ok((UnixStream(client), UnixStream(stream))) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn peer_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn read_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn write_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn take_error(&self) -> io::Result> { + Ok(None) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn shutdown(&self, _how: Shutdown) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub(crate) struct UnixListener(FileDesc); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn bind(path: &Path) -> io::Result { + if let Some(s) = path.to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixListener) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixListener::bind: non-utf8 paths not supported on redox" + )) + } + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub(crate) fn take_error(&self) -> io::Result> { + Ok(None) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(FileDesc::new(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index 88e4237f8e2..b7a1b45e9b7 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -44,6 +44,7 @@ pub mod process; pub mod raw; pub mod thread; pub mod net; +pub(crate) mod unixsocket; /// A prelude for conveniently writing platform-specific code. /// diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 55f43ccd7db..77bca85fe88 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -25,32 +25,34 @@ mod libc { pub struct sockaddr_un; } -use ascii; -use ffi::OsStr; use fmt; -use io::{self, Initializer}; +use io; use mem; use net::{self, Shutdown}; use os::unix::ffi::OsStrExt; use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; use path::Path; use time::Duration; -use sys::{self, cvt}; +use sys::ext::unixsocket as inner; use sys::net::Socket; +use sys::{self, cvt}; use sys_common::{self, AsInner, FromInner, IntoInner}; +#[stable(feature = "unix_socket", since = "1.10.0")] +pub use sys_common::unixsocket::*; + #[cfg(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "haiku", target_os = "bitrig"))] -use libc::MSG_NOSIGNAL; +pub(crate) use libc::MSG_NOSIGNAL; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "haiku", target_os = "bitrig")))] -const MSG_NOSIGNAL: libc::c_int = 0x0; +pub(crate) const MSG_NOSIGNAL: libc::c_int = 0x0; -fn sun_path_offset() -> usize { +pub(crate) fn sun_path_offset() -> usize { // Work with an actual instance of the type since using a null pointer is UB let addr: libc::sockaddr_un = unsafe { mem::uninitialized() }; let base = &addr as *const _ as usize; @@ -58,7 +60,7 @@ fn sun_path_offset() -> usize { path - base } -unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { +pub(crate) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { let mut addr: libc::sockaddr_un = mem::zeroed(); addr.sun_family = libc::AF_UNIX as libc::sa_family_t; @@ -87,557 +89,22 @@ unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::sockl Ok((addr, len as libc::socklen_t)) } -enum AddressKind<'a> { - Unnamed, - Pathname(&'a Path), - Abstract(&'a [u8]), -} - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - fn new(f: F) -> io::Result - where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket")); - } - - Ok(SocketAddr { - addr, - len, - }) - } - - /// Returns true if and only if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { - true - } else { - false - } - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { - Some(path) - } else { - None - } - } - - fn address<'a>(&'a self) -> AddressKind<'a> { - let len = self.len as usize - sun_path_offset(); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); -/// stream.write_all(b"hello world").unwrap(); -/// let mut response = String::new(); -/// stream.read_to_string(&mut response).unwrap(); -/// println!("{}", response); -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - inner(path.as_ref()) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl AsRawFd for net::TcpStream { fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl AsRawFd for net::TcpListener { fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl AsRawFd for net::UdpSocket { fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } } -#[stable(feature = "from_raw_os", since = "1.1.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl FromRawFd for net::TcpStream { unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { let socket = sys::net::Socket::from_inner(fd); @@ -645,7 +112,7 @@ impl FromRawFd for net::TcpStream { } } -#[stable(feature = "from_raw_os", since = "1.1.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl FromRawFd for net::TcpListener { unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { let socket = sys::net::Socket::from_inner(fd); @@ -653,7 +120,7 @@ impl FromRawFd for net::TcpListener { } } -#[stable(feature = "from_raw_os", since = "1.1.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl FromRawFd for net::UdpSocket { unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { let socket = sys::net::Socket::from_inner(fd); @@ -680,300 +147,6 @@ impl IntoRawFd for net::UdpSocket { } } -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - inner(path.as_ref()) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/tmp/sock").unwrap(); - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`SocketAddr`]: struct.SocketAddr.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming<'a>(&'a self) -> Incoming<'a> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// [`None`]: ../../../../std/option/enum.Option.html#variant.None -/// [`UnixListener`]: struct.UnixListener.html -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} - /// A Unix datagram socket. /// /// # Examples @@ -1150,7 +323,8 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + inner::SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + .map(SocketAddr) } /// Returns the address of this socket's peer. @@ -1171,7 +345,8 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + inner::SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + .map(SocketAddr) } /// Receives data from the socket. @@ -1194,7 +369,7 @@ impl UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { let mut count = 0; - let addr = SocketAddr::new(|addr, len| { + let addr = SocketAddr(inner::SocketAddr::new(|addr, len| { unsafe { count = libc::recvfrom(*self.0.as_inner(), buf.as_mut_ptr() as *mut _, @@ -1210,7 +385,7 @@ impl UnixDatagram { -1 } } - })?; + })?); Ok((count as usize, addr)) } diff --git a/src/libstd/sys/unix/ext/unixsocket.rs b/src/libstd/sys/unix/ext/unixsocket.rs new file mode 100644 index 00000000000..f6996ecd66f --- /dev/null +++ b/src/libstd/sys/unix/ext/unixsocket.rs @@ -0,0 +1,366 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "unix_socket", since = "1.10.0")] + +//! Unix-specific networking functionality + +#[cfg(unix)] +use libc; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +mod libc { + pub use libc::c_int; + pub type socklen_t = u32; + pub struct sockaddr; + #[derive(Clone)] + pub struct sockaddr_un; +} + +use ascii; +use ffi::OsStr; +use fmt; +use io::{self, Initializer}; +use mem; +use net::Shutdown; +use os::unix::ffi::OsStrExt; +use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; +use path::Path; +use time::Duration; +use sys::cvt; +use sys::net::Socket; +use sys::ext::net::*; +use sys_common::{AsInner, FromInner, IntoInner}; + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +#[derive(Clone)] +pub struct SocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, +} + +impl SocketAddr { + pub(crate) fn new(f: F) -> io::Result + where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int + { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as libc::socklen_t; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + + pub(crate) fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address + } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket")); + } + + Ok(SocketAddr { + addr, + len, + }) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + if let AddressKind::Unnamed = self.address() { + true + } else { + false + } + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { + Some(path) + } else { + None + } + } + + fn address<'a>(&'a self) -> AddressKind<'a> { + let len = self.len as usize - sun_path_offset(); + let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} + +struct AsciiEscaped<'a>(&'a [u8]); + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); +/// stream.write_all(b"hello world").unwrap(); +/// let mut response = String::new(); +/// stream.read_to_string(&mut response).unwrap(); +/// println!("{}", response); +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; + Ok((UnixStream(i1), UnixStream(i2))) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(Socket::from_inner(fd)) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = SocketAddr::from_parts(storage, len)?; + Ok((UnixStream(sock), addr)) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index d0c4d6a7737..7fb273826cc 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -54,6 +54,7 @@ pub mod util; pub mod wtf8; pub mod bytestring; pub mod process; +pub mod unixsocket; cfg_if! { if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] { diff --git a/src/libstd/sys_common/unixsocket.rs b/src/libstd/sys_common/unixsocket.rs new file mode 100644 index 00000000000..96037d6c5d9 --- /dev/null +++ b/src/libstd/sys_common/unixsocket.rs @@ -0,0 +1,704 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(any(all(unix, not(target_os = "emscripten")), target_os = "redox"))] +#![stable(feature = "unix_socket", since = "1.10.0")] + +//! Unix-specific networking functionality + +use fmt; +use io::{self, Initializer}; +use net::Shutdown; +use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; +use path::Path; +use time::Duration; + +use sys::ext::unixsocket as inner; + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +#[derive(Clone)] +pub struct SocketAddr(pub(crate) inner::SocketAddr); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.0) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + UnixStream(inner::UnixStream::from_raw_fd(fd)) + } +} +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &self.0, buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + io::Read::initializer(&&self.0) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &self.0, buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + io::Read::initializer(&&self.0) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &self.0, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &self.0) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &self.0, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &self.0) + } +} + +impl SocketAddr { + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + self.0.as_pathname() + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); +/// stream.write_all(b"hello world").unwrap(); +/// let mut response = String::new(); +/// stream.read_to_string(&mut response).unwrap(); +/// println!("{}", response); +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(inner::UnixStream); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.0) + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + inner::UnixStream::connect(path.as_ref()).map(UnixStream) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + inner::UnixStream::pair().map(|(s1, s2)| (UnixStream(s1), UnixStream(s2))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.try_clone().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + self.0.local_addr().map(SocketAddr) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + self.0.peer_addr().map(SocketAddr) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_read_timeout(timeout) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_write_timeout(timeout) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.read_timeout() + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.write_timeout() + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } +} + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// pub fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(inner::UnixListener); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.0) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + UnixListener(inner::UnixListener::from_raw_fd(fd)) + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + inner::UnixListener::bind(path.as_ref()).map(UnixListener) + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + self.0.accept().map(|(s, a)| (UnixStream(s), SocketAddr(a))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.try_clone().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + self.0.local_addr().map(SocketAddr) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/tmp/sock").unwrap(); + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: struct.SocketAddr.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// pub fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming<'a>(&'a self) -> Incoming<'a> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// [`None`]: ../../../../std/option/enum.Option.html#variant.None +/// [`UnixListener`]: struct.UnixListener.html +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// pub fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +#[derive(Debug)] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) + } +} -- cgit 1.4.1-3-g733a5 From 79bf00f4063793b3828001a845f6111d628c3349 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Wed, 27 Jun 2018 14:52:08 +0200 Subject: Fix tidy checks --- src/libstd/sys/redox/ext/net.rs | 10 ++++++++++ src/libstd/sys/unix/ext/net.rs | 10 ++++++---- src/libstd/sys/unix/ext/unixsocket.rs | 4 +++- src/libstd/sys_common/mod.rs | 4 +++- src/libstd/sys_common/unixsocket.rs | 1 - 5 files changed, 22 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index eb256885155..16eec67fb87 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![stable(feature = "unix_socket", since = "1.10.0")] #[stable(feature = "unix_socket", since = "1.10.0")] pub use sys_common::unixsocket::*; diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 77bca85fe88..9251871baf6 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -323,8 +323,9 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - inner::SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - .map(SocketAddr) + inner::SocketAddr::new(|addr, len| unsafe { + libc::getsockname(*self.0.as_inner(), addr, len) + }).map(SocketAddr) } /// Returns the address of this socket's peer. @@ -345,8 +346,9 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { - inner::SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - .map(SocketAddr) + inner::SocketAddr::new(|addr, len| unsafe { + libc::getsockname(*self.0.as_inner(), addr, len) + }).map(SocketAddr) } /// Receives data from the socket. diff --git a/src/libstd/sys/unix/ext/unixsocket.rs b/src/libstd/sys/unix/ext/unixsocket.rs index f6996ecd66f..7b52a5fcf0d 100644 --- a/src/libstd/sys/unix/ext/unixsocket.rs +++ b/src/libstd/sys/unix/ext/unixsocket.rs @@ -65,7 +65,9 @@ impl SocketAddr { } } - pub(crate) fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { + pub(crate) fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) + -> io::Result + { if len == 0 { // When there is a datagram from unnamed unix socket // linux returns zero bytes of address diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 7fb273826cc..89f5fd79f40 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -54,7 +54,9 @@ pub mod util; pub mod wtf8; pub mod bytestring; pub mod process; -pub mod unixsocket; + +#[cfg(any(all(unix, not(target_os = "emscripten")), target_os = "redox"))] +pub(crate) mod unixsocket; cfg_if! { if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] { diff --git a/src/libstd/sys_common/unixsocket.rs b/src/libstd/sys_common/unixsocket.rs index 96037d6c5d9..286e0e9f37f 100644 --- a/src/libstd/sys_common/unixsocket.rs +++ b/src/libstd/sys_common/unixsocket.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg(any(all(unix, not(target_os = "emscripten")), target_os = "redox"))] #![stable(feature = "unix_socket", since = "1.10.0")] //! Unix-specific networking functionality -- cgit 1.4.1-3-g733a5 From a9f7cc3b4968d1ec5a8bc857a83ea7ade33fffa8 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Wed, 27 Jun 2018 08:56:19 -0700 Subject: [fuchsia] Update zx_cprng_draw to target semantics This change is the final step in improving the semantics of zx_cprng_draw. Now the syscall always generates the requested number of bytes. If the syscall would have failed to generate the requested number of bytes, the syscall either terminates the entire operating system or terminates the calling process, depending on whether the error is a result of the kernel misbehaving or the userspace program misbehaving. --- src/libstd/sys/unix/rand.rs | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 3f7f0671490..01c0ada4ffb 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -183,34 +183,10 @@ mod imp { mod imp { #[link(name = "zircon")] extern { - fn zx_cprng_draw_new(buffer: *mut u8, len: usize) -> i32; - } - - fn getrandom(buf: &mut [u8]) -> Result { - unsafe { - let status = zx_cprng_draw_new(buf.as_mut_ptr(), buf.len()); - if status == 0 { - Ok(buf.len()) - } else { - Err(status) - } - } + fn zx_cprng_draw(buffer: *mut u8, len: usize); } pub fn fill_bytes(v: &mut [u8]) { - let mut buf = v; - while !buf.is_empty() { - let ret = getrandom(buf); - match ret { - Err(err) => { - panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})", - err, buf.len()) - } - Ok(actual) => { - let move_buf = buf; - buf = &mut move_buf[(actual as usize)..]; - } - } - } + unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) } } } -- cgit 1.4.1-3-g733a5 From c98631075748d19c1dce3768fdff9918e8f1492a Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Wed, 27 Jun 2018 18:37:44 +0200 Subject: Add is_unnamed on redox --- src/libstd/sys/redox/ext/unixsocket.rs | 48 ++++++++++++++++++---------------- src/libstd/sys/unix/ext/unixsocket.rs | 6 +++-- src/libstd/sys_common/unixsocket.rs | 28 ++++++++++++++++++++ 3 files changed, 58 insertions(+), 24 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/unixsocket.rs b/src/libstd/sys/redox/ext/unixsocket.rs index 78ca0f16af4..be37575145a 100644 --- a/src/libstd/sys/redox/ext/unixsocket.rs +++ b/src/libstd/sys/redox/ext/unixsocket.rs @@ -20,11 +20,15 @@ use sys::{cvt, fd::FileDesc, syscall}; #[stable(feature = "unix_socket", since = "1.10.0")] #[derive(Clone)] -pub(crate) struct SocketAddr(()); +pub struct SocketAddr(()); impl SocketAddr { #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn as_pathname(&self) -> Option<&Path> { + pub fn is_unnamed(&self) -> bool { + false + } + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { None } } @@ -36,7 +40,7 @@ impl fmt::Debug for SocketAddr { } #[stable(feature = "unix_socket", since = "1.10.0")] -pub(crate) struct UnixStream(FileDesc); +pub struct UnixStream(FileDesc); #[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixStream { @@ -55,7 +59,7 @@ impl fmt::Debug for UnixStream { impl UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn connect(path: &Path) -> io::Result { + pub fn connect(path: &Path) -> io::Result { if let Some(s) = path.to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) .map(FileDesc::new) @@ -69,7 +73,7 @@ impl UnixStream { } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn pair() -> io::Result<(UnixStream, UnixStream)> { + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new)?; let client = server.duplicate_path(b"connect")?; @@ -78,52 +82,52 @@ impl UnixStream { } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn try_clone(&self) -> io::Result { + pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn local_addr(&self) -> io::Result { + pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn peer_addr(&self) -> io::Result { + pub fn peer_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { + pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { + pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn read_timeout(&self) -> io::Result> { + pub fn read_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn write_timeout(&self) -> io::Result> { + pub fn write_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn take_error(&self) -> io::Result> { + pub fn take_error(&self) -> io::Result> { Ok(None) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn shutdown(&self, _how: Shutdown) -> io::Result<()> { + pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } @@ -173,7 +177,7 @@ impl IntoRawFd for UnixStream { } #[stable(feature = "unix_socket", since = "1.10.0")] -pub(crate) struct UnixListener(FileDesc); +pub struct UnixListener(FileDesc); #[stable(feature = "unix_socket", since = "1.10.0")] impl fmt::Debug for UnixListener { @@ -189,7 +193,7 @@ impl fmt::Debug for UnixListener { impl UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn bind(path: &Path) -> io::Result { + pub fn bind(path: &Path) -> io::Result { if let Some(s) = path.to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new) @@ -203,27 +207,27 @@ impl UnixListener { } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn try_clone(&self) -> io::Result { + pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn local_addr(&self) -> io::Result { + pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } #[stable(feature = "unix_socket", since = "1.10.0")] - pub(crate) fn take_error(&self) -> io::Result> { + pub fn take_error(&self) -> io::Result> { Ok(None) } } diff --git a/src/libstd/sys/unix/ext/unixsocket.rs b/src/libstd/sys/unix/ext/unixsocket.rs index 7b52a5fcf0d..124555141a3 100644 --- a/src/libstd/sys/unix/ext/unixsocket.rs +++ b/src/libstd/sys/unix/ext/unixsocket.rs @@ -54,7 +54,8 @@ pub struct SocketAddr { } impl SocketAddr { - pub(crate) fn new(f: F) -> io::Result + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn new(f: F) -> io::Result where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int { unsafe { @@ -65,7 +66,8 @@ impl SocketAddr { } } - pub(crate) fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { if len == 0 { diff --git a/src/libstd/sys_common/unixsocket.rs b/src/libstd/sys_common/unixsocket.rs index 286e0e9f37f..c7d71ae6790 100644 --- a/src/libstd/sys_common/unixsocket.rs +++ b/src/libstd/sys_common/unixsocket.rs @@ -113,6 +113,34 @@ impl<'a> io::Write for &'a UnixStream { } impl SocketAddr { + /// Returns true if and only if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + self.0.is_unnamed() + } + /// Returns the contents of this address if it is a `pathname` address. /// /// # Examples -- cgit 1.4.1-3-g733a5 From 30d825ce72c6e56a3c82f338897a437eaa8cd882 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Wed, 27 Jun 2018 20:15:24 +0200 Subject: Fix doc links --- src/libcore/future.rs | 14 +++++++++----- src/libstd/error.rs | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/future.rs b/src/libcore/future.rs index a8c8f69411e..153cd6c0724 100644 --- a/src/libcore/future.rs +++ b/src/libcore/future.rs @@ -45,18 +45,18 @@ pub trait Future { /// /// This function returns: /// - /// - `Poll::Pending` if the future is not ready yet - /// - `Poll::Ready(val)` with the result `val` of this future if it finished - /// successfully. + /// - [`Poll::Pending`] if the future is not ready yet + /// - [`Poll::Ready(val)`] with the result `val` of this future if it + /// finished successfully. /// /// Once a future has finished, clients should not `poll` it again. /// /// When a future is not ready yet, `poll` returns - /// [`Poll::Pending`](::task::Poll). The future will *also* register the + /// `Poll::Pending`. The future will *also* register the /// interest of the current task in the value being produced. For example, /// if the future represents the availability of data on a socket, then the /// task is recorded so that when data arrives, it is woken up (via - /// [`cx.waker()`](::task::Context::waker)). Once a task has been woken up, + /// [`cx.waker()`]). Once a task has been woken up, /// it should attempt to `poll` the future again, which may or may not /// produce a final value. /// @@ -90,6 +90,10 @@ pub trait Future { /// then any future calls to `poll` may panic, block forever, or otherwise /// cause bad behavior. The `Future` trait itself provides no guarantees /// about the behavior of `poll` after a future has completed. + /// + /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending + /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready + /// [`cx.waker()`]: ../task/struct.Context.html#method.waker fn poll(self: PinMut, cx: &mut task::Context) -> Poll; } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3160485375f..1958915602f 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -49,6 +49,7 @@ use string; /// /// [`Result`]: ../result/enum.Result.html /// [`Display`]: ../fmt/trait.Display.html +/// [`Debug`]: ../fmt/trait.Debug.html /// [`cause`]: trait.Error.html#method.cause #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { -- cgit 1.4.1-3-g733a5 From d39c66bf4ff2b49957edadf10afcc4050c3fc60b Mon Sep 17 00:00:00 2001 From: moxian Date: Tue, 8 May 2018 06:19:55 +0000 Subject: Add a fallback for stacktrace printing for older Windows versions. PR #47252 switched stack inspection functions of dbghelp.dll to their newer alternatives that also capture inlined context. Unfortunately, said new alternatives are not present in older dbghelp.dll versions. In particular Windows 7 at the time of writing has dbghelp.dll version 6.1.7601 from 2010, that lacks StackWalkEx and friends. Fixes #50138 --- src/libstd/sys/windows/backtrace/mod.rs | 170 +++++++++++---- src/libstd/sys/windows/backtrace/printing/msvc.rs | 253 ++++++++++++++++------ src/libstd/sys/windows/c.rs | 16 ++ 3 files changed, 331 insertions(+), 108 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 82498ad4d58..8e879e0f49e 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -48,24 +48,21 @@ pub mod gnu; pub use self::printing::{resolve_symname, foreach_symbol_fileline}; -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ +pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; // Fetch the symbols necessary from dbghelp.dll let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - let StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?; + // StackWalkEx might not be present and we'll fall back to StackWalk64 + let ResStackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn); + let ResStackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn); // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; let thread = unsafe { c::GetCurrentThread() }; let mut context: c::CONTEXT = unsafe { mem::zeroed() }; unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; - frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; - let image = init_frame(&mut frame, &context); let backtrace_context = BacktraceContext { handle: process, @@ -76,49 +73,139 @@ pub fn unwind_backtrace(frames: &mut [Frame]) // Initialize this process's symbols let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) }; if ret != c::TRUE { - return Ok((0, backtrace_context)) + return Ok((0, backtrace_context)); } // And now that we're done with all the setup, do the stack walking! - let mut i = 0; - unsafe { - while i < frames.len() && - StackWalkEx(image, process, thread, &mut frame, &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0) == c::TRUE - { - let addr = (frame.AddrPC.Offset - 1) as *const u8; - - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.InlineFrameContext, - }; - i += 1; + match (ResStackWalkEx, ResStackWalk64) { + (Ok(StackWalkEx), _) => { + let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; + frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; + let image = init_frame_ex(&mut frame, &context); + + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalkEx( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) == c::TRUE + { + let addr = (frame.AddrPC.Offset - 1) as *const u8; + + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: frame.InlineFrameContext, + }; + i += 1; + } + } + + Ok((i, backtrace_context)) } + (_, Ok(StackWalk64)) => { + let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; + let image = init_frame_64(&mut frame, &context); + + // Start from -1 to avoid printing this stack frame, which will + // always be exactly the same. + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalk64( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) == c::TRUE + { + let addr = frame.AddrPC.Offset; + if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 + { + break; + } + + frames[i] = Frame { + symbol_addr: (addr - 1) as *const u8, + exact_position: (addr - 1) as *const u8, + inline_context: 0, + }; + i += 1; + } + } + + Ok((i, backtrace_context)) + } + (Err(e), _) => Err(e), } - - Ok((i, backtrace_context)) } -type SymInitializeFn = - unsafe extern "system" fn(c::HANDLE, *mut c_void, - c::BOOL) -> c::BOOL; -type SymCleanupFn = - unsafe extern "system" fn(c::HANDLE) -> c::BOOL; +type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; +type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; + +type StackWalkExFn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME_EX, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, + c::DWORD, +) -> c::BOOL; + +type StackWalk64Fn = unsafe extern "system" fn( + c::DWORD, + c::HANDLE, + c::HANDLE, + *mut c::STACKFRAME64, + *mut c::CONTEXT, + *mut c_void, + *mut c_void, + *mut c_void, + *mut c_void, +) -> c::BOOL; -type StackWalkExFn = - unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE, - *mut c::STACKFRAME_EX, *mut c::CONTEXT, - *mut c_void, *mut c_void, - *mut c_void, *mut c_void, c::DWORD) -> c::BOOL; +#[cfg(target_arch = "x86")] +fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { + frame.AddrPC.Offset = ctx.Eip as u64; + frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrStack.Offset = ctx.Esp as u64; + frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrFrame.Offset = ctx.Ebp as u64; + frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 +} + +#[cfg(target_arch = "x86_64")] +fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { + frame.AddrPC.Offset = ctx.Rip as u64; + frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrStack.Offset = ctx.Rsp as u64; + frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + frame.AddrFrame.Offset = ctx.Rbp as u64; + frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 +} #[cfg(target_arch = "x86")] -fn init_frame(frame: &mut c::STACKFRAME_EX, - ctx: &c::CONTEXT) -> c::DWORD { +fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Eip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; frame.AddrStack.Offset = ctx.Esp as u64; @@ -129,8 +216,7 @@ fn init_frame(frame: &mut c::STACKFRAME_EX, } #[cfg(target_arch = "x86_64")] -fn init_frame(frame: &mut c::STACKFRAME_EX, - ctx: &c::CONTEXT) -> c::DWORD { +fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Rip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; frame.AddrStack.Offset = ctx.Rsp as u64; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 967df1c8a2d..e26d95a4f9d 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -10,88 +10,209 @@ use ffi::CStr; use io; -use libc::{c_ulong, c_char}; +use libc::{c_char, c_ulong}; use mem; -use sys::c; use sys::backtrace::BacktraceContext; +use sys::c; use sys_common::backtrace::Frame; type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, - *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; -type SymGetLineFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, - u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL; + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; +type SymFromInlineContextFn = + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; +type SymGetLineFromInlineContextFn = unsafe extern "system" fn( + c::HANDLE, + u64, + c::ULONG, + u64, + *mut c::DWORD, + *mut c::IMAGEHLP_LINE64, +) -> c::BOOL; + +type SymFromAddrFn = + unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; +type SymGetLineFromAddr64Fn = + unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; /// Converts a pointer to symbol to its string value. -pub fn resolve_symname(frame: Frame, - callback: F, - context: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> +pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, { - let SymFromInlineContext = sym!(&context.dbghelp, - "SymFromInlineContext", - SymFromInlineContextFn)?; + match ( + sym!( + &context.dbghelp, + "SymFromInlineContext", + SymFromInlineContextFn + ), + sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), + ) { + (Ok(SymFromInlineContext), _) => unsafe { + let mut info: c::SYMBOL_INFO = mem::zeroed(); + info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; + // the struct size in C. the value is different to + // `size_of::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; - unsafe { - let mut info: c::SYMBOL_INFO = mem::zeroed(); - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; + let mut displacement = 0u64; + let ret = SymFromInlineContext( + context.handle, + frame.symbol_addr as u64, + frame.inline_context, + &mut displacement, + &mut info, + ); + let valid_range = + if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { + if info.Size != 0 { + (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize + } else { + true + } + } else { + false + }; + let symname = if valid_range { + let ptr = info.Name.as_ptr() as *const c_char; + CStr::from_ptr(ptr).to_str().ok() + } else { + None + }; + callback(symname) +{ + match ( + sym!( + &context.dbghelp, + "SymFromInlineContext", + SymFromInlineContextFn + ), + sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), + ) { + (Ok(SymFromInlineContext), _) => unsafe { + let mut info: c::SYMBOL_INFO = mem::zeroed(); + info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; + // the struct size in C. the value is different to + // `size_of::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; - let mut displacement = 0u64; - let ret = SymFromInlineContext(context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut displacement, - &mut info); - let valid_range = if ret == c::TRUE && - frame.symbol_addr as usize >= info.Address as usize { - if info.Size != 0 { - (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize + let mut displacement = 0u64; + let ret = SymFromInlineContext( + context.handle, + frame.symbol_addr as u64, + frame.inline_context, + &mut displacement, + &mut info, + ); + let valid_range = + if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { + if info.Size != 0 { + (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize + } else { + true + } + } else { + false + }; + let symname = if valid_range { + let ptr = info.Name.as_ptr() as *const c_char; + CStr::from_ptr(ptr).to_str().ok() } else { - true - } - } else { - false - }; - let symname = if valid_range { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) + None + }; + callback(symname) + }, + (_, Ok(SymFromAddr)) => unsafe { + } else { + None + }; + callback(symname) + }, + (_, Ok(SymFromAddr)) => unsafe { + let mut info: c::SYMBOL_INFO = mem::zeroed(); + info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; + // the struct size in C. the value is different to + // `size_of::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; + + let mut displacement = 0u64; + let ret = SymFromAddr( + context.handle, + frame.symbol_addr as u64, + &mut displacement, + &mut info, + ); + + let symname = if ret == c::TRUE { + let ptr = info.Name.as_ptr() as *const c_char; + CStr::from_ptr(ptr).to_str().ok() + } else { + None + }; + callback(symname) + }, + (Err(e), _) => Err(e), } } -pub fn foreach_symbol_fileline(frame: Frame, - mut f: F, - context: &BacktraceContext) - -> io::Result - where F: FnMut(&[u8], u32) -> io::Result<()> +pub fn foreach_symbol_fileline( + frame: Frame, + mut f: F, + context: &BacktraceContext, +) -> io::Result +where + F: FnMut(&[u8], u32) -> io::Result<()>, { - let SymGetLineFromInlineContext = sym!(&context.dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn)?; + match ( + sym!( + &context.dbghelp, + "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn + ), + sym!( + &context.dbghelp, + "SymGetLineFromAddr64", + SymGetLineFromAddr64Fn + ), + ) { + (Ok(SymGetLineFromInlineContext), _) => unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; + let mut displacement = 0u32; + let ret = SymGetLineFromInlineContext( + context.handle, + frame.exact_position as u64, + frame.inline_context, + 0, + &mut displacement, + &mut line, + ); + if ret == c::TRUE { + let name = CStr::from_ptr(line.Filename).to_bytes(); + f(name, line.LineNumber as u32)?; + } + Ok(false) + }, + (_, Ok(SymGetLineFromAddr64)) => unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; - let mut displacement = 0u32; - let ret = SymGetLineFromInlineContext(context.handle, - frame.exact_position as u64, - frame.inline_context, - 0, - &mut displacement, - &mut line); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as u32)?; - } - Ok(false) + let mut displacement = 0u32; + let ret = SymGetLineFromAddr64( + context.handle, + frame.exact_position as u64, + &mut displacement, + &mut line, + ); + if ret == c::TRUE { + let name = CStr::from_ptr(line.Filename).to_bytes(); + f(name, line.LineNumber as u32)?; + } + Ok(false) + }, + (Err(e), _) => Err(e), } } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 6d929f21365..30aba2f400f 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -635,6 +635,22 @@ pub struct STACKFRAME_EX { pub InlineFrameContext: DWORD, } +#[repr(C)] +#[cfg(feature = "backtrace")] +pub struct STACKFRAME64 { + pub AddrPC: ADDRESS64, + pub AddrReturn: ADDRESS64, + pub AddrFrame: ADDRESS64, + pub AddrStack: ADDRESS64, + pub AddrBStore: ADDRESS64, + pub FuncTableEntry: *mut c_void, + pub Params: [u64; 4], + pub Far: BOOL, + pub Virtual: BOOL, + pub Reserved: [u64; 3], + pub KdHelp: KDHELP64, +} + #[repr(C)] #[cfg(feature = "backtrace")] pub struct KDHELP64 { -- cgit 1.4.1-3-g733a5 From 3245a475ab92b5ab77cf69e336279420c86a83eb Mon Sep 17 00:00:00 2001 From: moxian Date: Sun, 13 May 2018 04:38:43 +0000 Subject: Split separate stackwalk variants into their own functions .. rather than having them be one giant match statement. --- src/libstd/sys/windows/backtrace/mod.rs | 194 ++++++++++------- src/libstd/sys/windows/backtrace/printing/msvc.rs | 248 +++++++++++----------- 2 files changed, 238 insertions(+), 204 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 8e879e0f49e..884ec4e9fad 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -46,7 +46,7 @@ mod printing; #[path = "backtrace_gnu.rs"] pub mod gnu; -pub use self::printing::{resolve_symname, foreach_symbol_fileline}; +pub use self::printing::{foreach_symbol_fileline, resolve_symname}; pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; @@ -54,19 +54,30 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon // Fetch the symbols necessary from dbghelp.dll let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; + + // enum for holding the StackWalk function. Different from StackWalkVariant + // below, since there's no need to pass the function itself into + // the BacktraceContext + enum sw_fn_local { + SWExFn(StackWalkExFn), + SW64Fn(StackWalk64Fn), + } // StackWalkEx might not be present and we'll fall back to StackWalk64 - let ResStackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn); - let ResStackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn); + let (StackWalkFn, variant) = + sym!(dbghelp, "StackWalkEx", StackWalkExFn) + .map(|f| (sw_fn_local::SWExFn(f), StackWalkVariant::StackWalkEx)) + .or_else(|_| + sym!(dbghelp, "StackWalk64", StackWalk64Fn) + .map(|f| (sw_fn_local::SW64Fn(f), StackWalkVariant::StackWalk64)) + )?; // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; - let thread = unsafe { c::GetCurrentThread() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; let backtrace_context = BacktraceContext { handle: process, SymCleanup, + StackWalkVariant: variant, dbghelp, }; @@ -77,81 +88,102 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon } // And now that we're done with all the setup, do the stack walking! - match (ResStackWalkEx, ResStackWalk64) { - (Ok(StackWalkEx), _) => { - let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; - frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; - let image = init_frame_ex(&mut frame, &context); - - let mut i = 0; - unsafe { - while i < frames.len() - && StackWalkEx( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ) == c::TRUE - { - let addr = (frame.AddrPC.Offset - 1) as *const u8; - - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.InlineFrameContext, - }; - i += 1; - } - } + match StackWalkFn { + sw_fn_local::SWExFn(f) => set_frames_ex(f, frames, backtrace_context, process), + sw_fn_local::SW64Fn(f) => set_frames_64(f, frames, backtrace_context, process), + } +} - Ok((i, backtrace_context)) +fn set_frames_ex( + StackWalkEx: StackWalkExFn, + frames: &mut [Frame], + backtrace_context: BacktraceContext, + process: c::HANDLE, +) -> io::Result<(usize, BacktraceContext)> { + let thread = unsafe { c::GetCurrentProcess() }; + let mut context: c::CONTEXT = unsafe { mem::zeroed() }; + unsafe { c::RtlCaptureContext(&mut context) }; + + let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; + frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; + let image = init_frame_ex(&mut frame, &context); + + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalkEx( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) == c::TRUE + { + let addr = (frame.AddrPC.Offset - 1) as *const u8; + + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: frame.InlineFrameContext, + }; + i += 1; } - (_, Ok(StackWalk64)) => { - let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; - let image = init_frame_64(&mut frame, &context); - - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. - let mut i = 0; - unsafe { - while i < frames.len() - && StackWalk64( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) == c::TRUE - { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 - { - break; - } - - frames[i] = Frame { - symbol_addr: (addr - 1) as *const u8, - exact_position: (addr - 1) as *const u8, - inline_context: 0, - }; - i += 1; - } + } + + Ok((i, backtrace_context)) +} + +fn set_frames_64( + StackWalk64: StackWalk64Fn, + frames: &mut [Frame], + backtrace_context: BacktraceContext, + process: c::HANDLE, +) -> io::Result<(usize, BacktraceContext)> { + let thread = unsafe { c::GetCurrentProcess() }; + let mut context: c::CONTEXT = unsafe { mem::zeroed() }; + unsafe { c::RtlCaptureContext(&mut context) }; + + let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; + let image = init_frame_64(&mut frame, &context); + + // Start from -1 to avoid printing this stack frame, which will + // always be exactly the same. + let mut i = 0; + unsafe { + while i < frames.len() + && StackWalk64( + image, + process, + thread, + &mut frame, + &mut context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) == c::TRUE + { + let addr = frame.AddrPC.Offset; + if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 + { + break; } - Ok((i, backtrace_context)) + frames[i] = Frame { + symbol_addr: (addr - 1) as *const u8, + exact_position: (addr - 1) as *const u8, + inline_context: 0, + }; + i += 1; } - (Err(e), _) => Err(e), } + + Ok((i, backtrace_context)) } type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; @@ -226,16 +258,26 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { c::IMAGE_FILE_MACHINE_AMD64 } +enum StackWalkVariant { + StackWalkEx, + StackWalk64, +} + + pub struct BacktraceContext { handle: c::HANDLE, SymCleanup: SymCleanupFn, // Only used in printing for msvc and not gnu #[allow(dead_code)] + StackWalkVariant: StackWalkVariant, + #[allow(dead_code)] dbghelp: DynamicLibrary, } impl Drop for BacktraceContext { fn drop(&mut self) { - unsafe { (self.SymCleanup)(self.handle); } + unsafe { + (self.SymCleanup)(self.handle); + } } } diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index e26d95a4f9d..9d7accb7ad7 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -13,11 +13,10 @@ use io; use libc::{c_char, c_ulong}; use mem; use sys::backtrace::BacktraceContext; +use sys::backtrace::StackWalkVariant; use sys::c; use sys_common::backtrace::Frame; -type SymFromInlineContextFn = - unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; type SymFromInlineContextFn = unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; type SymGetLineFromInlineContextFn = unsafe extern "system" fn( @@ -39,57 +38,26 @@ pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) where F: FnOnce(Option<&str>) -> io::Result<()>, { - match ( - sym!( - &context.dbghelp, - "SymFromInlineContext", - SymFromInlineContextFn - ), - sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), - ) { - (Ok(SymFromInlineContext), _) => unsafe { - let mut info: c::SYMBOL_INFO = mem::zeroed(); - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; + match context.StackWalkVariant { + StackWalkVariant::StackWalkEx => { + let SymFromInlineContext = + sym!(&context.dbghelp, "SymFromInlineContext",SymFromInlineContextFn)?; + resolve_symname_from_inline_context(SymFromInlineContext, frame, callback, context) + }, + StackWalkVariant::StackWalk64 => { + let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?; + resolve_symname_from_addr(SymFromAddr, frame, callback, context) + } + } +} - let mut displacement = 0u64; - let ret = SymFromInlineContext( - context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut displacement, - &mut info, - ); - let valid_range = - if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { - if info.Size != 0 { - (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize - } else { - true - } - } else { - false - }; - let symname = if valid_range { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) +fn resolve_symname_from_inline_context( + SymFromInlineContext: SymFromInlineContextFn, + frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, { - match ( - sym!( - &context.dbghelp, - "SymFromInlineContext", - SymFromInlineContextFn - ), - sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn), - ) { - (Ok(SymFromInlineContext), _) => unsafe { + unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; // the struct size in C. the value is different to @@ -122,42 +90,69 @@ where None }; callback(symname) - }, - (_, Ok(SymFromAddr)) => unsafe { - } else { - None - }; - callback(symname) - }, - (_, Ok(SymFromAddr)) => unsafe { - let mut info: c::SYMBOL_INFO = mem::zeroed(); - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; + } +} - let mut displacement = 0u64; - let ret = SymFromAddr( - context.handle, - frame.symbol_addr as u64, - &mut displacement, - &mut info, - ); +fn resolve_symname_from_addr( + SymFromAddr: SymFromAddrFn, + frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +where + F: FnOnce(Option<&str>) -> io::Result<()>, +{ + unsafe { + let mut info: c::SYMBOL_INFO = mem::zeroed(); + info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; + // the struct size in C. the value is different to + // `size_of::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; - let symname = if ret == c::TRUE { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) - }, - (Err(e), _) => Err(e), + let mut displacement = 0u64; + let ret = SymFromAddr( + context.handle, + frame.symbol_addr as u64, + &mut displacement, + &mut info, + ); + + let symname = if ret == c::TRUE { + let ptr = info.Name.as_ptr() as *const c_char; + CStr::from_ptr(ptr).to_str().ok() + } else { + None + }; + callback(symname) } } pub fn foreach_symbol_fileline( + frame: Frame, + f: F, + context: &BacktraceContext, +) -> io::Result +where + F: FnMut(&[u8], u32) -> io::Result<()>, +{ + match context.StackWalkVariant { + StackWalkVariant::StackWalkEx => { + let SymGetLineFromInlineContext = + sym!(&context.dbghelp, "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn)?; + foreach_symbol_fileline_ex(SymGetLineFromInlineContext, + frame, f, context) + }, + StackWalkVariant::StackWalk64 => { + let SymGetLineFromAddr64 = + sym!(&context.dbghelp, "SymGetLineFromAddr64", + SymGetLineFromAddr64Fn)?; + foreach_symbol_fileline_64(SymGetLineFromAddr64, + frame, f, context) + } + } +} + +fn foreach_symbol_fileline_ex( + SymGetLineFromInlineContext: SymGetLineFromInlineContextFn, frame: Frame, mut f: F, context: &BacktraceContext, @@ -165,54 +160,51 @@ pub fn foreach_symbol_fileline( where F: FnMut(&[u8], u32) -> io::Result<()>, { - match ( - sym!( - &context.dbghelp, - "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn - ), - sym!( - &context.dbghelp, - "SymGetLineFromAddr64", - SymGetLineFromAddr64Fn - ), - ) { - (Ok(SymGetLineFromInlineContext), _) => unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; + unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; - let mut displacement = 0u32; - let ret = SymGetLineFromInlineContext( - context.handle, - frame.exact_position as u64, - frame.inline_context, - 0, - &mut displacement, - &mut line, - ); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as u32)?; - } - Ok(false) - }, - (_, Ok(SymGetLineFromAddr64)) => unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; + let mut displacement = 0u32; + let ret = SymGetLineFromInlineContext( + context.handle, + frame.exact_position as u64, + frame.inline_context, + 0, + &mut displacement, + &mut line, + ); + if ret == c::TRUE { + let name = CStr::from_ptr(line.Filename).to_bytes(); + f(name, line.LineNumber as u32)?; + } + Ok(false) + } +} - let mut displacement = 0u32; - let ret = SymGetLineFromAddr64( - context.handle, - frame.exact_position as u64, - &mut displacement, - &mut line, - ); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as u32)?; - } - Ok(false) - }, - (Err(e), _) => Err(e), +fn foreach_symbol_fileline_64( + SymGetLineFromAddr64: SymGetLineFromAddr64Fn, + frame: Frame, + mut f: F, + context: &BacktraceContext, +) -> io::Result +where + F: FnMut(&[u8], u32) -> io::Result<()>, +{ + unsafe { + let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); + line.SizeOfStruct = ::mem::size_of::() as u32; + + let mut displacement = 0u32; + let ret = SymGetLineFromAddr64( + context.handle, + frame.exact_position as u64, + &mut displacement, + &mut line, + ); + if ret == c::TRUE { + let name = CStr::from_ptr(line.Filename).to_bytes(); + f(name, line.LineNumber as u32)?; + } + Ok(false) } } -- cgit 1.4.1-3-g733a5 From c0b280f5f594fc6ff34ddcf35aa26cc46a073808 Mon Sep 17 00:00:00 2001 From: moxian Date: Sun, 13 May 2018 08:41:24 +0000 Subject: Load backtrace-related functions only once .. and pass them around in BacktraceContext. --- src/libstd/sys/windows/backtrace/mod.rs | 45 +++++++++-------- src/libstd/sys/windows/backtrace/printing/mod.rs | 14 ++++++ src/libstd/sys/windows/backtrace/printing/msvc.rs | 59 +++++++++++++++-------- 3 files changed, 77 insertions(+), 41 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 884ec4e9fad..23bb4ab6dfe 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -47,6 +47,7 @@ mod printing; pub mod gnu; pub use self::printing::{foreach_symbol_fileline, resolve_symname}; +use self::printing::{load_printing_fns_ex, load_printing_fns_64}; pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; @@ -55,21 +56,23 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - // enum for holding the StackWalk function. Different from StackWalkVariant - // below, since there's no need to pass the function itself into - // the BacktraceContext - enum sw_fn_local { - SWExFn(StackWalkExFn), - SW64Fn(StackWalk64Fn), - } + // StackWalkEx might not be present and we'll fall back to StackWalk64 - let (StackWalkFn, variant) = - sym!(dbghelp, "StackWalkEx", StackWalkExFn) - .map(|f| (sw_fn_local::SWExFn(f), StackWalkVariant::StackWalkEx)) - .or_else(|_| - sym!(dbghelp, "StackWalk64", StackWalk64Fn) - .map(|f| (sw_fn_local::SW64Fn(f), StackWalkVariant::StackWalk64)) - )?; + let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { + Ok(StackWalkEx) => + StackWalkVariant::StackWalkEx( + StackWalkEx, + load_printing_fns_ex(&dbghelp)?, + ), + Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) { + Ok(StackWalk64) => + StackWalkVariant::StackWalk64( + StackWalk64, + load_printing_fns_64(&dbghelp)?, + ), + Err(..) => return Err(e), + }, + }; // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; @@ -77,7 +80,7 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon let backtrace_context = BacktraceContext { handle: process, SymCleanup, - StackWalkVariant: variant, + StackWalkVariant: sw_var, dbghelp, }; @@ -88,9 +91,9 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon } // And now that we're done with all the setup, do the stack walking! - match StackWalkFn { - sw_fn_local::SWExFn(f) => set_frames_ex(f, frames, backtrace_context, process), - sw_fn_local::SW64Fn(f) => set_frames_64(f, frames, backtrace_context, process), + match backtrace_context.StackWalkVariant { + StackWalkVariant::StackWalkEx(f, _) => set_frames_ex(f, frames, backtrace_context, process), + StackWalkVariant::StackWalk64(f, _) => set_frames_64(f, frames, backtrace_context, process), } } @@ -259,8 +262,8 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { } enum StackWalkVariant { - StackWalkEx, - StackWalk64, + StackWalkEx(StackWalkExFn, printing::PrintingFnsEx), + StackWalk64(StackWalk64Fn, printing::PrintingFns64), } @@ -268,8 +271,10 @@ pub struct BacktraceContext { handle: c::HANDLE, SymCleanup: SymCleanupFn, // Only used in printing for msvc and not gnu + // The gnu version is effectively a ZST dummy. #[allow(dead_code)] StackWalkVariant: StackWalkVariant, + // keeping DynamycLibrary loaded until its functions no longer needed #[allow(dead_code)] dbghelp: DynamicLibrary, } diff --git a/src/libstd/sys/windows/backtrace/printing/mod.rs b/src/libstd/sys/windows/backtrace/printing/mod.rs index 3e566f6e2bd..251d5028aea 100644 --- a/src/libstd/sys/windows/backtrace/printing/mod.rs +++ b/src/libstd/sys/windows/backtrace/printing/mod.rs @@ -15,6 +15,20 @@ mod printing; #[cfg(target_env = "gnu")] mod printing { pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname}; + + // dummy functions to mirror those present in msvc version. + use sys::dynamic_lib::DynamicLibrary; + use io; + pub struct PrintingFnsEx {} + pub struct PrintingFns64 {} + pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result { + Ok(PrintingFnsEx{}) + } + pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result { + Ok(PrintingFns64{}) + } } pub use self::printing::{foreach_symbol_fileline, resolve_symname}; +pub use self::printing::{load_printing_fns_ex, load_printing_fns_64, + PrintingFnsEx, PrintingFns64}; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 9d7accb7ad7..9cfc2c3d352 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -15,8 +15,38 @@ use mem; use sys::backtrace::BacktraceContext; use sys::backtrace::StackWalkVariant; use sys::c; +use sys::dynamic_lib::DynamicLibrary; use sys_common::backtrace::Frame; + +// Structs holding printing functions and loaders for them +// Two versions depending on whether dbghelp.dll has StackWalkEx or not +// (the former being in newer Windows versions, the older being in Win7 and before) +pub struct PrintingFnsEx { + resolve_symname: SymFromInlineContextFn, + sym_get_line: SymGetLineFromInlineContextFn, +} +pub struct PrintingFns64 { + resolve_symname: SymFromAddrFn, + sym_get_line: SymGetLineFromAddr64Fn, +} + +pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result { + Ok(PrintingFnsEx{ + resolve_symname: sym!(dbghelp, "SymFromInlineContext", + SymFromInlineContextFn)?, + sym_get_line: sym!(dbghelp, "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn)?, + }) +} +pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result { + Ok(PrintingFns64{ + resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, + sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", + SymGetLineFromAddr64Fn)?, + }) +} + type SymFromInlineContextFn = unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; type SymGetLineFromInlineContextFn = unsafe extern "system" fn( @@ -39,14 +69,11 @@ where F: FnOnce(Option<&str>) -> io::Result<()>, { match context.StackWalkVariant { - StackWalkVariant::StackWalkEx => { - let SymFromInlineContext = - sym!(&context.dbghelp, "SymFromInlineContext",SymFromInlineContextFn)?; - resolve_symname_from_inline_context(SymFromInlineContext, frame, callback, context) + StackWalkVariant::StackWalkEx(_, ref fns) => { + resolve_symname_from_inline_context(fns.resolve_symname, frame, callback, context) }, - StackWalkVariant::StackWalk64 => { - let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?; - resolve_symname_from_addr(SymFromAddr, frame, callback, context) + StackWalkVariant::StackWalk64(_, ref fns) => { + resolve_symname_from_addr(fns.resolve_symname, frame, callback, context) } } } @@ -134,20 +161,10 @@ where F: FnMut(&[u8], u32) -> io::Result<()>, { match context.StackWalkVariant { - StackWalkVariant::StackWalkEx => { - let SymGetLineFromInlineContext = - sym!(&context.dbghelp, "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn)?; - foreach_symbol_fileline_ex(SymGetLineFromInlineContext, - frame, f, context) - }, - StackWalkVariant::StackWalk64 => { - let SymGetLineFromAddr64 = - sym!(&context.dbghelp, "SymGetLineFromAddr64", - SymGetLineFromAddr64Fn)?; - foreach_symbol_fileline_64(SymGetLineFromAddr64, - frame, f, context) - } + StackWalkVariant::StackWalkEx(_, ref fns) => + foreach_symbol_fileline_ex(fns.sym_get_line, frame, f, context), + StackWalkVariant::StackWalk64(_, ref fns) => + foreach_symbol_fileline_64(fns.sym_get_line, frame, f, context), } } -- cgit 1.4.1-3-g733a5 From a0b15012a17594566311ea490eda243b6bd9d92b Mon Sep 17 00:00:00 2001 From: moxian Date: Fri, 18 May 2018 11:38:50 +0000 Subject: Make stackwalking generic instead of matching on enum variants. --- src/libstd/sys/windows/backtrace/mod.rs | 280 +++++++++++++++++--------------- 1 file changed, 147 insertions(+), 133 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 23bb4ab6dfe..7ef4e203571 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -47,7 +47,7 @@ mod printing; pub mod gnu; pub use self::printing::{foreach_symbol_fileline, resolve_symname}; -use self::printing::{load_printing_fns_ex, load_printing_fns_64}; +use self::printing::{load_printing_fns_64, load_printing_fns_ex}; pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> { let dbghelp = DynamicLibrary::open("dbghelp.dll")?; @@ -56,20 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - // StackWalkEx might not be present and we'll fall back to StackWalk64 let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) { - Ok(StackWalkEx) => - StackWalkVariant::StackWalkEx( - StackWalkEx, - load_printing_fns_ex(&dbghelp)?, - ), + Ok(StackWalkEx) => { + StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?) + } Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) { - Ok(StackWalk64) => - StackWalkVariant::StackWalk64( - StackWalk64, - load_printing_fns_64(&dbghelp)?, - ), + Ok(StackWalk64) => { + StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?) + } Err(..) => return Err(e), }, }; @@ -92,101 +87,38 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon // And now that we're done with all the setup, do the stack walking! match backtrace_context.StackWalkVariant { - StackWalkVariant::StackWalkEx(f, _) => set_frames_ex(f, frames, backtrace_context, process), - StackWalkVariant::StackWalk64(f, _) => set_frames_64(f, frames, backtrace_context, process), - } -} - -fn set_frames_ex( - StackWalkEx: StackWalkExFn, - frames: &mut [Frame], - backtrace_context: BacktraceContext, - process: c::HANDLE, -) -> io::Result<(usize, BacktraceContext)> { - let thread = unsafe { c::GetCurrentProcess() }; - let mut context: c::CONTEXT = unsafe { mem::zeroed() }; - unsafe { c::RtlCaptureContext(&mut context) }; - - let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; - frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; - let image = init_frame_ex(&mut frame, &context); + StackWalkVariant::StackWalkEx(StackWalkEx, _) => { + set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context)) + } - let mut i = 0; - unsafe { - while i < frames.len() - && StackWalkEx( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - 0, - ) == c::TRUE - { - let addr = (frame.AddrPC.Offset - 1) as *const u8; - - frames[i] = Frame { - symbol_addr: addr, - exact_position: addr, - inline_context: frame.InlineFrameContext, - }; - i += 1; + StackWalkVariant::StackWalk64(StackWalk64, _) => { + set_frames(StackWalk64, frames).map(|i| (i, backtrace_context)) } } - - Ok((i, backtrace_context)) } -fn set_frames_64( - StackWalk64: StackWalk64Fn, - frames: &mut [Frame], - backtrace_context: BacktraceContext, - process: c::HANDLE, -) -> io::Result<(usize, BacktraceContext)> { +fn set_frames(StackWalk: W, frames: &mut [Frame]) -> io::Result { + let process = unsafe { c::GetCurrentProcess() }; let thread = unsafe { c::GetCurrentProcess() }; let mut context: c::CONTEXT = unsafe { mem::zeroed() }; unsafe { c::RtlCaptureContext(&mut context) }; + let mut frame = W::Item::new(); + let image = frame.init(&context); - let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; - let image = init_frame_64(&mut frame, &context); - - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. let mut i = 0; - unsafe { - while i < frames.len() - && StackWalk64( - image, - process, - thread, - &mut frame, - &mut context, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ) == c::TRUE - { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0 - { - break; - } - - frames[i] = Frame { - symbol_addr: (addr - 1) as *const u8, - exact_position: (addr - 1) as *const u8, - inline_context: 0, - }; - i += 1; - } + while i < frames.len() + && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE + { + let addr = frame.get_addr(); + frames[i] = Frame { + symbol_addr: addr, + exact_position: addr, + inline_context: 0, + }; + + i += 1 } - - Ok((i, backtrace_context)) + Ok(i) } type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; @@ -217,48 +149,131 @@ type StackWalk64Fn = unsafe extern "system" fn( *mut c_void, ) -> c::BOOL; -#[cfg(target_arch = "x86")] -fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Eip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Esp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Ebp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 +trait StackWalker { + type Item: StackFrame; + + fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL; } -#[cfg(target_arch = "x86_64")] -fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Rip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Rsp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Rbp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 +impl StackWalker for StackWalkExFn { + type Item = c::STACKFRAME_EX; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ) + } + } +} + +impl StackWalker for StackWalk64Fn { + type Item = c::STACKFRAME64; + fn walk( + &self, + image: c::DWORD, + process: c::HANDLE, + thread: c::HANDLE, + frame: &mut Self::Item, + context: &mut c::CONTEXT, + ) -> c::BOOL { + unsafe { + self( + image, + process, + thread, + frame, + context, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ) + } + } +} + +trait StackFrame { + fn new() -> Self; + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD; + fn get_addr(&self) -> *const u8; } -#[cfg(target_arch = "x86")] -fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Eip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Esp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Ebp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_I386 +impl StackFrame for c::STACKFRAME_EX { + fn new() -> c::STACKFRAME_EX { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } -#[cfg(target_arch = "x86_64")] -fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD { - frame.AddrPC.Offset = ctx.Rip as u64; - frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrStack.Offset = ctx.Rsp as u64; - frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; - frame.AddrFrame.Offset = ctx.Rbp as u64; - frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; - c::IMAGE_FILE_MACHINE_AMD64 +impl StackFrame for c::STACKFRAME64 { + fn new() -> c::STACKFRAME64 { + unsafe { mem::zeroed() } + } + + #[cfg(target_arch = "x86")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Eip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Esp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Ebp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_I386 + } + #[cfg(target_arch = "x86_64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Rip as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Rsp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Rbp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_AMD64 + } + + fn get_addr(&self) -> *const u8 { + (self.AddrPC.Offset - 1) as *const u8 + } } enum StackWalkVariant { @@ -266,7 +281,6 @@ enum StackWalkVariant { StackWalk64(StackWalk64Fn, printing::PrintingFns64), } - pub struct BacktraceContext { handle: c::HANDLE, SymCleanup: SymCleanupFn, -- cgit 1.4.1-3-g733a5 From 9d426ac387f2d42c998349c76ac1c2aea044e0ec Mon Sep 17 00:00:00 2001 From: moxian Date: Fri, 18 May 2018 12:33:23 +0000 Subject: Make msvc symbol extraction/printing functions generic. --- src/libstd/sys/windows/backtrace/printing/msvc.rs | 240 ++++++++++++---------- 1 file changed, 137 insertions(+), 103 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 9cfc2c3d352..d8f0a4d8208 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -18,7 +18,6 @@ use sys::c; use sys::dynamic_lib::DynamicLibrary; use sys_common::backtrace::Frame; - // Structs holding printing functions and loaders for them // Two versions depending on whether dbghelp.dll has StackWalkEx or not // (the former being in newer Windows versions, the older being in Win7 and before) @@ -32,23 +31,29 @@ pub struct PrintingFns64 { } pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFnsEx{ - resolve_symname: sym!(dbghelp, "SymFromInlineContext", - SymFromInlineContextFn)?, - sym_get_line: sym!(dbghelp, "SymGetLineFromInlineContext", - SymGetLineFromInlineContextFn)?, + Ok(PrintingFnsEx { + resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, + sym_get_line: sym!( + dbghelp, + "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn + )?, }) } pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result { - Ok(PrintingFns64{ + Ok(PrintingFns64 { resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, - sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", - SymGetLineFromAddr64Fn)?, + sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, }) } +type SymFromAddrFn = + unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; type SymFromInlineContextFn = unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; + +type SymGetLineFromAddr64Fn = + unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; type SymGetLineFromInlineContextFn = unsafe extern "system" fn( c::HANDLE, u64, @@ -58,11 +63,6 @@ type SymGetLineFromInlineContextFn = unsafe extern "system" fn( *mut c::IMAGEHLP_LINE64, ) -> c::BOOL; -type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; -type SymGetLineFromAddr64Fn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; - /// Converts a pointer to symbol to its string value. pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> where @@ -70,61 +70,23 @@ where { match context.StackWalkVariant { StackWalkVariant::StackWalkEx(_, ref fns) => { - resolve_symname_from_inline_context(fns.resolve_symname, frame, callback, context) - }, + resolve_symname_internal(fns.resolve_symname, frame, callback, context) + } StackWalkVariant::StackWalk64(_, ref fns) => { - resolve_symname_from_addr(fns.resolve_symname, frame, callback, context) + resolve_symname_internal(fns.resolve_symname, frame, callback, context) } } } -fn resolve_symname_from_inline_context( - SymFromInlineContext: SymFromInlineContextFn, - frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()>, -{ - unsafe { - let mut info: c::SYMBOL_INFO = mem::zeroed(); - info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; - // the struct size in C. the value is different to - // `size_of::() - MAX_SYM_NAME + 1` (== 81) - // due to struct alignment. - info.SizeOfStruct = 88; - - let mut displacement = 0u64; - let ret = SymFromInlineContext( - context.handle, - frame.symbol_addr as u64, - frame.inline_context, - &mut displacement, - &mut info, - ); - let valid_range = - if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { - if info.Size != 0 { - (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize - } else { - true - } - } else { - false - }; - let symname = if valid_range { - let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() - } else { - None - }; - callback(symname) - } -} - -fn resolve_symname_from_addr( - SymFromAddr: SymFromAddrFn, - frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> +fn resolve_symname_internal( + symbol_resolver: R, + frame: Frame, + callback: F, + context: &BacktraceContext, +) -> io::Result<()> where F: FnOnce(Option<&str>) -> io::Result<()>, + R: SymbolResolver, { unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); @@ -134,15 +96,22 @@ where // due to struct alignment. info.SizeOfStruct = 88; - let mut displacement = 0u64; - let ret = SymFromAddr( + let ret = symbol_resolver.resolve_symbol( context.handle, frame.symbol_addr as u64, - &mut displacement, + frame.inline_context, &mut info, ); - - let symname = if ret == c::TRUE { + let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { + if info.Size != 0 { + (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize + } else { + true + } + } else { + false + }; + let symname = if valid_range { let ptr = info.Name.as_ptr() as *const c_char; CStr::from_ptr(ptr).to_str().ok() } else { @@ -152,76 +121,141 @@ where } } +trait SymbolResolver { + fn resolve_symbol( + &self, + process: c::HANDLE, + symbol_address: u64, + inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO, + ) -> c::BOOL; +} + +impl SymbolResolver for SymFromAddrFn { + fn resolve_symbol( + &self, + process: c::HANDLE, + symbol_address: u64, + _inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO, + ) -> c::BOOL { + unsafe { + let mut displacement = 0u64; + self(process, symbol_address, &mut displacement, info) + } + } +} + +impl SymbolResolver for SymFromInlineContextFn { + fn resolve_symbol( + &self, + process: c::HANDLE, + symbol_address: u64, + inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO, + ) -> c::BOOL { + unsafe { + let mut displacement = 0u64; + self( + process, + symbol_address, + inline_context, + &mut displacement, + info, + ) + } + } +} + pub fn foreach_symbol_fileline( frame: Frame, - f: F, + callback: F, context: &BacktraceContext, ) -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()>, { match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => - foreach_symbol_fileline_ex(fns.sym_get_line, frame, f, context), - StackWalkVariant::StackWalk64(_, ref fns) => - foreach_symbol_fileline_64(fns.sym_get_line, frame, f, context), + StackWalkVariant::StackWalkEx(_, ref fns) => { + foreach_symbol_fileline_iternal(fns.sym_get_line, frame, callback, context) + } + StackWalkVariant::StackWalk64(_, ref fns) => { + foreach_symbol_fileline_iternal(fns.sym_get_line, frame, callback, context) + } } } -fn foreach_symbol_fileline_ex( - SymGetLineFromInlineContext: SymGetLineFromInlineContextFn, +fn foreach_symbol_fileline_iternal( + line_getter: G, frame: Frame, - mut f: F, + mut callback: F, context: &BacktraceContext, ) -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()>, + G: LineGetter, { unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::() as u32; - let mut displacement = 0u32; - let ret = SymGetLineFromInlineContext( + let ret = line_getter.get_line( context.handle, frame.exact_position as u64, frame.inline_context, - 0, - &mut displacement, &mut line, ); if ret == c::TRUE { let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as u32)?; + callback(name, line.LineNumber as u32)?; } Ok(false) } } -fn foreach_symbol_fileline_64( - SymGetLineFromAddr64: SymGetLineFromAddr64Fn, - frame: Frame, - mut f: F, - context: &BacktraceContext, -) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()>, -{ - unsafe { - let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); - line.SizeOfStruct = ::mem::size_of::() as u32; +trait LineGetter { + fn get_line( + &self, + process: c::HANDLE, + frame_address: u64, + inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64, + ) -> c::BOOL; +} - let mut displacement = 0u32; - let ret = SymGetLineFromAddr64( - context.handle, - frame.exact_position as u64, - &mut displacement, - &mut line, - ); - if ret == c::TRUE { - let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as u32)?; +impl LineGetter for SymGetLineFromAddr64Fn { + fn get_line( + &self, + process: c::HANDLE, + frame_address: u64, + _inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64, + ) -> c::BOOL { + unsafe { + let mut displacement = 0u32; + self(process, frame_address, &mut displacement, line) + } + } +} + +impl LineGetter for SymGetLineFromInlineContextFn { + fn get_line( + &self, + process: c::HANDLE, + frame_address: u64, + inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64, + ) -> c::BOOL { + unsafe { + let mut displacement = 0u32; + self( + process, + frame_address, + inline_context, + 0, + &mut displacement, + line, + ) } - Ok(false) } } -- cgit 1.4.1-3-g733a5 From be7f619870085121bdd7911aa882c35e70aedb8a Mon Sep 17 00:00:00 2001 From: moxian Date: Mon, 4 Jun 2018 11:00:12 +0000 Subject: Change traits to bare FnMut where possible. --- src/libstd/sys/windows/backtrace/printing/msvc.rs | 178 ++++++++-------------- 1 file changed, 67 insertions(+), 111 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index d8f0a4d8208..c8b946bf13a 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -69,24 +69,48 @@ where F: FnOnce(Option<&str>) -> io::Result<()>, { match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => { - resolve_symname_internal(fns.resolve_symname, frame, callback, context) - } - StackWalkVariant::StackWalk64(_, ref fns) => { - resolve_symname_internal(fns.resolve_symname, frame, callback, context) - } + StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)( + process, + symbol_address, + inline_context, + &mut displacement, + info, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( + |process: c::HANDLE, + symbol_address: u64, + _inline_context: c::ULONG, + info: *mut c::SYMBOL_INFO| unsafe { + let mut displacement = 0u64; + (fns.resolve_symname)(process, symbol_address, &mut displacement, info) + }, + frame, + callback, + context, + ), } } fn resolve_symname_internal( - symbol_resolver: R, + mut symbol_resolver: R, frame: Frame, callback: F, context: &BacktraceContext, ) -> io::Result<()> where F: FnOnce(Option<&str>) -> io::Result<()>, - R: SymbolResolver, + R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, { unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); @@ -96,7 +120,7 @@ where // due to struct alignment. info.SizeOfStruct = 88; - let ret = symbol_resolver.resolve_symbol( + let ret = symbol_resolver( context.handle, frame.symbol_addr as u64, frame.inline_context, @@ -121,52 +145,6 @@ where } } -trait SymbolResolver { - fn resolve_symbol( - &self, - process: c::HANDLE, - symbol_address: u64, - inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO, - ) -> c::BOOL; -} - -impl SymbolResolver for SymFromAddrFn { - fn resolve_symbol( - &self, - process: c::HANDLE, - symbol_address: u64, - _inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO, - ) -> c::BOOL { - unsafe { - let mut displacement = 0u64; - self(process, symbol_address, &mut displacement, info) - } - } -} - -impl SymbolResolver for SymFromInlineContextFn { - fn resolve_symbol( - &self, - process: c::HANDLE, - symbol_address: u64, - inline_context: c::ULONG, - info: *mut c::SYMBOL_INFO, - ) -> c::BOOL { - unsafe { - let mut displacement = 0u64; - self( - process, - symbol_address, - inline_context, - &mut displacement, - info, - ) - } - } -} - pub fn foreach_symbol_fileline( frame: Frame, callback: F, @@ -176,30 +154,55 @@ where F: FnMut(&[u8], u32) -> io::Result<()>, { match context.StackWalkVariant { - StackWalkVariant::StackWalkEx(_, ref fns) => { - foreach_symbol_fileline_iternal(fns.sym_get_line, frame, callback, context) - } - StackWalkVariant::StackWalk64(_, ref fns) => { - foreach_symbol_fileline_iternal(fns.sym_get_line, frame, callback, context) - } + StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)( + process, + frame_address, + inline_context, + 0, + &mut displacement, + line, + ) + }, + frame, + callback, + context, + ), + StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( + |process: c::HANDLE, + frame_address: u64, + _inline_context: c::ULONG, + line: *mut c::IMAGEHLP_LINE64| unsafe { + let mut displacement = 0u32; + (fns.sym_get_line)(process, frame_address, &mut displacement, line) + }, + frame, + callback, + context, + ), } } fn foreach_symbol_fileline_iternal( - line_getter: G, + mut line_getter: G, frame: Frame, mut callback: F, context: &BacktraceContext, ) -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()>, - G: LineGetter, + G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, { unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::() as u32; - let ret = line_getter.get_line( + let ret = line_getter( context.handle, frame.exact_position as u64, frame.inline_context, @@ -212,50 +215,3 @@ where Ok(false) } } - -trait LineGetter { - fn get_line( - &self, - process: c::HANDLE, - frame_address: u64, - inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64, - ) -> c::BOOL; -} - -impl LineGetter for SymGetLineFromAddr64Fn { - fn get_line( - &self, - process: c::HANDLE, - frame_address: u64, - _inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64, - ) -> c::BOOL { - unsafe { - let mut displacement = 0u32; - self(process, frame_address, &mut displacement, line) - } - } -} - -impl LineGetter for SymGetLineFromInlineContextFn { - fn get_line( - &self, - process: c::HANDLE, - frame_address: u64, - inline_context: c::ULONG, - line: *mut c::IMAGEHLP_LINE64, - ) -> c::BOOL { - unsafe { - let mut displacement = 0u32; - self( - process, - frame_address, - inline_context, - 0, - &mut displacement, - line, - ) - } - } -} -- cgit 1.4.1-3-g733a5 From d6cf1821bffbaa92f07481e24749ac84bce5bfdc Mon Sep 17 00:00:00 2001 From: Ixrec Date: Fri, 29 Jun 2018 03:12:02 +0100 Subject: Fix inconsequential typo in GlobalAlloc doc example --- src/libstd/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index f28e91e19b7..f6cecbea11f 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -61,7 +61,7 @@ //! ```rust,ignore (demonstrates crates.io usage) //! extern crate jemallocator; //! -//! use jemallacator::Jemalloc; +//! use jemallocator::Jemalloc; //! //! #[global_allocator] //! static GLOBAL: Jemalloc = Jemalloc; -- cgit 1.4.1-3-g733a5 From 02503029b83a295f1a03160472556fea491491f1 Mon Sep 17 00:00:00 2001 From: Gabriel Majeri Date: Tue, 29 May 2018 19:16:49 +0300 Subject: Implement PartialEq between &str and OsString Allows for example `os_string == "something"` --- src/libstd/ffi/os_str.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 0a3148029d0..1940a1da8a0 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -417,6 +417,20 @@ impl PartialEq for str { } } +#[stable(feature = "rust1", since = "1.28.0")] +impl<'a> PartialEq<&'a str> for OsString { + fn eq(&self, other: &&'a str) -> bool { + **self == **other + } +} + +#[stable(feature = "rust1", since = "1.28.0")] +impl<'a> PartialEq for &'a str { + fn eq(&self, other: &OsString) -> bool { + **other == **self + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Eq for OsString {} -- cgit 1.4.1-3-g733a5 From fdcee4da79a61028bc7d32a74648b913e924545a Mon Sep 17 00:00:00 2001 From: Gabriel Majeri Date: Wed, 30 May 2018 08:26:24 +0300 Subject: Fix stability attributes --- src/libstd/ffi/os_str.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 1940a1da8a0..4ada6a77a8e 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -417,14 +417,14 @@ impl PartialEq for str { } } -#[stable(feature = "rust1", since = "1.28.0")] +#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] impl<'a> PartialEq<&'a str> for OsString { fn eq(&self, other: &&'a str) -> bool { **self == **other } } -#[stable(feature = "rust1", since = "1.28.0")] +#[stable(feature = "os_str_str_ref_eq", since = "1.28.0")] impl<'a> PartialEq for &'a str { fn eq(&self, other: &OsString) -> bool { **other == **self -- cgit 1.4.1-3-g733a5 From 121b57b87ae4b58082f38a450373636286a8d678 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 15 Jun 2018 03:52:25 +0200 Subject: Move some alloc crate top-level items to a new alloc::collections module This matches std::collections --- src/liballoc/binary_heap.rs | 1196 ------------ src/liballoc/btree/map.rs | 2578 -------------------------- src/liballoc/btree/mod.rs | 23 - src/liballoc/btree/node.rs | 1622 ---------------- src/liballoc/btree/search.rs | 75 - src/liballoc/btree/set.rs | 1153 ------------ src/liballoc/collections/binary_heap.rs | 1196 ++++++++++++ src/liballoc/collections/btree/map.rs | 2578 ++++++++++++++++++++++++++ src/liballoc/collections/btree/mod.rs | 23 + src/liballoc/collections/btree/node.rs | 1622 ++++++++++++++++ src/liballoc/collections/btree/search.rs | 75 + src/liballoc/collections/btree/set.rs | 1153 ++++++++++++ src/liballoc/collections/linked_list.rs | 1486 +++++++++++++++ src/liballoc/collections/mod.rs | 59 + src/liballoc/collections/vec_deque.rs | 2970 ++++++++++++++++++++++++++++++ src/liballoc/lib.rs | 37 +- src/liballoc/linked_list.rs | 1486 --------------- src/liballoc/str.rs | 1 - src/liballoc/vec_deque.rs | 2970 ------------------------------ src/libstd/collections/mod.rs | 8 +- 20 files changed, 11167 insertions(+), 11144 deletions(-) delete mode 100644 src/liballoc/binary_heap.rs delete mode 100644 src/liballoc/btree/map.rs delete mode 100644 src/liballoc/btree/mod.rs delete mode 100644 src/liballoc/btree/node.rs delete mode 100644 src/liballoc/btree/search.rs delete mode 100644 src/liballoc/btree/set.rs create mode 100644 src/liballoc/collections/binary_heap.rs create mode 100644 src/liballoc/collections/btree/map.rs create mode 100644 src/liballoc/collections/btree/mod.rs create mode 100644 src/liballoc/collections/btree/node.rs create mode 100644 src/liballoc/collections/btree/search.rs create mode 100644 src/liballoc/collections/btree/set.rs create mode 100644 src/liballoc/collections/linked_list.rs create mode 100644 src/liballoc/collections/mod.rs create mode 100644 src/liballoc/collections/vec_deque.rs delete mode 100644 src/liballoc/linked_list.rs delete mode 100644 src/liballoc/vec_deque.rs (limited to 'src/libstd') diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs deleted file mode 100644 index fcadcb544c4..00000000000 --- a/src/liballoc/binary_heap.rs +++ /dev/null @@ -1,1196 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A priority queue implemented with a binary heap. -//! -//! Insertion and popping the largest element have `O(log n)` time complexity. -//! Checking the largest element is `O(1)`. Converting a vector to a binary heap -//! can be done in-place, and has `O(n)` complexity. A binary heap can also be -//! converted to a sorted vector in-place, allowing it to be used for an `O(n -//! log n)` in-place heapsort. -//! -//! # Examples -//! -//! This is a larger example that implements [Dijkstra's algorithm][dijkstra] -//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph]. -//! It shows how to use [`BinaryHeap`] with custom types. -//! -//! [dijkstra]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm -//! [sssp]: http://en.wikipedia.org/wiki/Shortest_path_problem -//! [dir_graph]: http://en.wikipedia.org/wiki/Directed_graph -//! [`BinaryHeap`]: struct.BinaryHeap.html -//! -//! ``` -//! use std::cmp::Ordering; -//! use std::collections::BinaryHeap; -//! use std::usize; -//! -//! #[derive(Copy, Clone, Eq, PartialEq)] -//! struct State { -//! cost: usize, -//! position: usize, -//! } -//! -//! // The priority queue depends on `Ord`. -//! // Explicitly implement the trait so the queue becomes a min-heap -//! // instead of a max-heap. -//! impl Ord for State { -//! fn cmp(&self, other: &State) -> Ordering { -//! // Notice that the we flip the ordering on costs. -//! // In case of a tie we compare positions - this step is necessary -//! // to make implementations of `PartialEq` and `Ord` consistent. -//! other.cost.cmp(&self.cost) -//! .then_with(|| self.position.cmp(&other.position)) -//! } -//! } -//! -//! // `PartialOrd` needs to be implemented as well. -//! impl PartialOrd for State { -//! fn partial_cmp(&self, other: &State) -> Option { -//! Some(self.cmp(other)) -//! } -//! } -//! -//! // Each node is represented as an `usize`, for a shorter implementation. -//! struct Edge { -//! node: usize, -//! cost: usize, -//! } -//! -//! // Dijkstra's shortest path algorithm. -//! -//! // Start at `start` and use `dist` to track the current shortest distance -//! // to each node. This implementation isn't memory-efficient as it may leave duplicate -//! // nodes in the queue. It also uses `usize::MAX` as a sentinel value, -//! // for a simpler implementation. -//! fn shortest_path(adj_list: &Vec>, start: usize, goal: usize) -> Option { -//! // dist[node] = current shortest distance from `start` to `node` -//! let mut dist: Vec<_> = (0..adj_list.len()).map(|_| usize::MAX).collect(); -//! -//! let mut heap = BinaryHeap::new(); -//! -//! // We're at `start`, with a zero cost -//! dist[start] = 0; -//! heap.push(State { cost: 0, position: start }); -//! -//! // Examine the frontier with lower cost nodes first (min-heap) -//! while let Some(State { cost, position }) = heap.pop() { -//! // Alternatively we could have continued to find all shortest paths -//! if position == goal { return Some(cost); } -//! -//! // Important as we may have already found a better way -//! if cost > dist[position] { continue; } -//! -//! // For each node we can reach, see if we can find a way with -//! // a lower cost going through this node -//! for edge in &adj_list[position] { -//! let next = State { cost: cost + edge.cost, position: edge.node }; -//! -//! // If so, add it to the frontier and continue -//! if next.cost < dist[next.position] { -//! heap.push(next); -//! // Relaxation, we have now found a better way -//! dist[next.position] = next.cost; -//! } -//! } -//! } -//! -//! // Goal not reachable -//! None -//! } -//! -//! fn main() { -//! // This is the directed graph we're going to use. -//! // The node numbers correspond to the different states, -//! // and the edge weights symbolize the cost of moving -//! // from one node to another. -//! // Note that the edges are one-way. -//! // -//! // 7 -//! // +-----------------+ -//! // | | -//! // v 1 2 | 2 -//! // 0 -----> 1 -----> 3 ---> 4 -//! // | ^ ^ ^ -//! // | | 1 | | -//! // | | | 3 | 1 -//! // +------> 2 -------+ | -//! // 10 | | -//! // +---------------+ -//! // -//! // The graph is represented as an adjacency list where each index, -//! // corresponding to a node value, has a list of outgoing edges. -//! // Chosen for its efficiency. -//! let graph = vec![ -//! // Node 0 -//! vec![Edge { node: 2, cost: 10 }, -//! Edge { node: 1, cost: 1 }], -//! // Node 1 -//! vec![Edge { node: 3, cost: 2 }], -//! // Node 2 -//! vec![Edge { node: 1, cost: 1 }, -//! Edge { node: 3, cost: 3 }, -//! Edge { node: 4, cost: 1 }], -//! // Node 3 -//! vec![Edge { node: 0, cost: 7 }, -//! Edge { node: 4, cost: 2 }], -//! // Node 4 -//! vec![]]; -//! -//! assert_eq!(shortest_path(&graph, 0, 1), Some(1)); -//! assert_eq!(shortest_path(&graph, 0, 3), Some(3)); -//! assert_eq!(shortest_path(&graph, 3, 0), Some(7)); -//! assert_eq!(shortest_path(&graph, 0, 4), Some(5)); -//! assert_eq!(shortest_path(&graph, 4, 0), None); -//! } -//! ``` - -#![allow(missing_docs)] -#![stable(feature = "rust1", since = "1.0.0")] - -use core::ops::{Deref, DerefMut}; -use core::iter::{FromIterator, FusedIterator}; -use core::mem::{swap, size_of, ManuallyDrop}; -use core::ptr; -use core::fmt; - -use slice; -use vec::{self, Vec}; - -use super::SpecExtend; - -/// A priority queue implemented with a binary heap. -/// -/// This will be a max-heap. -/// -/// It is a logic error for an item to be modified in such a way that the -/// item's ordering relative to any other item, as determined by the `Ord` -/// trait, changes while it is in the heap. This is normally only possible -/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. -/// -/// # Examples -/// -/// ``` -/// use std::collections::BinaryHeap; -/// -/// // Type inference lets us omit an explicit type signature (which -/// // would be `BinaryHeap` in this example). -/// let mut heap = BinaryHeap::new(); -/// -/// // We can use peek to look at the next item in the heap. In this case, -/// // there's no items in there yet so we get None. -/// assert_eq!(heap.peek(), None); -/// -/// // Let's add some scores... -/// heap.push(1); -/// heap.push(5); -/// heap.push(2); -/// -/// // Now peek shows the most important item in the heap. -/// assert_eq!(heap.peek(), Some(&5)); -/// -/// // We can check the length of a heap. -/// assert_eq!(heap.len(), 3); -/// -/// // We can iterate over the items in the heap, although they are returned in -/// // a random order. -/// for x in &heap { -/// println!("{}", x); -/// } -/// -/// // If we instead pop these scores, they should come back in order. -/// assert_eq!(heap.pop(), Some(5)); -/// assert_eq!(heap.pop(), Some(2)); -/// assert_eq!(heap.pop(), Some(1)); -/// assert_eq!(heap.pop(), None); -/// -/// // We can clear the heap of any remaining items. -/// heap.clear(); -/// -/// // The heap should now be empty. -/// assert!(heap.is_empty()) -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BinaryHeap { - data: Vec, -} - -/// Structure wrapping a mutable reference to the greatest item on a -/// `BinaryHeap`. -/// -/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See -/// its documentation for more. -/// -/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut -/// [`BinaryHeap`]: struct.BinaryHeap.html -#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -pub struct PeekMut<'a, T: 'a + Ord> { - heap: &'a mut BinaryHeap, - sift: bool, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: Ord + fmt::Debug> fmt::Debug for PeekMut<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("PeekMut") - .field(&self.heap.data[0]) - .finish() - } -} - -#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord> Drop for PeekMut<'a, T> { - fn drop(&mut self) { - if self.sift { - self.heap.sift_down(0); - } - } -} - -#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord> Deref for PeekMut<'a, T> { - type Target = T; - fn deref(&self) -> &T { - &self.heap.data[0] - } -} - -#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord> DerefMut for PeekMut<'a, T> { - fn deref_mut(&mut self) -> &mut T { - &mut self.heap.data[0] - } -} - -impl<'a, T: Ord> PeekMut<'a, T> { - /// Removes the peeked value from the heap and returns it. - #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")] - pub fn pop(mut this: PeekMut<'a, T>) -> T { - let value = this.heap.pop().unwrap(); - this.sift = false; - value - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for BinaryHeap { - fn clone(&self) -> Self { - BinaryHeap { data: self.data.clone() } - } - - fn clone_from(&mut self, source: &Self) { - self.data.clone_from(&source.data); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for BinaryHeap { - /// Creates an empty `BinaryHeap`. - #[inline] - fn default() -> BinaryHeap { - BinaryHeap::new() - } -} - -#[stable(feature = "binaryheap_debug", since = "1.4.0")] -impl fmt::Debug for BinaryHeap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -impl BinaryHeap { - /// Creates an empty `BinaryHeap` as a max-heap. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.push(4); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> BinaryHeap { - BinaryHeap { data: vec![] } - } - - /// Creates an empty `BinaryHeap` with a specific capacity. - /// This preallocates enough memory for `capacity` elements, - /// so that the `BinaryHeap` does not have to be reallocated - /// until it contains at least that many values. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::with_capacity(10); - /// heap.push(4); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize) -> BinaryHeap { - BinaryHeap { data: Vec::with_capacity(capacity) } - } - - /// Returns an iterator visiting all values in the underlying vector, in - /// arbitrary order. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); - /// - /// // Print 1, 2, 3, 4 in arbitrary order - /// for x in heap.iter() { - /// println!("{}", x); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { iter: self.data.iter() } - } - - /// Returns the greatest item in the binary heap, or `None` if it is empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// assert_eq!(heap.peek(), None); - /// - /// heap.push(1); - /// heap.push(5); - /// heap.push(2); - /// assert_eq!(heap.peek(), Some(&5)); - /// - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn peek(&self) -> Option<&T> { - self.data.get(0) - } - - /// Returns a mutable reference to the greatest item in the binary heap, or - /// `None` if it is empty. - /// - /// Note: If the `PeekMut` value is leaked, the heap may be in an - /// inconsistent state. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// assert!(heap.peek_mut().is_none()); - /// - /// heap.push(1); - /// heap.push(5); - /// heap.push(2); - /// { - /// let mut val = heap.peek_mut().unwrap(); - /// *val = 0; - /// } - /// assert_eq!(heap.peek(), Some(&2)); - /// ``` - #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] - pub fn peek_mut(&mut self) -> Option> { - if self.is_empty() { - None - } else { - Some(PeekMut { - heap: self, - sift: true, - }) - } - } - - /// Returns the number of elements the binary heap can hold without reallocating. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::with_capacity(100); - /// assert!(heap.capacity() >= 100); - /// heap.push(4); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { - self.data.capacity() - } - - /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the - /// given `BinaryHeap`. Does nothing if the capacity is already sufficient. - /// - /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future - /// insertions are expected. - /// - /// # Panics - /// - /// Panics if the new capacity overflows `usize`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.reserve_exact(100); - /// assert!(heap.capacity() >= 100); - /// heap.push(4); - /// ``` - /// - /// [`reserve`]: #method.reserve - #[stable(feature = "rust1", since = "1.0.0")] - pub fn reserve_exact(&mut self, additional: usize) { - self.data.reserve_exact(additional); - } - - /// Reserves capacity for at least `additional` more elements to be inserted in the - /// `BinaryHeap`. The collection may reserve more space to avoid frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new capacity overflows `usize`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.reserve(100); - /// assert!(heap.capacity() >= 100); - /// heap.push(4); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn reserve(&mut self, additional: usize) { - self.data.reserve(additional); - } - - /// Discards as much additional capacity as possible. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap: BinaryHeap = BinaryHeap::with_capacity(100); - /// - /// assert!(heap.capacity() >= 100); - /// heap.shrink_to_fit(); - /// assert!(heap.capacity() == 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn shrink_to_fit(&mut self) { - self.data.shrink_to_fit(); - } - - /// Discards capacity with a lower bound. - /// - /// The capacity will remain at least as large as both the length - /// and the supplied value. - /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. - /// - /// # Examples - /// - /// ``` - /// #![feature(shrink_to)] - /// use std::collections::BinaryHeap; - /// let mut heap: BinaryHeap = BinaryHeap::with_capacity(100); - /// - /// assert!(heap.capacity() >= 100); - /// heap.shrink_to(10); - /// assert!(heap.capacity() >= 10); - /// ``` - #[inline] - #[unstable(feature = "shrink_to", reason = "new API", issue="0")] - pub fn shrink_to(&mut self, min_capacity: usize) { - self.data.shrink_to(min_capacity) - } - - /// Removes the greatest item from the binary heap and returns it, or `None` if it - /// is empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from(vec![1, 3]); - /// - /// assert_eq!(heap.pop(), Some(3)); - /// assert_eq!(heap.pop(), Some(1)); - /// assert_eq!(heap.pop(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop(&mut self) -> Option { - self.data.pop().map(|mut item| { - if !self.is_empty() { - swap(&mut item, &mut self.data[0]); - self.sift_down_to_bottom(0); - } - item - }) - } - - /// Pushes an item onto the binary heap. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.push(3); - /// heap.push(5); - /// heap.push(1); - /// - /// assert_eq!(heap.len(), 3); - /// assert_eq!(heap.peek(), Some(&5)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn push(&mut self, item: T) { - let old_len = self.len(); - self.data.push(item); - self.sift_up(0, old_len); - } - - /// Consumes the `BinaryHeap` and returns the underlying vector - /// in arbitrary order. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]); - /// let vec = heap.into_vec(); - /// - /// // Will print in some order - /// for x in vec { - /// println!("{}", x); - /// } - /// ``` - #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] - pub fn into_vec(self) -> Vec { - self.into() - } - - /// Consumes the `BinaryHeap` and returns a vector in sorted - /// (ascending) order. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// - /// let mut heap = BinaryHeap::from(vec![1, 2, 4, 5, 7]); - /// heap.push(6); - /// heap.push(3); - /// - /// let vec = heap.into_sorted_vec(); - /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]); - /// ``` - #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] - pub fn into_sorted_vec(mut self) -> Vec { - let mut end = self.len(); - while end > 1 { - end -= 1; - self.data.swap(0, end); - self.sift_down_range(0, end); - } - self.into_vec() - } - - // The implementations of sift_up and sift_down use unsafe blocks in - // order to move an element out of the vector (leaving behind a - // hole), shift along the others and move the removed element back into the - // vector at the final location of the hole. - // The `Hole` type is used to represent this, and make sure - // the hole is filled back at the end of its scope, even on panic. - // Using a hole reduces the constant factor compared to using swaps, - // which involves twice as many moves. - fn sift_up(&mut self, start: usize, pos: usize) -> usize { - unsafe { - // Take out the value at `pos` and create a hole. - let mut hole = Hole::new(&mut self.data, pos); - - while hole.pos() > start { - let parent = (hole.pos() - 1) / 2; - if hole.element() <= hole.get(parent) { - break; - } - hole.move_to(parent); - } - hole.pos() - } - } - - /// Take an element at `pos` and move it down the heap, - /// while its children are larger. - fn sift_down_range(&mut self, pos: usize, end: usize) { - unsafe { - let mut hole = Hole::new(&mut self.data, pos); - let mut child = 2 * pos + 1; - while child < end { - let right = child + 1; - // compare with the greater of the two children - if right < end && !(hole.get(child) > hole.get(right)) { - child = right; - } - // if we are already in order, stop. - if hole.element() >= hole.get(child) { - break; - } - hole.move_to(child); - child = 2 * hole.pos() + 1; - } - } - } - - fn sift_down(&mut self, pos: usize) { - let len = self.len(); - self.sift_down_range(pos, len); - } - - /// Take an element at `pos` and move it all the way down the heap, - /// then sift it up to its position. - /// - /// Note: This is faster when the element is known to be large / should - /// be closer to the bottom. - fn sift_down_to_bottom(&mut self, mut pos: usize) { - let end = self.len(); - let start = pos; - unsafe { - let mut hole = Hole::new(&mut self.data, pos); - let mut child = 2 * pos + 1; - while child < end { - let right = child + 1; - // compare with the greater of the two children - if right < end && !(hole.get(child) > hole.get(right)) { - child = right; - } - hole.move_to(child); - child = 2 * hole.pos() + 1; - } - pos = hole.pos; - } - self.sift_up(start, pos); - } - - /// Returns the length of the binary heap. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 3]); - /// - /// assert_eq!(heap.len(), 2); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { - self.data.len() - } - - /// Checks if the binary heap is empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// - /// assert!(heap.is_empty()); - /// - /// heap.push(3); - /// heap.push(5); - /// heap.push(1); - /// - /// assert!(!heap.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Clears the binary heap, returning an iterator over the removed elements. - /// - /// The elements are removed in arbitrary order. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from(vec![1, 3]); - /// - /// assert!(!heap.is_empty()); - /// - /// for x in heap.drain() { - /// println!("{}", x); - /// } - /// - /// assert!(heap.is_empty()); - /// ``` - #[inline] - #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain { - Drain { iter: self.data.drain(..) } - } - - /// Drops all items from the binary heap. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::from(vec![1, 3]); - /// - /// assert!(!heap.is_empty()); - /// - /// heap.clear(); - /// - /// assert!(heap.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn clear(&mut self) { - self.drain(); - } - - fn rebuild(&mut self) { - let mut n = self.len() / 2; - while n > 0 { - n -= 1; - self.sift_down(n); - } - } - - /// Moves all the elements of `other` into `self`, leaving `other` empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// - /// let v = vec![-10, 1, 2, 3, 3]; - /// let mut a = BinaryHeap::from(v); - /// - /// let v = vec![-20, 5, 43]; - /// let mut b = BinaryHeap::from(v); - /// - /// a.append(&mut b); - /// - /// assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); - /// assert!(b.is_empty()); - /// ``` - #[stable(feature = "binary_heap_append", since = "1.11.0")] - pub fn append(&mut self, other: &mut Self) { - if self.len() < other.len() { - swap(self, other); - } - - if other.is_empty() { - return; - } - - #[inline(always)] - fn log2_fast(x: usize) -> usize { - 8 * size_of::() - (x.leading_zeros() as usize) - 1 - } - - // `rebuild` takes O(len1 + len2) operations - // and about 2 * (len1 + len2) comparisons in the worst case - // while `extend` takes O(len2 * log_2(len1)) operations - // and about 1 * len2 * log_2(len1) comparisons in the worst case, - // assuming len1 >= len2. - #[inline] - fn better_to_rebuild(len1: usize, len2: usize) -> bool { - 2 * (len1 + len2) < len2 * log2_fast(len1) - } - - if better_to_rebuild(self.len(), other.len()) { - self.data.append(&mut other.data); - self.rebuild(); - } else { - self.extend(other.drain()); - } - } -} - -/// Hole represents a hole in a slice i.e. an index without valid value -/// (because it was moved from or duplicated). -/// In drop, `Hole` will restore the slice by filling the hole -/// position with the value that was originally removed. -struct Hole<'a, T: 'a> { - data: &'a mut [T], - elt: ManuallyDrop, - pos: usize, -} - -impl<'a, T> Hole<'a, T> { - /// Create a new Hole at index `pos`. - /// - /// Unsafe because pos must be within the data slice. - #[inline] - unsafe fn new(data: &'a mut [T], pos: usize) -> Self { - debug_assert!(pos < data.len()); - let elt = ptr::read(&data[pos]); - Hole { - data, - elt: ManuallyDrop::new(elt), - pos, - } - } - - #[inline] - fn pos(&self) -> usize { - self.pos - } - - /// Returns a reference to the element removed. - #[inline] - fn element(&self) -> &T { - &self.elt - } - - /// Returns a reference to the element at `index`. - /// - /// Unsafe because index must be within the data slice and not equal to pos. - #[inline] - unsafe fn get(&self, index: usize) -> &T { - debug_assert!(index != self.pos); - debug_assert!(index < self.data.len()); - self.data.get_unchecked(index) - } - - /// Move hole to new location - /// - /// Unsafe because index must be within the data slice and not equal to pos. - #[inline] - unsafe fn move_to(&mut self, index: usize) { - debug_assert!(index != self.pos); - debug_assert!(index < self.data.len()); - let index_ptr: *const _ = self.data.get_unchecked(index); - let hole_ptr = self.data.get_unchecked_mut(self.pos); - ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); - self.pos = index; - } -} - -impl<'a, T> Drop for Hole<'a, T> { - #[inline] - fn drop(&mut self) { - // fill the hole again - unsafe { - let pos = self.pos; - ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1); - } - } -} - -/// An iterator over the elements of a `BinaryHeap`. -/// -/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its -/// documentation for more. -/// -/// [`iter`]: struct.BinaryHeap.html#method.iter -/// [`BinaryHeap`]: struct.BinaryHeap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - iter: slice::Iter<'a, T>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.iter.as_slice()) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Iter<'a, T> { - Iter { iter: self.iter.clone() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Iter<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a T> { - self.iter.next_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} - -/// An owning iterator over the elements of a `BinaryHeap`. -/// -/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter -/// [`BinaryHeap`]: struct.BinaryHeap.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct IntoIter { - iter: vec::IntoIter, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("IntoIter") - .field(&self.iter.as_slice()) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -/// A draining iterator over the elements of a `BinaryHeap`. -/// -/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its -/// documentation for more. -/// -/// [`drain`]: struct.BinaryHeap.html#method.drain -/// [`BinaryHeap`]: struct.BinaryHeap.html -#[stable(feature = "drain", since = "1.6.0")] -#[derive(Debug)] -pub struct Drain<'a, T: 'a> { - iter: vec::Drain<'a, T>, -} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> Iterator for Drain<'a, T> { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} - -#[stable(feature = "binary_heap_extras_15", since = "1.5.0")] -impl From> for BinaryHeap { - fn from(vec: Vec) -> BinaryHeap { - let mut heap = BinaryHeap { data: vec }; - heap.rebuild(); - heap - } -} - -#[stable(feature = "binary_heap_extras_15", since = "1.5.0")] -impl From> for Vec { - fn from(heap: BinaryHeap) -> Vec { - heap.data - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromIterator for BinaryHeap { - fn from_iter>(iter: I) -> BinaryHeap { - BinaryHeap::from(iter.into_iter().collect::>()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for BinaryHeap { - type Item = T; - type IntoIter = IntoIter; - - /// Creates a consuming iterator, that is, one that moves each value out of - /// the binary heap in arbitrary order. The binary heap cannot be used - /// after calling this. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); - /// - /// // Print 1, 2, 3, 4 in arbitrary order - /// for x in heap.into_iter() { - /// // x has type i32, not &i32 - /// println!("{}", x); - /// } - /// ``` - fn into_iter(self) -> IntoIter { - IntoIter { iter: self.data.into_iter() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a BinaryHeap - where T: Ord -{ - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Extend for BinaryHeap { - #[inline] - fn extend>(&mut self, iter: I) { - >::spec_extend(self, iter); - } -} - -impl> SpecExtend for BinaryHeap { - default fn spec_extend(&mut self, iter: I) { - self.extend_desugared(iter.into_iter()); - } -} - -impl SpecExtend> for BinaryHeap { - fn spec_extend(&mut self, ref mut other: BinaryHeap) { - self.append(other); - } -} - -impl BinaryHeap { - fn extend_desugared>(&mut self, iter: I) { - let iterator = iter.into_iter(); - let (lower, _) = iterator.size_hint(); - - self.reserve(lower); - - for elem in iterator { - self.push(elem); - } - } -} - -#[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs deleted file mode 100644 index e6e454446e2..00000000000 --- a/src/liballoc/btree/map.rs +++ /dev/null @@ -1,2578 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::cmp::Ordering; -use core::fmt::Debug; -use core::hash::{Hash, Hasher}; -use core::iter::{FromIterator, Peekable, FusedIterator}; -use core::marker::PhantomData; -use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::Index; -use core::ops::RangeBounds; -use core::{fmt, intrinsics, mem, ptr}; - -use borrow::Borrow; - -use super::node::{self, Handle, NodeRef, marker}; -use super::search; - -use super::node::InsertResult::*; -use super::node::ForceResult::*; -use super::search::SearchResult::*; -use self::UnderflowResult::*; -use self::Entry::*; - -/// A map based on a B-Tree. -/// -/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing -/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal -/// choice for a sorted map, as a perfectly balanced BST performs the theoretical minimum amount of -/// comparisons necessary to find an element (log2n). However, in practice the way this -/// is done is *very* inefficient for modern computer architectures. In particular, every element -/// is stored in its own individually heap-allocated node. This means that every single insertion -/// triggers a heap-allocation, and every single comparison should be a cache-miss. Since these -/// are both notably expensive things to do in practice, we are forced to at very least reconsider -/// the BST strategy. -/// -/// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing -/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in -/// searches. However, this does mean that searches will have to do *more* comparisons on average. -/// The precise number of comparisons depends on the node search strategy used. For optimal cache -/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search -/// the node using binary search. As a compromise, one could also perform a linear search -/// that initially only checks every ith element for some choice of i. -/// -/// Currently, our implementation simply performs naive linear search. This provides excellent -/// performance on *small* nodes of elements which are cheap to compare. However in the future we -/// would like to further explore choosing the optimal search strategy based on the choice of B, -/// and possibly other factors. Using linear search, searching for a random element is expected -/// to take O(B logBn) comparisons, which is generally worse than a BST. In practice, -/// however, performance is excellent. -/// -/// It is a logic error for a key to be modified in such a way that the key's ordering relative to -/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is -/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. -/// -/// [`Ord`]: ../../std/cmp/trait.Ord.html -/// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// -/// # Examples -/// -/// ``` -/// use std::collections::BTreeMap; -/// -/// // type inference lets us omit an explicit type signature (which -/// // would be `BTreeMap<&str, &str>` in this example). -/// let mut movie_reviews = BTreeMap::new(); -/// -/// // review some movies. -/// movie_reviews.insert("Office Space", "Deals with real issues in the workplace."); -/// movie_reviews.insert("Pulp Fiction", "Masterpiece."); -/// movie_reviews.insert("The Godfather", "Very enjoyable."); -/// movie_reviews.insert("The Blues Brothers", "Eye lyked it alot."); -/// -/// // check for a specific one. -/// if !movie_reviews.contains_key("Les Misérables") { -/// println!("We've got {} reviews, but Les Misérables ain't one.", -/// movie_reviews.len()); -/// } -/// -/// // oops, this review has a lot of spelling mistakes, let's delete it. -/// movie_reviews.remove("The Blues Brothers"); -/// -/// // look up the values associated with some keys. -/// let to_find = ["Up!", "Office Space"]; -/// for book in &to_find { -/// match movie_reviews.get(book) { -/// Some(review) => println!("{}: {}", book, review), -/// None => println!("{} is unreviewed.", book) -/// } -/// } -/// -/// // iterate over everything. -/// for (movie, review) in &movie_reviews { -/// println!("{}: \"{}\"", movie, review); -/// } -/// ``` -/// -/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows -/// for more complex methods of getting, setting, updating and removing keys and -/// their values: -/// -/// ``` -/// use std::collections::BTreeMap; -/// -/// // type inference lets us omit an explicit type signature (which -/// // would be `BTreeMap<&str, u8>` in this example). -/// let mut player_stats = BTreeMap::new(); -/// -/// fn random_stat_buff() -> u8 { -/// // could actually return some random value here - let's just return -/// // some fixed value for now -/// 42 -/// } -/// -/// // insert a key only if it doesn't already exist -/// player_stats.entry("health").or_insert(100); -/// -/// // insert a key using a function that provides a new value only if it -/// // doesn't already exist -/// player_stats.entry("defence").or_insert_with(random_stat_buff); -/// -/// // update a key, guarding against the key possibly not being set -/// let stat = player_stats.entry("attack").or_insert(100); -/// *stat += random_stat_buff(); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BTreeMap { - root: node::Root, - length: usize, -} - -#[stable(feature = "btree_drop", since = "1.7.0")] -unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap { - fn drop(&mut self) { - unsafe { - drop(ptr::read(self).into_iter()); - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for BTreeMap { - fn clone(&self) -> BTreeMap { - fn clone_subtree(node: node::NodeRef) - -> BTreeMap { - - match node.force() { - Leaf(leaf) => { - let mut out_tree = BTreeMap { - root: node::Root::new_leaf(), - length: 0, - }; - - { - let mut out_node = match out_tree.root.as_mut().force() { - Leaf(leaf) => leaf, - Internal(_) => unreachable!(), - }; - - let mut in_edge = leaf.first_edge(); - while let Ok(kv) = in_edge.right_kv() { - let (k, v) = kv.into_kv(); - in_edge = kv.right_edge(); - - out_node.push(k.clone(), v.clone()); - out_tree.length += 1; - } - } - - out_tree - } - Internal(internal) => { - let mut out_tree = clone_subtree(internal.first_edge().descend()); - - { - let mut out_node = out_tree.root.push_level(); - let mut in_edge = internal.first_edge(); - while let Ok(kv) = in_edge.right_kv() { - let (k, v) = kv.into_kv(); - in_edge = kv.right_edge(); - - let k = (*k).clone(); - let v = (*v).clone(); - let subtree = clone_subtree(in_edge.descend()); - - // We can't destructure subtree directly - // because BTreeMap implements Drop - let (subroot, sublength) = unsafe { - let root = ptr::read(&subtree.root); - let length = subtree.length; - mem::forget(subtree); - (root, length) - }; - - out_node.push(k, v, subroot); - out_tree.length += 1 + sublength; - } - } - - out_tree - } - } - } - - clone_subtree(self.root.as_ref()) - } -} - -impl super::Recover for BTreeMap - where K: Borrow + Ord, - Q: Ord -{ - type Key = K; - - fn get(&self, key: &Q) -> Option<&K> { - match search::search_tree(self.root.as_ref(), key) { - Found(handle) => Some(handle.into_kv().0), - GoDown(_) => None, - } - } - - fn take(&mut self, key: &Q) -> Option { - match search::search_tree(self.root.as_mut(), key) { - Found(handle) => { - Some(OccupiedEntry { - handle, - length: &mut self.length, - _marker: PhantomData, - } - .remove_kv() - .0) - } - GoDown(_) => None, - } - } - - fn replace(&mut self, key: K) -> Option { - self.ensure_root_is_owned(); - match search::search_tree::(self.root.as_mut(), &key) { - Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)), - GoDown(handle) => { - VacantEntry { - key, - handle, - length: &mut self.length, - _marker: PhantomData, - } - .insert(()); - None - } - } - } -} - -/// An iterator over the entries of a `BTreeMap`. -/// -/// This `struct` is created by the [`iter`] method on [`BTreeMap`]. See its -/// documentation for more. -/// -/// [`iter`]: struct.BTreeMap.html#method.iter -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, K: 'a, V: 'a> { - range: Range<'a, K, V>, - length: usize, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Iter<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A mutable iterator over the entries of a `BTreeMap`. -/// -/// This `struct` is created by the [`iter_mut`] method on [`BTreeMap`]. See its -/// documentation for more. -/// -/// [`iter_mut`]: struct.BTreeMap.html#method.iter_mut -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct IterMut<'a, K: 'a, V: 'a> { - range: RangeMut<'a, K, V>, - length: usize, -} - -/// An owning iterator over the entries of a `BTreeMap`. -/// -/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`into_iter`]: struct.BTreeMap.html#method.into_iter -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - front: Handle, marker::Edge>, - back: Handle, marker::Edge>, - length: usize, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let range = Range { - front: self.front.reborrow(), - back: self.back.reborrow(), - }; - f.debug_list().entries(range).finish() - } -} - -/// An iterator over the keys of a `BTreeMap`. -/// -/// This `struct` is created by the [`keys`] method on [`BTreeMap`]. See its -/// documentation for more. -/// -/// [`keys`]: struct.BTreeMap.html#method.keys -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Keys<'a, K: 'a, V: 'a> { - inner: Iter<'a, K, V>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a> fmt::Debug for Keys<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// An iterator over the values of a `BTreeMap`. -/// -/// This `struct` is created by the [`values`] method on [`BTreeMap`]. See its -/// documentation for more. -/// -/// [`values`]: struct.BTreeMap.html#method.values -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Values<'a, K: 'a, V: 'a> { - inner: Iter<'a, K, V>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a, V: 'a + fmt::Debug> fmt::Debug for Values<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A mutable iterator over the values of a `BTreeMap`. -/// -/// This `struct` is created by the [`values_mut`] method on [`BTreeMap`]. See its -/// documentation for more. -/// -/// [`values_mut`]: struct.BTreeMap.html#method.values_mut -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "map_values_mut", since = "1.10.0")] -#[derive(Debug)] -pub struct ValuesMut<'a, K: 'a, V: 'a> { - inner: IterMut<'a, K, V>, -} - -/// An iterator over a sub-range of entries in a `BTreeMap`. -/// -/// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its -/// documentation for more. -/// -/// [`range`]: struct.BTreeMap.html#method.range -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "btree_range", since = "1.17.0")] -pub struct Range<'a, K: 'a, V: 'a> { - front: Handle, K, V, marker::Leaf>, marker::Edge>, - back: Handle, K, V, marker::Leaf>, marker::Edge>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -/// A mutable iterator over a sub-range of entries in a `BTreeMap`. -/// -/// This `struct` is created by the [`range_mut`] method on [`BTreeMap`]. See its -/// documentation for more. -/// -/// [`range_mut`]: struct.BTreeMap.html#method.range_mut -/// [`BTreeMap`]: struct.BTreeMap.html -#[stable(feature = "btree_range", since = "1.17.0")] -pub struct RangeMut<'a, K: 'a, V: 'a> { - front: Handle, K, V, marker::Leaf>, marker::Edge>, - back: Handle, K, V, marker::Leaf>, marker::Edge>, - - // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for RangeMut<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let range = Range { - front: self.front.reborrow(), - back: self.back.reborrow(), - }; - f.debug_list().entries(range).finish() - } -} - -/// A view into a single entry in a map, which may either be vacant or occupied. -/// -/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. -/// -/// [`BTreeMap`]: struct.BTreeMap.html -/// [`entry`]: struct.BTreeMap.html#method.entry -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Entry<'a, K: 'a, V: 'a> { - /// A vacant entry. - #[stable(feature = "rust1", since = "1.0.0")] - Vacant(#[stable(feature = "rust1", since = "1.0.0")] - VacantEntry<'a, K, V>), - - /// An occupied entry. - #[stable(feature = "rust1", since = "1.0.0")] - Occupied(#[stable(feature = "rust1", since = "1.0.0")] - OccupiedEntry<'a, K, V>), -} - -#[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Vacant(ref v) => f.debug_tuple("Entry") - .field(v) - .finish(), - Occupied(ref o) => f.debug_tuple("Entry") - .field(o) - .finish(), - } - } -} - -/// A view into a vacant entry in a `BTreeMap`. -/// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { - key: K, - handle: Handle, K, V, marker::Leaf>, marker::Edge>, - length: &'a mut usize, - - // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, -} - -#[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("VacantEntry") - .field(self.key()) - .finish() - } -} - -/// A view into an occupied entry in a `BTreeMap`. -/// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, - - length: &'a mut usize, - - // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, -} - -#[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("OccupiedEntry") - .field("key", self.key()) - .field("value", self.get()) - .finish() - } -} - -// An iterator for merging two sorted sequences into one -struct MergeIter> { - left: Peekable, - right: Peekable, -} - -impl BTreeMap { - /// Makes a new empty BTreeMap with a reasonable choice for B. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// - /// // entries can now be inserted into the empty map - /// map.insert(1, "a"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> BTreeMap { - BTreeMap { - root: node::Root::shared_empty_root(), - length: 0, - } - } - - /// Clears the map, removing all values. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "a"); - /// a.clear(); - /// assert!(a.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn clear(&mut self) { - *self = BTreeMap::new(); - } - - /// Returns a reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but the ordering - /// on the borrowed form *must* match the ordering on the key type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get(&1), Some(&"a")); - /// assert_eq!(map.get(&2), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self, key: &Q) -> Option<&V> - where K: Borrow, - Q: Ord - { - match search::search_tree(self.root.as_ref(), key) { - Found(handle) => Some(handle.into_kv().1), - GoDown(_) => None, - } - } - - /// Returns the key-value pair corresponding to the supplied key. - /// - /// The supplied key may be any borrowed form of the map's key type, but the ordering - /// on the borrowed form *must* match the ordering on the key type. - /// - /// # Examples - /// - /// ``` - /// #![feature(map_get_key_value)] - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); - /// assert_eq!(map.get_key_value(&2), None); - /// ``` - #[unstable(feature = "map_get_key_value", issue = "49347")] - pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> - where K: Borrow, - Q: Ord - { - match search::search_tree(self.root.as_ref(), k) { - Found(handle) => Some(handle.into_kv()), - GoDown(_) => None, - } - } - - /// Returns `true` if the map contains a value for the specified key. - /// - /// The key may be any borrowed form of the map's key type, but the ordering - /// on the borrowed form *must* match the ordering on the key type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.contains_key(&1), true); - /// assert_eq!(map.contains_key(&2), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains_key(&self, key: &Q) -> bool - where K: Borrow, - Q: Ord - { - self.get(key).is_some() - } - - /// Returns a mutable reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but the ordering - /// on the borrowed form *must* match the ordering on the key type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// if let Some(x) = map.get_mut(&1) { - /// *x = "b"; - /// } - /// assert_eq!(map[&1], "b"); - /// ``` - // See `get` for implementation notes, this is basically a copy-paste with mut's added - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> - where K: Borrow, - Q: Ord - { - match search::search_tree(self.root.as_mut(), key) { - Found(handle) => Some(handle.into_kv_mut().1), - GoDown(_) => None, - } - } - - /// Inserts a key-value pair into the map. - /// - /// If the map did not have this key present, `None` is returned. - /// - /// If the map did have this key present, the value is updated, and the old - /// value is returned. The key is not updated, though; this matters for - /// types that can be `==` without being identical. See the [module-level - /// documentation] for more. - /// - /// [module-level documentation]: index.html#insert-and-complex-keys - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// assert_eq!(map.insert(37, "a"), None); - /// assert_eq!(map.is_empty(), false); - /// - /// map.insert(37, "b"); - /// assert_eq!(map.insert(37, "c"), Some("b")); - /// assert_eq!(map[&37], "c"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, key: K, value: V) -> Option { - match self.entry(key) { - Occupied(mut entry) => Some(entry.insert(value)), - Vacant(entry) => { - entry.insert(value); - None - } - } - } - - /// Removes a key from the map, returning the value at the key if the key - /// was previously in the map. - /// - /// The key may be any borrowed form of the map's key type, but the ordering - /// on the borrowed form *must* match the ordering on the key type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// assert_eq!(map.remove(&1), Some("a")); - /// assert_eq!(map.remove(&1), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, key: &Q) -> Option - where K: Borrow, - Q: Ord - { - match search::search_tree(self.root.as_mut(), key) { - Found(handle) => { - Some(OccupiedEntry { - handle, - length: &mut self.length, - _marker: PhantomData, - } - .remove()) - } - GoDown(_) => None, - } - } - - /// Moves all elements from `other` into `Self`, leaving `other` empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "a"); - /// a.insert(2, "b"); - /// a.insert(3, "c"); - /// - /// let mut b = BTreeMap::new(); - /// b.insert(3, "d"); - /// b.insert(4, "e"); - /// b.insert(5, "f"); - /// - /// a.append(&mut b); - /// - /// assert_eq!(a.len(), 5); - /// assert_eq!(b.len(), 0); - /// - /// assert_eq!(a[&1], "a"); - /// assert_eq!(a[&2], "b"); - /// assert_eq!(a[&3], "d"); - /// assert_eq!(a[&4], "e"); - /// assert_eq!(a[&5], "f"); - /// ``` - #[stable(feature = "btree_append", since = "1.11.0")] - pub fn append(&mut self, other: &mut Self) { - // Do we have to append anything at all? - if other.len() == 0 { - return; - } - - // We can just swap `self` and `other` if `self` is empty. - if self.len() == 0 { - mem::swap(self, other); - return; - } - - // First, we merge `self` and `other` into a sorted sequence in linear time. - let self_iter = mem::replace(self, BTreeMap::new()).into_iter(); - let other_iter = mem::replace(other, BTreeMap::new()).into_iter(); - let iter = MergeIter { - left: self_iter.peekable(), - right: other_iter.peekable(), - }; - - // Second, we build a tree from the sorted sequence in linear time. - self.from_sorted_iter(iter); - self.fix_right_edge(); - } - - /// Constructs a double-ended iterator over a sub-range of elements in the map. - /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will - /// yield elements from min (inclusive) to max (exclusive). - /// The range may also be entered as `(Bound, Bound)`, so for example - /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive - /// range from 4 to 10. - /// - /// # Panics - /// - /// Panics if range `start > end`. - /// Panics if range `start == end` and both bounds are `Excluded`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::ops::Bound::Included; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(3, "a"); - /// map.insert(5, "b"); - /// map.insert(8, "c"); - /// for (&key, &value) in map.range((Included(&4), Included(&8))) { - /// println!("{}: {}", key, value); - /// } - /// assert_eq!(Some((&5, &"b")), map.range(4..).next()); - /// ``` - #[stable(feature = "btree_range", since = "1.17.0")] - pub fn range(&self, range: R) -> Range - where T: Ord, K: Borrow, R: RangeBounds - { - let root1 = self.root.as_ref(); - let root2 = self.root.as_ref(); - let (f, b) = range_search(root1, root2, range); - - Range { front: f, back: b} - } - - /// Constructs a mutable double-ended iterator over a sub-range of elements in the map. - /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will - /// yield elements from min (inclusive) to max (exclusive). - /// The range may also be entered as `(Bound, Bound)`, so for example - /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive - /// range from 4 to 10. - /// - /// # Panics - /// - /// Panics if range `start > end`. - /// Panics if range `start == end` and both bounds are `Excluded`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"].iter() - /// .map(|&s| (s, 0)) - /// .collect(); - /// for (_, balance) in map.range_mut("B".."Cheryl") { - /// *balance += 100; - /// } - /// for (name, balance) in &map { - /// println!("{} => {}", name, balance); - /// } - /// ``` - #[stable(feature = "btree_range", since = "1.17.0")] - pub fn range_mut(&mut self, range: R) -> RangeMut - where T: Ord, K: Borrow, R: RangeBounds - { - let root1 = self.root.as_mut(); - let root2 = unsafe { ptr::read(&root1) }; - let (f, b) = range_search(root1, root2, range); - - RangeMut { - front: f, - back: b, - _marker: PhantomData, - } - } - - /// Gets the given key's corresponding entry in the map for in-place manipulation. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// // count the number of occurrences of letters in the vec - /// for x in vec!["a","b","a","c","a","b"] { - /// *count.entry(x).or_insert(0) += 1; - /// } - /// - /// assert_eq!(count["a"], 3); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry { - // FIXME(@porglezomp) Avoid allocating if we don't insert - self.ensure_root_is_owned(); - match search::search_tree(self.root.as_mut(), &key) { - Found(handle) => { - Occupied(OccupiedEntry { - handle, - length: &mut self.length, - _marker: PhantomData, - }) - } - GoDown(handle) => { - Vacant(VacantEntry { - key, - handle, - length: &mut self.length, - _marker: PhantomData, - }) - } - } - } - - fn from_sorted_iter>(&mut self, iter: I) { - self.ensure_root_is_owned(); - let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node(); - // Iterate through all key-value pairs, pushing them into nodes at the right level. - for (key, value) in iter { - // Try to push key-value pair into the current leaf node. - if cur_node.len() < node::CAPACITY { - cur_node.push(key, value); - } else { - // No space left, go up and push there. - let mut open_node; - let mut test_node = cur_node.forget_type(); - loop { - match test_node.ascend() { - Ok(parent) => { - let parent = parent.into_node(); - if parent.len() < node::CAPACITY { - // Found a node with space left, push here. - open_node = parent; - break; - } else { - // Go up again. - test_node = parent.forget_type(); - } - } - Err(node) => { - // We are at the top, create a new root node and push there. - open_node = node.into_root_mut().push_level(); - break; - } - } - } - - // Push key-value pair and new right subtree. - let tree_height = open_node.height() - 1; - let mut right_tree = node::Root::new_leaf(); - for _ in 0..tree_height { - right_tree.push_level(); - } - open_node.push(key, value, right_tree); - - // Go down to the right-most leaf again. - cur_node = last_leaf_edge(open_node.forget_type()).into_node(); - } - - self.length += 1; - } - } - - fn fix_right_edge(&mut self) { - // Handle underfull nodes, start from the top. - let mut cur_node = self.root.as_mut(); - while let Internal(internal) = cur_node.force() { - // Check if right-most child is underfull. - let mut last_edge = internal.last_edge(); - let right_child_len = last_edge.reborrow().descend().len(); - if right_child_len < node::MIN_LEN { - // We need to steal. - let mut last_kv = match last_edge.left_kv() { - Ok(left) => left, - Err(_) => unreachable!(), - }; - last_kv.bulk_steal_left(node::MIN_LEN - right_child_len); - last_edge = last_kv.right_edge(); - } - - // Go further down. - cur_node = last_edge.descend(); - } - } - - /// Splits the collection into two at the given key. Returns everything after the given key, - /// including the key. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "a"); - /// a.insert(2, "b"); - /// a.insert(3, "c"); - /// a.insert(17, "d"); - /// a.insert(41, "e"); - /// - /// let b = a.split_off(&3); - /// - /// assert_eq!(a.len(), 2); - /// assert_eq!(b.len(), 3); - /// - /// assert_eq!(a[&1], "a"); - /// assert_eq!(a[&2], "b"); - /// - /// assert_eq!(b[&3], "c"); - /// assert_eq!(b[&17], "d"); - /// assert_eq!(b[&41], "e"); - /// ``` - #[stable(feature = "btree_split_off", since = "1.11.0")] - pub fn split_off(&mut self, key: &Q) -> Self - where K: Borrow - { - if self.is_empty() { - return Self::new(); - } - - let total_num = self.len(); - - let mut right = Self::new(); - right.root = node::Root::new_leaf(); - for _ in 0..(self.root.as_ref().height()) { - right.root.push_level(); - } - - { - let mut left_node = self.root.as_mut(); - let mut right_node = right.root.as_mut(); - - loop { - let mut split_edge = match search::search_node(left_node, key) { - // key is going to the right tree - Found(handle) => handle.left_edge(), - GoDown(handle) => handle, - }; - - split_edge.move_suffix(&mut right_node); - - match (split_edge.force(), right_node.force()) { - (Internal(edge), Internal(node)) => { - left_node = edge.descend(); - right_node = node.first_edge().descend(); - } - (Leaf(_), Leaf(_)) => { - break; - } - _ => { - unreachable!(); - } - } - } - } - - self.fix_right_border(); - right.fix_left_border(); - - if self.root.as_ref().height() < right.root.as_ref().height() { - self.recalc_length(); - right.length = total_num - self.len(); - } else { - right.recalc_length(); - self.length = total_num - right.len(); - } - - right - } - - /// Calculates the number of elements if it is incorrect. - fn recalc_length(&mut self) { - fn dfs(node: NodeRef) -> usize { - let mut res = node.len(); - - if let Internal(node) = node.force() { - let mut edge = node.first_edge(); - loop { - res += dfs(edge.reborrow().descend()); - match edge.right_kv() { - Ok(right_kv) => { - edge = right_kv.right_edge(); - } - Err(_) => { - break; - } - } - } - } - - res - } - - self.length = dfs(self.root.as_ref()); - } - - /// Removes empty levels on the top. - fn fix_top(&mut self) { - loop { - { - let node = self.root.as_ref(); - if node.height() == 0 || node.len() > 0 { - break; - } - } - self.root.pop_level(); - } - } - - fn fix_right_border(&mut self) { - self.fix_top(); - - { - let mut cur_node = self.root.as_mut(); - - while let Internal(node) = cur_node.force() { - let mut last_kv = node.last_kv(); - - if last_kv.can_merge() { - cur_node = last_kv.merge().descend(); - } else { - let right_len = last_kv.reborrow().right_edge().descend().len(); - // `MINLEN + 1` to avoid readjust if merge happens on the next level. - if right_len < node::MIN_LEN + 1 { - last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len); - } - cur_node = last_kv.right_edge().descend(); - } - } - } - - self.fix_top(); - } - - /// The symmetric clone of `fix_right_border`. - fn fix_left_border(&mut self) { - self.fix_top(); - - { - let mut cur_node = self.root.as_mut(); - - while let Internal(node) = cur_node.force() { - let mut first_kv = node.first_kv(); - - if first_kv.can_merge() { - cur_node = first_kv.merge().descend(); - } else { - let left_len = first_kv.reborrow().left_edge().descend().len(); - if left_len < node::MIN_LEN + 1 { - first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len); - } - cur_node = first_kv.left_edge().descend(); - } - } - } - - self.fix_top(); - } - - /// If the root node is the shared root node, allocate our own node. - fn ensure_root_is_owned(&mut self) { - if self.root.is_shared_root() { - self.root = node::Root::new_leaf(); - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap { - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - fn next(&mut self) -> Option<(&'a K, &'a V)> { - if self.length == 0 { - None - } else { - self.length -= 1; - unsafe { Some(self.range.next_unchecked()) } - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.length, Some(self.length)) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { - fn next_back(&mut self) -> Option<(&'a K, &'a V)> { - if self.length == 0 { - None - } else { - self.length -= 1; - unsafe { Some(self.range.next_back_unchecked()) } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> { - fn len(&self) -> usize { - self.length - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Iter<'a, K, V> { - fn clone(&self) -> Iter<'a, K, V> { - Iter { - range: self.range.clone(), - length: self.length, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap { - type Item = (&'a K, &'a mut V); - type IntoIter = IterMut<'a, K, V>; - - fn into_iter(self) -> IterMut<'a, K, V> { - self.iter_mut() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { - type Item = (&'a K, &'a mut V); - - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.length == 0 { - None - } else { - self.length -= 1; - unsafe { Some(self.range.next_unchecked()) } - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.length, Some(self.length)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> { - fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.length == 0 { - None - } else { - self.length -= 1; - unsafe { Some(self.range.next_back_unchecked()) } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { - fn len(&self) -> usize { - self.length - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for BTreeMap { - type Item = (K, V); - type IntoIter = IntoIter; - - fn into_iter(self) -> IntoIter { - let root1 = unsafe { ptr::read(&self.root).into_ref() }; - let root2 = unsafe { ptr::read(&self.root).into_ref() }; - let len = self.length; - mem::forget(self); - - IntoIter { - front: first_leaf_edge(root1), - back: last_leaf_edge(root2), - length: len, - } - } -} - -#[stable(feature = "btree_drop", since = "1.7.0")] -impl Drop for IntoIter { - fn drop(&mut self) { - self.for_each(drop); - unsafe { - let leaf_node = ptr::read(&self.front).into_node(); - if leaf_node.is_shared_root() { - return; - } - - if let Some(first_parent) = leaf_node.deallocate_and_ascend() { - let mut cur_node = first_parent.into_node(); - while let Some(parent) = cur_node.deallocate_and_ascend() { - cur_node = parent.into_node() - } - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = (K, V); - - fn next(&mut self) -> Option<(K, V)> { - if self.length == 0 { - return None; - } else { - self.length -= 1; - } - - let handle = unsafe { ptr::read(&self.front) }; - - let mut cur_handle = match handle.right_kv() { - Ok(kv) => { - let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; - let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; - self.front = kv.right_edge(); - return Some((k, v)); - } - Err(last_edge) => unsafe { - unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()) - }, - }; - - loop { - match cur_handle.right_kv() { - Ok(kv) => { - let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; - let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; - self.front = first_leaf_edge(kv.right_edge().descend()); - return Some((k, v)); - } - Err(last_edge) => unsafe { - cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()); - }, - } - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.length, Some(self.length)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { - fn next_back(&mut self) -> Option<(K, V)> { - if self.length == 0 { - return None; - } else { - self.length -= 1; - } - - let handle = unsafe { ptr::read(&self.back) }; - - let mut cur_handle = match handle.left_kv() { - Ok(kv) => { - let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; - let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; - self.back = kv.left_edge(); - return Some((k, v)); - } - Err(last_edge) => unsafe { - unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()) - }, - }; - - loop { - match cur_handle.left_kv() { - Ok(kv) => { - let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; - let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; - self.back = last_leaf_edge(kv.left_edge().descend()); - return Some((k, v)); - } - Err(last_edge) => unsafe { - cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()); - }, - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { - self.length - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Iterator for Keys<'a, K, V> { - type Item = &'a K; - - fn next(&mut self) -> Option<&'a K> { - self.inner.next().map(|(k, _)| k) - } - - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> { - fn next_back(&mut self) -> Option<&'a K> { - self.inner.next_back().map(|(k, _)| k) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { - fn len(&self) -> usize { - self.inner.len() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Keys<'a, K, V> { - fn clone(&self) -> Keys<'a, K, V> { - Keys { inner: self.inner.clone() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Iterator for Values<'a, K, V> { - type Item = &'a V; - - fn next(&mut self) -> Option<&'a V> { - self.inner.next().map(|(_, v)| v) - } - - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { - fn next_back(&mut self) -> Option<&'a V> { - self.inner.next_back().map(|(_, v)| v) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { - fn len(&self) -> usize { - self.inner.len() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Values<'a, K, V> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Values<'a, K, V> { - fn clone(&self) -> Values<'a, K, V> { - Values { inner: self.inner.clone() } - } -} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, K, V> Iterator for Range<'a, K, V> { - type Item = (&'a K, &'a V); - - fn next(&mut self) -> Option<(&'a K, &'a V)> { - if self.front == self.back { - None - } else { - unsafe { Some(self.next_unchecked()) } - } - } -} - -#[stable(feature = "map_values_mut", since = "1.10.0")] -impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { - type Item = &'a mut V; - - fn next(&mut self) -> Option<&'a mut V> { - self.inner.next().map(|(_, v)| v) - } - - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "map_values_mut", since = "1.10.0")] -impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> { - fn next_back(&mut self) -> Option<&'a mut V> { - self.inner.next_back().map(|(_, v)| v) - } -} - -#[stable(feature = "map_values_mut", since = "1.10.0")] -impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { - fn len(&self) -> usize { - self.inner.len() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} - - -impl<'a, K, V> Range<'a, K, V> { - unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { - let handle = self.front; - - let mut cur_handle = match handle.right_kv() { - Ok(kv) => { - let ret = kv.into_kv(); - self.front = kv.right_edge(); - return ret; - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - unwrap_unchecked(next_level) - } - }; - - loop { - match cur_handle.right_kv() { - Ok(kv) => { - let ret = kv.into_kv(); - self.front = first_leaf_edge(kv.right_edge().descend()); - return ret; - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - cur_handle = unwrap_unchecked(next_level); - } - } - } - } -} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { - fn next_back(&mut self) -> Option<(&'a K, &'a V)> { - if self.front == self.back { - None - } else { - unsafe { Some(self.next_back_unchecked()) } - } - } -} - -impl<'a, K, V> Range<'a, K, V> { - unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { - let handle = self.back; - - let mut cur_handle = match handle.left_kv() { - Ok(kv) => { - let ret = kv.into_kv(); - self.back = kv.left_edge(); - return ret; - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - unwrap_unchecked(next_level) - } - }; - - loop { - match cur_handle.left_kv() { - Ok(kv) => { - let ret = kv.into_kv(); - self.back = last_leaf_edge(kv.left_edge().descend()); - return ret; - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - cur_handle = unwrap_unchecked(next_level); - } - } - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Range<'a, K, V> {} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, K, V> Clone for Range<'a, K, V> { - fn clone(&self) -> Range<'a, K, V> { - Range { - front: self.front, - back: self.back, - } - } -} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, K, V> Iterator for RangeMut<'a, K, V> { - type Item = (&'a K, &'a mut V); - - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.front == self.back { - None - } else { - unsafe { Some(self.next_unchecked()) } - } - } -} - -impl<'a, K, V> RangeMut<'a, K, V> { - unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { - let handle = ptr::read(&self.front); - - let mut cur_handle = match handle.right_kv() { - Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.front = kv.right_edge(); - return (k, v); - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - unwrap_unchecked(next_level) - } - }; - - loop { - match cur_handle.right_kv() { - Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.front = first_leaf_edge(kv.right_edge().descend()); - return (k, v); - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - cur_handle = unwrap_unchecked(next_level); - } - } - } - } -} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { - fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.front == self.back { - None - } else { - unsafe { Some(self.next_back_unchecked()) } - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} - -impl<'a, K, V> RangeMut<'a, K, V> { - unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { - let handle = ptr::read(&self.back); - - let mut cur_handle = match handle.left_kv() { - Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.back = kv.left_edge(); - return (k, v); - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - unwrap_unchecked(next_level) - } - }; - - loop { - match cur_handle.left_kv() { - Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.back = last_leaf_edge(kv.left_edge().descend()); - return (k, v); - } - Err(last_edge) => { - let next_level = last_edge.into_node().ascend().ok(); - cur_handle = unwrap_unchecked(next_level); - } - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromIterator<(K, V)> for BTreeMap { - fn from_iter>(iter: T) -> BTreeMap { - let mut map = BTreeMap::new(); - map.extend(iter); - map - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Extend<(K, V)> for BTreeMap { - #[inline] - fn extend>(&mut self, iter: T) { - for (k, v) in iter { - self.insert(k, v); - } - } -} - -#[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for BTreeMap { - fn hash(&self, state: &mut H) { - for elt in self { - elt.hash(state); - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for BTreeMap { - /// Creates an empty `BTreeMap`. - fn default() -> BTreeMap { - BTreeMap::new() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for BTreeMap { - fn eq(&self, other: &BTreeMap) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for BTreeMap {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for BTreeMap { - #[inline] - fn partial_cmp(&self, other: &BTreeMap) -> Option { - self.iter().partial_cmp(other.iter()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for BTreeMap { - #[inline] - fn cmp(&self, other: &BTreeMap) -> Ordering { - self.iter().cmp(other.iter()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Debug for BTreeMap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_map().entries(self.iter()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap - where K: Borrow, - Q: Ord -{ - type Output = V; - - /// Returns a reference to the value corresponding to the supplied key. - /// - /// # Panics - /// - /// Panics if the key is not present in the `BTreeMap`. - #[inline] - fn index(&self, key: &Q) -> &V { - self.get(key).expect("no entry found for key") - } -} - -fn first_leaf_edge - (mut node: NodeRef) - -> Handle, marker::Edge> { - loop { - match node.force() { - Leaf(leaf) => return leaf.first_edge(), - Internal(internal) => { - node = internal.first_edge().descend(); - } - } - } -} - -fn last_leaf_edge - (mut node: NodeRef) - -> Handle, marker::Edge> { - loop { - match node.force() { - Leaf(leaf) => return leaf.last_edge(), - Internal(internal) => { - node = internal.last_edge().descend(); - } - } - } -} - -fn range_search>( - root1: NodeRef, - root2: NodeRef, - range: R -)-> (Handle, marker::Edge>, - Handle, marker::Edge>) - where Q: Ord, K: Borrow -{ - match (range.start_bound(), range.end_bound()) { - (Excluded(s), Excluded(e)) if s==e => - panic!("range start and end are equal and excluded in BTreeMap"), - (Included(s), Included(e)) | - (Included(s), Excluded(e)) | - (Excluded(s), Included(e)) | - (Excluded(s), Excluded(e)) if s>e => - panic!("range start is greater than range end in BTreeMap"), - _ => {}, - }; - - let mut min_node = root1; - let mut max_node = root2; - let mut min_found = false; - let mut max_found = false; - let mut diverged = false; - - loop { - let min_edge = match (min_found, range.start_bound()) { - (false, Included(key)) => match search::search_linear(&min_node, key) { - (i, true) => { min_found = true; i }, - (i, false) => i, - }, - (false, Excluded(key)) => match search::search_linear(&min_node, key) { - (i, true) => { min_found = true; i+1 }, - (i, false) => i, - }, - (_, Unbounded) => 0, - (true, Included(_)) => min_node.keys().len(), - (true, Excluded(_)) => 0, - }; - - let max_edge = match (max_found, range.end_bound()) { - (false, Included(key)) => match search::search_linear(&max_node, key) { - (i, true) => { max_found = true; i+1 }, - (i, false) => i, - }, - (false, Excluded(key)) => match search::search_linear(&max_node, key) { - (i, true) => { max_found = true; i }, - (i, false) => i, - }, - (_, Unbounded) => max_node.keys().len(), - (true, Included(_)) => 0, - (true, Excluded(_)) => max_node.keys().len(), - }; - - if !diverged { - if max_edge < min_edge { panic!("Ord is ill-defined in BTreeMap range") } - if min_edge != max_edge { diverged = true; } - } - - let front = Handle::new_edge(min_node, min_edge); - let back = Handle::new_edge(max_node, max_edge); - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return (f, b); - }, - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - }, - _ => unreachable!("BTreeMap has different depths"), - }; - } -} - -#[inline(always)] -unsafe fn unwrap_unchecked(val: Option) -> T { - val.unwrap_or_else(|| { - if cfg!(debug_assertions) { - panic!("'unchecked' unwrap on None in BTreeMap"); - } else { - intrinsics::unreachable(); - } - }) -} - -impl BTreeMap { - /// Gets an iterator over the entries of the map, sorted by key. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(3, "c"); - /// map.insert(2, "b"); - /// map.insert(1, "a"); - /// - /// for (key, value) in map.iter() { - /// println!("{}: {}", key, value); - /// } - /// - /// let (first_key, first_value) = map.iter().next().unwrap(); - /// assert_eq!((*first_key, *first_value), (1, "a")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { - range: Range { - front: first_leaf_edge(self.root.as_ref()), - back: last_leaf_edge(self.root.as_ref()), - }, - length: self.length, - } - } - - /// Gets a mutable iterator over the entries of the map, sorted by key. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// // add 10 to the value if the key isn't "a" - /// for (key, value) in map.iter_mut() { - /// if key != &"a" { - /// *value += 10; - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { - let root1 = self.root.as_mut(); - let root2 = unsafe { ptr::read(&root1) }; - IterMut { - range: RangeMut { - front: first_leaf_edge(root1), - back: last_leaf_edge(root2), - _marker: PhantomData, - }, - length: self.length, - } - } - - /// Gets an iterator over the keys of the map, in sorted order. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// a.insert(2, "b"); - /// a.insert(1, "a"); - /// - /// let keys: Vec<_> = a.keys().cloned().collect(); - /// assert_eq!(keys, [1, 2]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { - Keys { inner: self.iter() } - } - - /// Gets an iterator over the values of the map, in order by key. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "hello"); - /// a.insert(2, "goodbye"); - /// - /// let values: Vec<&str> = a.values().cloned().collect(); - /// assert_eq!(values, ["hello", "goodbye"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn values<'a>(&'a self) -> Values<'a, K, V> { - Values { inner: self.iter() } - } - - /// Gets a mutable iterator over the values of the map, in order by key. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, String::from("hello")); - /// a.insert(2, String::from("goodbye")); - /// - /// for value in a.values_mut() { - /// value.push_str("!"); - /// } - /// - /// let values: Vec = a.values().cloned().collect(); - /// assert_eq!(values, [String::from("hello!"), - /// String::from("goodbye!")]); - /// ``` - #[stable(feature = "map_values_mut", since = "1.10.0")] - pub fn values_mut(&mut self) -> ValuesMut { - ValuesMut { inner: self.iter_mut() } - } - - /// Returns the number of elements in the map. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// assert_eq!(a.len(), 0); - /// a.insert(1, "a"); - /// assert_eq!(a.len(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { - self.length - } - - /// Returns `true` if the map contains no elements. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut a = BTreeMap::new(); - /// assert!(a.is_empty()); - /// a.insert(1, "a"); - /// assert!(!a.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl<'a, K: Ord, V> Entry<'a, K, V> { - /// Ensures a value is in the entry by inserting the default if empty, and returns - /// a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_insert(self, default: V) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default), - } - } - - /// Ensures a value is in the entry by inserting the result of the default function if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); - /// let s = "hoho".to_string(); - /// - /// map.entry("poneyland").or_insert_with(|| s); - /// - /// assert_eq!(map["poneyland"], "hoho".to_string()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_insert_with V>(self, default: F) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default()), - } - } - - /// Returns a reference to this entry's key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - match *self { - Occupied(ref entry) => entry.key(), - Vacant(ref entry) => entry.key(), - } - } - - /// Provides in-place mutable access to an occupied entry before any - /// potential inserts into the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 42); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 43); - /// ``` - #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify(self, f: F) -> Self - where F: FnOnce(&mut V) - { - match self { - Occupied(mut entry) => { - f(entry.get_mut()); - Occupied(entry) - }, - Vacant(entry) => Vacant(entry), - } - } -} - -impl<'a, K: Ord, V: Default> Entry<'a, K, V> { - #[stable(feature = "entry_or_default", since = "1.28.0")] - /// Ensures a value is in the entry by inserting the default value if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// # fn main() { - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, Option> = BTreeMap::new(); - /// map.entry("poneyland").or_default(); - /// - /// assert_eq!(map["poneyland"], None); - /// # } - /// ``` - pub fn or_default(self) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(Default::default()), - } - } - -} - -impl<'a, K: Ord, V> VacantEntry<'a, K, V> { - /// Gets a reference to the key that would be used when inserting a value - /// through the VacantEntry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - &self.key - } - - /// Take ownership of the key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// if let Entry::Vacant(v) = map.entry("poneyland") { - /// v.into_key(); - /// } - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn into_key(self) -> K { - self.key - } - - /// Sets the value of the entry with the `VacantEntry`'s key, - /// and returns a mutable reference to it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// // count the number of occurrences of letters in the vec - /// for x in vec!["a","b","a","c","a","b"] { - /// *count.entry(x).or_insert(0) += 1; - /// } - /// - /// assert_eq!(count["a"], 3); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(self, value: V) -> &'a mut V { - *self.length += 1; - - let out_ptr; - - let mut ins_k; - let mut ins_v; - let mut ins_edge; - - let mut cur_parent = match self.handle.insert(self.key, value) { - (Fit(handle), _) => return handle.into_kv_mut().1, - (Split(left, k, v, right), ptr) => { - ins_k = k; - ins_v = v; - ins_edge = right; - out_ptr = ptr; - left.ascend().map_err(|n| n.into_root_mut()) - } - }; - - loop { - match cur_parent { - Ok(parent) => { - match parent.insert(ins_k, ins_v, ins_edge) { - Fit(_) => return unsafe { &mut *out_ptr }, - Split(left, k, v, right) => { - ins_k = k; - ins_v = v; - ins_edge = right; - cur_parent = left.ascend().map_err(|n| n.into_root_mut()); - } - } - } - Err(root) => { - root.push_level().push(ins_k, ins_v, ins_edge); - return unsafe { &mut *out_ptr }; - } - } - } - } -} - -impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { - /// Gets a reference to the key in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - self.handle.reborrow().into_kv().0 - } - - /// Take ownership of the key and value from the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// // We delete the entry from the map. - /// o.remove_entry(); - /// } - /// - /// // If now try to get the value, it will panic: - /// // println!("{}", map["poneyland"]); - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn remove_entry(self) -> (K, V) { - self.remove_kv() - } - - /// Gets a reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.get(), &12); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> &V { - self.handle.reborrow().into_kv().1 - } - - /// Gets a mutable reference to the value in the entry. - /// - /// If you need a reference to the `OccupiedEntry` which may outlive the - /// destruction of the `Entry` value, see [`into_mut`]. - /// - /// [`into_mut`]: #method.into_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// *o.get_mut() += 10; - /// assert_eq!(*o.get(), 22); - /// - /// // We can use the same Entry multiple times. - /// *o.get_mut() += 2; - /// } - /// assert_eq!(map["poneyland"], 24); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut V { - self.handle.kv_mut().1 - } - - /// Converts the entry into a mutable reference to its value. - /// - /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. - /// - /// [`get_mut`]: #method.get_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// *o.into_mut() += 10; - /// } - /// assert_eq!(map["poneyland"], 22); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_mut(self) -> &'a mut V { - self.handle.into_kv_mut().1 - } - - /// Sets the value of the entry with the `OccupiedEntry`'s key, - /// and returns the entry's old value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// assert_eq!(o.insert(15), 12); - /// } - /// assert_eq!(map["poneyland"], 15); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, value: V) -> V { - mem::replace(self.get_mut(), value) - } - - /// Takes the value of the entry out of the map, and returns it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.remove(), 12); - /// } - /// // If we try to get "poneyland"'s value, it'll panic: - /// // println!("{}", map["poneyland"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(self) -> V { - self.remove_kv().1 - } - - fn remove_kv(self) -> (K, V) { - *self.length -= 1; - - let (small_leaf, old_key, old_val) = match self.handle.force() { - Leaf(leaf) => { - let (hole, old_key, old_val) = leaf.remove(); - (hole.into_node(), old_key, old_val) - } - Internal(mut internal) => { - let key_loc = internal.kv_mut().0 as *mut K; - let val_loc = internal.kv_mut().1 as *mut V; - - let to_remove = first_leaf_edge(internal.right_edge().descend()).right_kv().ok(); - let to_remove = unsafe { unwrap_unchecked(to_remove) }; - - let (hole, key, val) = to_remove.remove(); - - let old_key = unsafe { mem::replace(&mut *key_loc, key) }; - let old_val = unsafe { mem::replace(&mut *val_loc, val) }; - - (hole.into_node(), old_key, old_val) - } - }; - - // Handle underflow - let mut cur_node = small_leaf.forget_type(); - while cur_node.len() < node::CAPACITY / 2 { - match handle_underfull_node(cur_node) { - AtRoot => break, - EmptyParent(_) => unreachable!(), - Merged(parent) => { - if parent.len() == 0 { - // We must be at the root - parent.into_root_mut().pop_level(); - break; - } else { - cur_node = parent.forget_type(); - } - } - Stole(_) => break, - } - } - - (old_key, old_val) - } -} - -enum UnderflowResult<'a, K, V> { - AtRoot, - EmptyParent(NodeRef, K, V, marker::Internal>), - Merged(NodeRef, K, V, marker::Internal>), - Stole(NodeRef, K, V, marker::Internal>), -} - -fn handle_underfull_node<'a, K, V>(node: NodeRef, K, V, marker::LeafOrInternal>) - -> UnderflowResult<'a, K, V> { - let parent = if let Ok(parent) = node.ascend() { - parent - } else { - return AtRoot; - }; - - let (is_left, mut handle) = match parent.left_kv() { - Ok(left) => (true, left), - Err(parent) => { - match parent.right_kv() { - Ok(right) => (false, right), - Err(parent) => { - return EmptyParent(parent.into_node()); - } - } - } - }; - - if handle.can_merge() { - Merged(handle.merge().into_node()) - } else { - if is_left { - handle.steal_left(); - } else { - handle.steal_right(); - } - Stole(handle.into_node()) - } -} - -impl> Iterator for MergeIter { - type Item = (K, V); - - fn next(&mut self) -> Option<(K, V)> { - let res = match (self.left.peek(), self.right.peek()) { - (Some(&(ref left_key, _)), Some(&(ref right_key, _))) => left_key.cmp(right_key), - (Some(_), None) => Ordering::Less, - (None, Some(_)) => Ordering::Greater, - (None, None) => return None, - }; - - // Check which elements comes first and only advance the corresponding iterator. - // If two keys are equal, take the value from `right`. - match res { - Ordering::Less => self.left.next(), - Ordering::Greater => self.right.next(), - Ordering::Equal => { - self.left.next(); - self.right.next() - } - } - } -} diff --git a/src/liballoc/btree/mod.rs b/src/liballoc/btree/mod.rs deleted file mode 100644 index 087c9f228d4..00000000000 --- a/src/liballoc/btree/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -mod node; -mod search; -pub mod map; -pub mod set; - -#[doc(hidden)] -trait Recover { - type Key; - - fn get(&self, key: &Q) -> Option<&Self::Key>; - fn take(&mut self, key: &Q) -> Option; - fn replace(&mut self, key: Self::Key) -> Option; -} diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs deleted file mode 100644 index 19bdcbc6ad6..00000000000 --- a/src/liballoc/btree/node.rs +++ /dev/null @@ -1,1622 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This is an attempt at an implementation following the ideal -// -// ``` -// struct BTreeMap { -// height: usize, -// root: Option>> -// } -// -// struct Node { -// keys: [K; 2 * B - 1], -// vals: [V; 2 * B - 1], -// edges: if height > 0 { -// [Box>; 2 * B] -// } else { () }, -// parent: *const Node, -// parent_idx: u16, -// len: u16, -// } -// ``` -// -// Since Rust doesn't actually have dependent types and polymorphic recursion, -// we make do with lots of unsafety. - -// A major goal of this module is to avoid complexity by treating the tree as a generic (if -// weirdly shaped) container and avoiding dealing with most of the B-Tree invariants. As such, -// this module doesn't care whether the entries are sorted, which nodes can be underfull, or -// even what underfull means. However, we do rely on a few invariants: -// -// - Trees must have uniform depth/height. This means that every path down to a leaf from a -// given node has exactly the same length. -// - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges. -// This implies that even an empty internal node has at least one edge. - -use core::marker::PhantomData; -use core::mem; -use core::ptr::{self, Unique, NonNull}; -use core::slice; - -use alloc::{Global, Alloc, Layout}; -use boxed::Box; - -const B: usize = 6; -pub const MIN_LEN: usize = B - 1; -pub const CAPACITY: usize = 2 * B - 1; - -/// The underlying representation of leaf nodes. Note that it is often unsafe to actually store -/// these, since only the first `len` keys and values are assumed to be initialized. As such, -/// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned -/// case. -/// -/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by -/// avoiding accidentally dropping unused and uninitialized keys and values. -/// -/// We put the metadata first so that its position is the same for every `K` and `V`, in order -/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to -/// prevent them from being reordered. -#[repr(C)] -struct LeafNode { - /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. - /// This either points to an actual node or is null. - parent: *const InternalNode, - - /// This node's index into the parent node's `edges` array. - /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. - /// This is only guaranteed to be initialized when `parent` is nonnull. - parent_idx: u16, - - /// The number of keys and values this node stores. - /// - /// This next to `parent_idx` to encourage the compiler to join `len` and - /// `parent_idx` into the same 32-bit word, reducing space overhead. - len: u16, - - /// The arrays storing the actual data of the node. Only the first `len` elements of each - /// array are initialized and valid. - keys: [K; CAPACITY], - vals: [V; CAPACITY], -} - -impl LeafNode { - /// Creates a new `LeafNode`. Unsafe because all nodes should really be hidden behind - /// `BoxedNode`, preventing accidental dropping of uninitialized keys and values. - unsafe fn new() -> Self { - LeafNode { - // As a general policy, we leave fields uninitialized if they can be, as this should - // be both slightly faster and easier to track in Valgrind. - keys: mem::uninitialized(), - vals: mem::uninitialized(), - parent: ptr::null(), - parent_idx: mem::uninitialized(), - len: 0 - } - } - - fn is_shared_root(&self) -> bool { - self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode - } -} - -// We need to implement Sync here in order to make a static instance. -unsafe impl Sync for LeafNode<(), ()> {} - -// An empty node used as a placeholder for the root node, to avoid allocations. -// We use () in order to save space, since no operation on an empty tree will -// ever take a pointer past the first key. -static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode { - parent: ptr::null(), - parent_idx: 0, - len: 0, - keys: [(); CAPACITY], - vals: [(); CAPACITY], -}; - -/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden -/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an -/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the -/// node, allowing code to act on leaf and internal nodes generically without having to even check -/// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`. -#[repr(C)] -struct InternalNode { - data: LeafNode, - - /// The pointers to the children of this node. `len + 1` of these are considered - /// initialized and valid. - edges: [BoxedNode; 2 * B], -} - -impl InternalNode { - /// Creates a new `InternalNode`. - /// - /// This is unsafe for two reasons. First, it returns an `InternalNode` by value, risking - /// dropping of uninitialized fields. Second, an invariant of internal nodes is that `len + 1` - /// edges are initialized and valid, meaning that even when the node is empty (having a - /// `len` of 0), there must be one initialized and valid edge. This function does not set up - /// such an edge. - unsafe fn new() -> Self { - InternalNode { - data: LeafNode::new(), - edges: mem::uninitialized() - } - } -} - -/// An owned pointer to a node. This basically is either `Box>` or -/// `Box>`. However, it contains no information as to which of the two types -/// of nodes is actually behind the box, and, partially due to this lack of information, has no -/// destructor. -struct BoxedNode { - ptr: Unique> -} - -impl BoxedNode { - fn from_leaf(node: Box>) -> Self { - BoxedNode { ptr: Box::into_unique(node) } - } - - fn from_internal(node: Box>) -> Self { - unsafe { - BoxedNode { ptr: Unique::new_unchecked(Box::into_raw(node) as *mut LeafNode) } - } - } - - unsafe fn from_ptr(ptr: NonNull>) -> Self { - BoxedNode { ptr: Unique::from(ptr) } - } - - fn as_ptr(&self) -> NonNull> { - NonNull::from(self.ptr) - } -} - -/// An owned tree. Note that despite being owned, this does not have a destructor, -/// and must be cleaned up manually. -pub struct Root { - node: BoxedNode, - height: usize -} - -unsafe impl Sync for Root { } -unsafe impl Send for Root { } - -impl Root { - pub fn is_shared_root(&self) -> bool { - self.as_ref().is_shared_root() - } - - pub fn shared_empty_root() -> Self { - Root { - node: unsafe { - BoxedNode::from_ptr(NonNull::new_unchecked( - &EMPTY_ROOT_NODE as *const _ as *const LeafNode as *mut _ - )) - }, - height: 0, - } - } - - pub fn new_leaf() -> Self { - Root { - node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), - height: 0 - } - } - - pub fn as_ref(&self) - -> NodeRef { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *const _ as *mut _, - _marker: PhantomData, - } - } - - pub fn as_mut(&mut self) - -> NodeRef { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData, - } - } - - pub fn into_ref(self) - -> NodeRef { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null_mut(), // FIXME: Is there anything better to do here? - _marker: PhantomData, - } - } - - /// Adds a new internal node with a single edge, pointing to the previous root, and make that - /// new node the root. This increases the height by 1 and is the opposite of `pop_level`. - pub fn push_level(&mut self) - -> NodeRef { - debug_assert!(!self.is_shared_root()); - let mut new_node = Box::new(unsafe { InternalNode::new() }); - new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }; - - self.node = BoxedNode::from_internal(new_node); - self.height += 1; - - let mut ret = NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData - }; - - unsafe { - ret.reborrow_mut().first_edge().correct_parent_link(); - } - - ret - } - - /// Removes the root node, using its first child as the new root. This cannot be called when - /// the tree consists only of a leaf node. As it is intended only to be called when the root - /// has only one edge, no cleanup is done on any of the other children are elements of the root. - /// This decreases the height by 1 and is the opposite of `push_level`. - pub fn pop_level(&mut self) { - debug_assert!(self.height > 0); - - let top = self.node.ptr; - - self.node = unsafe { - BoxedNode::from_ptr(self.as_mut() - .cast_unchecked::() - .first_edge() - .descend() - .node) - }; - self.height -= 1; - self.as_mut().as_leaf_mut().parent = ptr::null(); - - unsafe { - Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); - } - } -} - -// N.B. `NodeRef` is always covariant in `K` and `V`, even when the `BorrowType` -// is `Mut`. This is technically wrong, but cannot result in any unsafety due to -// internal use of `NodeRef` because we stay completely generic over `K` and `V`. -// However, whenever a public type wraps `NodeRef`, make sure that it has the -// correct variance. -/// A reference to a node. -/// -/// This type has a number of parameters that controls how it acts: -/// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`. -/// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`, -/// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`, -/// and when this is `Owned`, the `NodeRef` acts roughly like `Box`. -/// - `K` and `V`: These control what types of things are stored in the nodes. -/// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is -/// `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the -/// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the -/// `NodeRef` could be pointing to either type of node. -pub struct NodeRef { - height: usize, - node: NonNull>, - // This is null unless the borrow type is `Mut` - root: *const Root, - _marker: PhantomData<(BorrowType, Type)> -} - -impl<'a, K: 'a, V: 'a, Type> Copy for NodeRef, K, V, Type> { } -impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef, K, V, Type> { - fn clone(&self) -> Self { - *self - } -} - -unsafe impl Sync - for NodeRef { } - -unsafe impl<'a, K: Sync + 'a, V: Sync + 'a, Type> Send - for NodeRef, K, V, Type> { } -unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send - for NodeRef, K, V, Type> { } -unsafe impl Send - for NodeRef { } - -impl NodeRef { - fn as_internal(&self) -> &InternalNode { - unsafe { - &*(self.node.as_ptr() as *mut InternalNode) - } - } -} - -impl<'a, K, V> NodeRef, K, V, marker::Internal> { - fn as_internal_mut(&mut self) -> &mut InternalNode { - unsafe { - &mut *(self.node.as_ptr() as *mut InternalNode) - } - } -} - - -impl NodeRef { - /// Finds the length of the node. This is the number of keys or values. In an - /// internal node, the number of edges is `len() + 1`. - pub fn len(&self) -> usize { - self.as_leaf().len as usize - } - - /// Returns the height of this node in the whole tree. Zero height denotes the - /// leaf level. - pub fn height(&self) -> usize { - self.height - } - - /// Removes any static information about whether this node is a `Leaf` or an - /// `Internal` node. - pub fn forget_type(self) -> NodeRef { - NodeRef { - height: self.height, - node: self.node, - root: self.root, - _marker: PhantomData - } - } - - /// Temporarily takes out another, immutable reference to the same node. - fn reborrow<'a>(&'a self) -> NodeRef, K, V, Type> { - NodeRef { - height: self.height, - node: self.node, - root: self.root, - _marker: PhantomData - } - } - - fn as_leaf(&self) -> &LeafNode { - unsafe { - self.node.as_ref() - } - } - - pub fn is_shared_root(&self) -> bool { - self.as_leaf().is_shared_root() - } - - pub fn keys(&self) -> &[K] { - self.reborrow().into_key_slice() - } - - fn vals(&self) -> &[V] { - self.reborrow().into_val_slice() - } - - /// Finds the parent of the current node. Returns `Ok(handle)` if the current - /// node actually has a parent, where `handle` points to the edge of the parent - /// that points to the current node. Returns `Err(self)` if the current node has - /// no parent, giving back the original `NodeRef`. - /// - /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should - /// both, upon success, do nothing. - pub fn ascend(self) -> Result< - Handle< - NodeRef< - BorrowType, - K, V, - marker::Internal - >, - marker::Edge - >, - Self - > { - let parent_as_leaf = self.as_leaf().parent as *const LeafNode; - if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { - Ok(Handle { - node: NodeRef { - height: self.height + 1, - node: non_zero, - root: self.root, - _marker: PhantomData - }, - idx: self.as_leaf().parent_idx as usize, - _marker: PhantomData - }) - } else { - Err(self) - } - } - - pub fn first_edge(self) -> Handle { - Handle::new_edge(self, 0) - } - - pub fn last_edge(self) -> Handle { - let len = self.len(); - Handle::new_edge(self, len) - } - - /// Note that `self` must be nonempty. - pub fn first_kv(self) -> Handle { - debug_assert!(self.len() > 0); - Handle::new_kv(self, 0) - } - - /// Note that `self` must be nonempty. - pub fn last_kv(self) -> Handle { - let len = self.len(); - debug_assert!(len > 0); - Handle::new_kv(self, len - 1) - } -} - -impl NodeRef { - /// Similar to `ascend`, gets a reference to a node's parent node, but also - /// deallocate the current node in the process. This is unsafe because the - /// current node will still be accessible despite being deallocated. - pub unsafe fn deallocate_and_ascend(self) -> Option< - Handle< - NodeRef< - marker::Owned, - K, V, - marker::Internal - >, - marker::Edge - > - > { - debug_assert!(!self.is_shared_root()); - let node = self.node; - let ret = self.ascend().ok(); - Global.dealloc(node.cast(), Layout::new::>()); - ret - } -} - -impl NodeRef { - /// Similar to `ascend`, gets a reference to a node's parent node, but also - /// deallocate the current node in the process. This is unsafe because the - /// current node will still be accessible despite being deallocated. - pub unsafe fn deallocate_and_ascend(self) -> Option< - Handle< - NodeRef< - marker::Owned, - K, V, - marker::Internal - >, - marker::Edge - > - > { - let node = self.node; - let ret = self.ascend().ok(); - Global.dealloc(node.cast(), Layout::new::>()); - ret - } -} - -impl<'a, K, V, Type> NodeRef, K, V, Type> { - /// Unsafely asserts to the compiler some static information about whether this - /// node is a `Leaf`. - unsafe fn cast_unchecked(&mut self) - -> NodeRef { - - NodeRef { - height: self.height, - node: self.node, - root: self.root, - _marker: PhantomData - } - } - - /// Temporarily takes out another, mutable reference to the same node. Beware, as - /// this method is very dangerous, doubly so since it may not immediately appear - /// dangerous. - /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. - unsafe fn reborrow_mut(&mut self) -> NodeRef { - NodeRef { - height: self.height, - node: self.node, - root: self.root, - _marker: PhantomData - } - } - - fn as_leaf_mut(&mut self) -> &mut LeafNode { - unsafe { - self.node.as_mut() - } - } - - fn keys_mut(&mut self) -> &mut [K] { - unsafe { self.reborrow_mut().into_key_slice_mut() } - } - - fn vals_mut(&mut self) -> &mut [V] { - unsafe { self.reborrow_mut().into_val_slice_mut() } - } -} - -impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - fn into_key_slice(self) -> &'a [K] { - // When taking a pointer to the keys, if our key has a stricter - // alignment requirement than the shared root does, then the pointer - // would be out of bounds, which LLVM assumes will not happen. If the - // alignment is more strict, we need to make an empty slice that doesn't - // use an out of bounds pointer. - if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { - &[] - } else { - // Here either it's not the root, or the alignment is less strict, - // in which case the keys pointer will point "one-past-the-end" of - // the node, which is allowed by LLVM. - unsafe { - slice::from_raw_parts( - self.as_leaf().keys.as_ptr(), - self.len() - ) - } - } - } - - fn into_val_slice(self) -> &'a [V] { - debug_assert!(!self.is_shared_root()); - unsafe { - slice::from_raw_parts( - self.as_leaf().vals.as_ptr(), - self.len() - ) - } - } - - fn into_slices(self) -> (&'a [K], &'a [V]) { - let k = unsafe { ptr::read(&self) }; - (k.into_key_slice(), self.into_val_slice()) - } -} - -impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Gets a mutable reference to the root itself. This is useful primarily when the - /// height of the tree needs to be adjusted. Never call this on a reborrowed pointer. - pub fn into_root_mut(self) -> &'a mut Root { - unsafe { - &mut *(self.root as *mut Root) - } - } - - fn into_key_slice_mut(mut self) -> &'a mut [K] { - if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { - &mut [] - } else { - unsafe { - slice::from_raw_parts_mut( - &mut self.as_leaf_mut().keys as *mut [K] as *mut K, - self.len() - ) - } - } - } - - fn into_val_slice_mut(mut self) -> &'a mut [V] { - debug_assert!(!self.is_shared_root()); - unsafe { - slice::from_raw_parts_mut( - &mut self.as_leaf_mut().vals as *mut [V] as *mut V, - self.len() - ) - } - } - - fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) { - let k = unsafe { ptr::read(&self) }; - (k.into_key_slice_mut(), self.into_val_slice_mut()) - } -} - -impl<'a, K, V> NodeRef, K, V, marker::Leaf> { - /// Adds a key/value pair the end of the node. - pub fn push(&mut self, key: K, val: V) { - // Necessary for correctness, but this is an internal module - debug_assert!(self.len() < CAPACITY); - debug_assert!(!self.is_shared_root()); - - let idx = self.len(); - - unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - } - - self.as_leaf_mut().len += 1; - } - - /// Adds a key/value pair to the beginning of the node. - pub fn push_front(&mut self, key: K, val: V) { - // Necessary for correctness, but this is an internal module - debug_assert!(self.len() < CAPACITY); - debug_assert!(!self.is_shared_root()); - - unsafe { - slice_insert(self.keys_mut(), 0, key); - slice_insert(self.vals_mut(), 0, val); - } - - self.as_leaf_mut().len += 1; - } -} - -impl<'a, K, V> NodeRef, K, V, marker::Internal> { - /// Adds a key/value pair and an edge to go to the right of that pair to - /// the end of the node. - pub fn push(&mut self, key: K, val: V, edge: Root) { - // Necessary for correctness, but this is an internal module - debug_assert!(edge.height == self.height - 1); - debug_assert!(self.len() < CAPACITY); - - let idx = self.len(); - - unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - ptr::write(self.as_internal_mut().edges.get_unchecked_mut(idx + 1), edge.node); - - self.as_leaf_mut().len += 1; - - Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); - } - } - - fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) { - for i in first..after_last { - Handle::new_edge(unsafe { self.reborrow_mut() }, i).correct_parent_link(); - } - } - - fn correct_all_childrens_parent_links(&mut self) { - let len = self.len(); - self.correct_childrens_parent_links(0, len + 1); - } - - /// Adds a key/value pair and an edge to go to the left of that pair to - /// the beginning of the node. - pub fn push_front(&mut self, key: K, val: V, edge: Root) { - // Necessary for correctness, but this is an internal module - debug_assert!(edge.height == self.height - 1); - debug_assert!(self.len() < CAPACITY); - - unsafe { - slice_insert(self.keys_mut(), 0, key); - slice_insert(self.vals_mut(), 0, val); - slice_insert( - slice::from_raw_parts_mut( - self.as_internal_mut().edges.as_mut_ptr(), - self.len()+1 - ), - 0, - edge.node - ); - - self.as_leaf_mut().len += 1; - - self.correct_all_childrens_parent_links(); - } - } -} - -impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { - /// Removes a key/value pair from the end of this node. If this is an internal node, - /// also removes the edge that was to the right of that pair. - pub fn pop(&mut self) -> (K, V, Option>) { - // Necessary for correctness, but this is an internal module - debug_assert!(self.len() > 0); - - let idx = self.len() - 1; - - unsafe { - let key = ptr::read(self.keys().get_unchecked(idx)); - let val = ptr::read(self.vals().get_unchecked(idx)); - let edge = match self.reborrow_mut().force() { - ForceResult::Leaf(_) => None, - ForceResult::Internal(internal) => { - let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1)); - let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.as_mut().as_leaf_mut().parent = ptr::null(); - Some(new_root) - } - }; - - self.as_leaf_mut().len -= 1; - (key, val, edge) - } - } - - /// Removes a key/value pair from the beginning of this node. If this is an internal node, - /// also removes the edge that was to the left of that pair. - pub fn pop_front(&mut self) -> (K, V, Option>) { - // Necessary for correctness, but this is an internal module - debug_assert!(self.len() > 0); - - let old_len = self.len(); - - unsafe { - let key = slice_remove(self.keys_mut(), 0); - let val = slice_remove(self.vals_mut(), 0); - let edge = match self.reborrow_mut().force() { - ForceResult::Leaf(_) => None, - ForceResult::Internal(mut internal) => { - let edge = slice_remove( - slice::from_raw_parts_mut( - internal.as_internal_mut().edges.as_mut_ptr(), - old_len+1 - ), - 0 - ); - - let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.as_mut().as_leaf_mut().parent = ptr::null(); - - for i in 0..old_len { - Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); - } - - Some(new_root) - } - }; - - self.as_leaf_mut().len -= 1; - - (key, val, edge) - } - } - - fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) { - ( - self.keys_mut().as_mut_ptr(), - self.vals_mut().as_mut_ptr() - ) - } -} - -impl NodeRef { - /// Checks whether a node is an `Internal` node or a `Leaf` node. - pub fn force(self) -> ForceResult< - NodeRef, - NodeRef - > { - if self.height == 0 { - ForceResult::Leaf(NodeRef { - height: self.height, - node: self.node, - root: self.root, - _marker: PhantomData - }) - } else { - ForceResult::Internal(NodeRef { - height: self.height, - node: self.node, - root: self.root, - _marker: PhantomData - }) - } - } -} - -/// A reference to a specific key/value pair or edge within a node. The `Node` parameter -/// must be a `NodeRef`, while the `Type` can either be `KV` (signifying a handle on a key/value -/// pair) or `Edge` (signifying a handle on an edge). -/// -/// Note that even `Leaf` nodes can have `Edge` handles. Instead of representing a pointer to -/// a child node, these represent the spaces where child pointers would go between the key/value -/// pairs. For example, in a node with length 2, there would be 3 possible edge locations - one -/// to the left of the node, one between the two pairs, and one at the right of the node. -pub struct Handle { - node: Node, - idx: usize, - _marker: PhantomData -} - -impl Copy for Handle { } -// We don't need the full generality of `#[derive(Clone)]`, as the only time `Node` will be -// `Clone`able is when it is an immutable reference and therefore `Copy`. -impl Clone for Handle { - fn clone(&self) -> Self { - *self - } -} - -impl Handle { - /// Retrieves the node that contains the edge of key/value pair this handle points to. - pub fn into_node(self) -> Node { - self.node - } -} - -impl Handle, marker::KV> { - /// Creates a new handle to a key/value pair in `node`. `idx` must be less than `node.len()`. - pub fn new_kv(node: NodeRef, idx: usize) -> Self { - // Necessary for correctness, but in a private module - debug_assert!(idx < node.len()); - - Handle { - node, - idx, - _marker: PhantomData - } - } - - pub fn left_edge(self) -> Handle, marker::Edge> { - Handle::new_edge(self.node, self.idx) - } - - pub fn right_edge(self) -> Handle, marker::Edge> { - Handle::new_edge(self.node, self.idx + 1) - } -} - -impl PartialEq - for Handle, HandleType> { - - fn eq(&self, other: &Self) -> bool { - self.node.node == other.node.node && self.idx == other.idx - } -} - -impl - Handle, HandleType> { - - /// Temporarily takes out another, immutable handle on the same location. - pub fn reborrow(&self) - -> Handle, HandleType> { - - // We can't use Handle::new_kv or Handle::new_edge because we don't know our type - Handle { - node: self.node.reborrow(), - idx: self.idx, - _marker: PhantomData - } - } -} - -impl<'a, K, V, NodeType, HandleType> - Handle, K, V, NodeType>, HandleType> { - - /// Temporarily takes out another, mutable handle on the same location. Beware, as - /// this method is very dangerous, doubly so since it may not immediately appear - /// dangerous. - /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. - pub unsafe fn reborrow_mut(&mut self) - -> Handle, HandleType> { - - // We can't use Handle::new_kv or Handle::new_edge because we don't know our type - Handle { - node: self.node.reborrow_mut(), - idx: self.idx, - _marker: PhantomData - } - } -} - -impl - Handle, marker::Edge> { - - /// Creates a new handle to an edge in `node`. `idx` must be less than or equal to - /// `node.len()`. - pub fn new_edge(node: NodeRef, idx: usize) -> Self { - // Necessary for correctness, but in a private module - debug_assert!(idx <= node.len()); - - Handle { - node, - idx, - _marker: PhantomData - } - } - - pub fn left_kv(self) - -> Result, marker::KV>, Self> { - - if self.idx > 0 { - Ok(Handle::new_kv(self.node, self.idx - 1)) - } else { - Err(self) - } - } - - pub fn right_kv(self) - -> Result, marker::KV>, Self> { - - if self.idx < self.node.len() { - Ok(Handle::new_kv(self.node, self.idx)) - } else { - Err(self) - } - } -} - -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { - /// Inserts a new key/value pair between the key/value pairs to the right and left of - /// this edge. This method assumes that there is enough space in the node for the new - /// pair to fit. - /// - /// The returned pointer points to the inserted value. - fn insert_fit(&mut self, key: K, val: V) -> *mut V { - // Necessary for correctness, but in a private module - debug_assert!(self.node.len() < CAPACITY); - debug_assert!(!self.node.is_shared_root()); - - unsafe { - slice_insert(self.node.keys_mut(), self.idx, key); - slice_insert(self.node.vals_mut(), self.idx, val); - - self.node.as_leaf_mut().len += 1; - - self.node.vals_mut().get_unchecked_mut(self.idx) - } - } - - /// Inserts a new key/value pair between the key/value pairs to the right and left of - /// this edge. This method splits the node if there isn't enough room. - /// - /// The returned pointer points to the inserted value. - pub fn insert(mut self, key: K, val: V) - -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) { - - if self.node.len() < CAPACITY { - let ptr = self.insert_fit(key, val); - (InsertResult::Fit(Handle::new_kv(self.node, self.idx)), ptr) - } else { - let middle = Handle::new_kv(self.node, B); - let (mut left, k, v, mut right) = middle.split(); - let ptr = if self.idx <= B { - unsafe { - Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val) - } - } else { - unsafe { - Handle::new_edge( - right.as_mut().cast_unchecked::(), - self.idx - (B + 1) - ).insert_fit(key, val) - } - }; - (InsertResult::Split(left, k, v, right), ptr) - } - } -} - -impl<'a, K, V> Handle, K, V, marker::Internal>, marker::Edge> { - /// Fixes the parent pointer and index in the child node below this edge. This is useful - /// when the ordering of edges has been changed, such as in the various `insert` methods. - fn correct_parent_link(mut self) { - let idx = self.idx as u16; - let ptr = self.node.as_internal_mut() as *mut _; - let mut child = self.descend(); - child.as_leaf_mut().parent = ptr; - child.as_leaf_mut().parent_idx = idx; - } - - /// Unsafely asserts to the compiler some static information about whether the underlying - /// node of this handle is a `Leaf`. - unsafe fn cast_unchecked(&mut self) - -> Handle, marker::Edge> { - - Handle::new_edge(self.node.cast_unchecked(), self.idx) - } - - /// Inserts a new key/value pair and an edge that will go to the right of that new pair - /// between this edge and the key/value pair to the right of this edge. This method assumes - /// that there is enough space in the node for the new pair to fit. - fn insert_fit(&mut self, key: K, val: V, edge: Root) { - // Necessary for correctness, but in an internal module - debug_assert!(self.node.len() < CAPACITY); - debug_assert!(edge.height == self.node.height - 1); - - unsafe { - // This cast is a lie, but it allows us to reuse the key/value insertion logic. - self.cast_unchecked::().insert_fit(key, val); - - slice_insert( - slice::from_raw_parts_mut( - self.node.as_internal_mut().edges.as_mut_ptr(), - self.node.len() - ), - self.idx + 1, - edge.node - ); - - for i in (self.idx+1)..(self.node.len()+1) { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } - } - } - - /// Inserts a new key/value pair and an edge that will go to the right of that new pair - /// between this edge and the key/value pair to the right of this edge. This method splits - /// the node if there isn't enough room. - pub fn insert(mut self, key: K, val: V, edge: Root) - -> InsertResult<'a, K, V, marker::Internal> { - - // Necessary for correctness, but this is an internal module - debug_assert!(edge.height == self.node.height - 1); - - if self.node.len() < CAPACITY { - self.insert_fit(key, val, edge); - InsertResult::Fit(Handle::new_kv(self.node, self.idx)) - } else { - let middle = Handle::new_kv(self.node, B); - let (mut left, k, v, mut right) = middle.split(); - if self.idx <= B { - unsafe { - Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val, edge); - } - } else { - unsafe { - Handle::new_edge( - right.as_mut().cast_unchecked::(), - self.idx - (B + 1) - ).insert_fit(key, val, edge); - } - } - InsertResult::Split(left, k, v, right) - } - } -} - -impl - Handle, marker::Edge> { - - /// Finds the node pointed to by this edge. - /// - /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should - /// both, upon success, do nothing. - pub fn descend(self) -> NodeRef { - NodeRef { - height: self.node.height - 1, - node: unsafe { self.node.as_internal().edges.get_unchecked(self.idx).as_ptr() }, - root: self.node.root, - _marker: PhantomData - } - } -} - -impl<'a, K: 'a, V: 'a, NodeType> - Handle, K, V, NodeType>, marker::KV> { - - pub fn into_kv(self) -> (&'a K, &'a V) { - let (keys, vals) = self.node.into_slices(); - unsafe { - (keys.get_unchecked(self.idx), vals.get_unchecked(self.idx)) - } - } -} - -impl<'a, K: 'a, V: 'a, NodeType> - Handle, K, V, NodeType>, marker::KV> { - - pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { - let (keys, vals) = self.node.into_slices_mut(); - unsafe { - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) - } - } -} - -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { - pub fn kv_mut(&mut self) -> (&mut K, &mut V) { - unsafe { - let (keys, vals) = self.node.reborrow_mut().into_slices_mut(); - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) - } - } -} - -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> { - /// Splits the underlying node into three parts: - /// - /// - The node is truncated to only contain the key/value pairs to the right of - /// this handle. - /// - The key and value pointed to by this handle and extracted. - /// - All the key/value pairs to the right of this handle are put into a newly - /// allocated node. - pub fn split(mut self) - -> (NodeRef, K, V, marker::Leaf>, K, V, Root) { - debug_assert!(!self.node.is_shared_root()); - unsafe { - let mut new_node = Box::new(LeafNode::new()); - - let k = ptr::read(self.node.keys().get_unchecked(self.idx)); - let v = ptr::read(self.node.vals().get_unchecked(self.idx)); - - let new_len = self.node.len() - self.idx - 1; - - ptr::copy_nonoverlapping( - self.node.keys().as_ptr().offset(self.idx as isize + 1), - new_node.keys.as_mut_ptr(), - new_len - ); - ptr::copy_nonoverlapping( - self.node.vals().as_ptr().offset(self.idx as isize + 1), - new_node.vals.as_mut_ptr(), - new_len - ); - - self.node.as_leaf_mut().len = self.idx as u16; - new_node.len = new_len as u16; - - ( - self.node, - k, v, - Root { - node: BoxedNode::from_leaf(new_node), - height: 0 - } - ) - } - } - - /// Removes the key/value pair pointed to by this handle, returning the edge between the - /// now adjacent key/value pairs to the left and right of this handle. - pub fn remove(mut self) - -> (Handle, K, V, marker::Leaf>, marker::Edge>, K, V) { - debug_assert!(!self.node.is_shared_root()); - unsafe { - let k = slice_remove(self.node.keys_mut(), self.idx); - let v = slice_remove(self.node.vals_mut(), self.idx); - self.node.as_leaf_mut().len -= 1; - (self.left_edge(), k, v) - } - } -} - -impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { - /// Splits the underlying node into three parts: - /// - /// - The node is truncated to only contain the edges and key/value pairs to the - /// right of this handle. - /// - The key and value pointed to by this handle and extracted. - /// - All the edges and key/value pairs to the right of this handle are put into - /// a newly allocated node. - pub fn split(mut self) - -> (NodeRef, K, V, marker::Internal>, K, V, Root) { - unsafe { - let mut new_node = Box::new(InternalNode::new()); - - let k = ptr::read(self.node.keys().get_unchecked(self.idx)); - let v = ptr::read(self.node.vals().get_unchecked(self.idx)); - - let height = self.node.height; - let new_len = self.node.len() - self.idx - 1; - - ptr::copy_nonoverlapping( - self.node.keys().as_ptr().offset(self.idx as isize + 1), - new_node.data.keys.as_mut_ptr(), - new_len - ); - ptr::copy_nonoverlapping( - self.node.vals().as_ptr().offset(self.idx as isize + 1), - new_node.data.vals.as_mut_ptr(), - new_len - ); - ptr::copy_nonoverlapping( - self.node.as_internal().edges.as_ptr().offset(self.idx as isize + 1), - new_node.edges.as_mut_ptr(), - new_len + 1 - ); - - self.node.as_leaf_mut().len = self.idx as u16; - new_node.data.len = new_len as u16; - - let mut new_root = Root { - node: BoxedNode::from_internal(new_node), - height, - }; - - for i in 0..(new_len+1) { - Handle::new_edge(new_root.as_mut().cast_unchecked(), i).correct_parent_link(); - } - - ( - self.node, - k, v, - new_root - ) - } - } - - /// Returns whether it is valid to call `.merge()`, i.e., whether there is enough room in - /// a node to hold the combination of the nodes to the left and right of this handle along - /// with the key/value pair at this handle. - pub fn can_merge(&self) -> bool { - ( - self.reborrow() - .left_edge() - .descend() - .len() - + self.reborrow() - .right_edge() - .descend() - .len() - + 1 - ) <= CAPACITY - } - - /// Combines the node immediately to the left of this handle, the key/value pair pointed - /// to by this handle, and the node immediately to the right of this handle into one new - /// child of the underlying node, returning an edge referencing that new child. - /// - /// Assumes that this edge `.can_merge()`. - pub fn merge(mut self) - -> Handle, K, V, marker::Internal>, marker::Edge> { - let self1 = unsafe { ptr::read(&self) }; - let self2 = unsafe { ptr::read(&self) }; - let mut left_node = self1.left_edge().descend(); - let left_len = left_node.len(); - let mut right_node = self2.right_edge().descend(); - let right_len = right_node.len(); - - // necessary for correctness, but in a private module - debug_assert!(left_len + right_len + 1 <= CAPACITY); - - unsafe { - ptr::write(left_node.keys_mut().get_unchecked_mut(left_len), - slice_remove(self.node.keys_mut(), self.idx)); - ptr::copy_nonoverlapping( - right_node.keys().as_ptr(), - left_node.keys_mut().as_mut_ptr().offset(left_len as isize + 1), - right_len - ); - ptr::write(left_node.vals_mut().get_unchecked_mut(left_len), - slice_remove(self.node.vals_mut(), self.idx)); - ptr::copy_nonoverlapping( - right_node.vals().as_ptr(), - left_node.vals_mut().as_mut_ptr().offset(left_len as isize + 1), - right_len - ); - - slice_remove(&mut self.node.as_internal_mut().edges, self.idx + 1); - for i in self.idx+1..self.node.len() { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } - self.node.as_leaf_mut().len -= 1; - - left_node.as_leaf_mut().len += right_len as u16 + 1; - - if self.node.height > 1 { - ptr::copy_nonoverlapping( - right_node.cast_unchecked().as_internal().edges.as_ptr(), - left_node.cast_unchecked() - .as_internal_mut() - .edges - .as_mut_ptr() - .offset(left_len as isize + 1), - right_len + 1 - ); - - for i in left_len+1..left_len+right_len+2 { - Handle::new_edge( - left_node.cast_unchecked().reborrow_mut(), - i - ).correct_parent_link(); - } - - Global.dealloc( - right_node.node.cast(), - Layout::new::>(), - ); - } else { - Global.dealloc( - right_node.node.cast(), - Layout::new::>(), - ); - } - - Handle::new_edge(self.node, self.idx) - } - } - - /// This removes a key/value pair from the left child and replaces it with the key/value pair - /// pointed to by this handle while pushing the old key/value pair of this handle into the right - /// child. - pub fn steal_left(&mut self) { - unsafe { - let (k, v, edge) = self.reborrow_mut().left_edge().descend().pop(); - - let k = mem::replace(self.reborrow_mut().into_kv_mut().0, k); - let v = mem::replace(self.reborrow_mut().into_kv_mut().1, v); - - match self.reborrow_mut().right_edge().descend().force() { - ForceResult::Leaf(mut leaf) => leaf.push_front(k, v), - ForceResult::Internal(mut internal) => internal.push_front(k, v, edge.unwrap()) - } - } - } - - /// This removes a key/value pair from the right child and replaces it with the key/value pair - /// pointed to by this handle while pushing the old key/value pair of this handle into the left - /// child. - pub fn steal_right(&mut self) { - unsafe { - let (k, v, edge) = self.reborrow_mut().right_edge().descend().pop_front(); - - let k = mem::replace(self.reborrow_mut().into_kv_mut().0, k); - let v = mem::replace(self.reborrow_mut().into_kv_mut().1, v); - - match self.reborrow_mut().left_edge().descend().force() { - ForceResult::Leaf(mut leaf) => leaf.push(k, v), - ForceResult::Internal(mut internal) => internal.push(k, v, edge.unwrap()) - } - } - } - - /// This does stealing similar to `steal_left` but steals multiple elements at once. - pub fn bulk_steal_left(&mut self, count: usize) { - unsafe { - let mut left_node = ptr::read(self).left_edge().descend(); - let left_len = left_node.len(); - let mut right_node = ptr::read(self).right_edge().descend(); - let right_len = right_node.len(); - - // Make sure that we may steal safely. - debug_assert!(right_len + count <= CAPACITY); - debug_assert!(left_len >= count); - - let new_left_len = left_len - count; - - // Move data. - { - let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); - let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); - let parent_kv = { - let kv = self.reborrow_mut().into_kv_mut(); - (kv.0 as *mut K, kv.1 as *mut V) - }; - - // Make room for stolen elements in the right child. - ptr::copy(right_kv.0, - right_kv.0.offset(count as isize), - right_len); - ptr::copy(right_kv.1, - right_kv.1.offset(count as isize), - right_len); - - // Move elements from the left child to the right one. - move_kv(left_kv, new_left_len + 1, right_kv, 0, count - 1); - - // Move parent's key/value pair to the right child. - move_kv(parent_kv, 0, right_kv, count - 1, 1); - - // Move the left-most stolen pair to the parent. - move_kv(left_kv, new_left_len, parent_kv, 0, 1); - } - - left_node.reborrow_mut().as_leaf_mut().len -= count as u16; - right_node.reborrow_mut().as_leaf_mut().len += count as u16; - - match (left_node.force(), right_node.force()) { - (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { - // Make room for stolen edges. - let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); - ptr::copy(right_edges, - right_edges.offset(count as isize), - right_len + 1); - right.correct_childrens_parent_links(count, count + right_len + 1); - - move_edges(left, new_left_len + 1, right, 0, count); - }, - (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { } - _ => { unreachable!(); } - } - } - } - - /// The symmetric clone of `bulk_steal_left`. - pub fn bulk_steal_right(&mut self, count: usize) { - unsafe { - let mut left_node = ptr::read(self).left_edge().descend(); - let left_len = left_node.len(); - let mut right_node = ptr::read(self).right_edge().descend(); - let right_len = right_node.len(); - - // Make sure that we may steal safely. - debug_assert!(left_len + count <= CAPACITY); - debug_assert!(right_len >= count); - - let new_right_len = right_len - count; - - // Move data. - { - let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); - let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); - let parent_kv = { - let kv = self.reborrow_mut().into_kv_mut(); - (kv.0 as *mut K, kv.1 as *mut V) - }; - - // Move parent's key/value pair to the left child. - move_kv(parent_kv, 0, left_kv, left_len, 1); - - // Move elements from the right child to the left one. - move_kv(right_kv, 0, left_kv, left_len + 1, count - 1); - - // Move the right-most stolen pair to the parent. - move_kv(right_kv, count - 1, parent_kv, 0, 1); - - // Fix right indexing - ptr::copy(right_kv.0.offset(count as isize), - right_kv.0, - new_right_len); - ptr::copy(right_kv.1.offset(count as isize), - right_kv.1, - new_right_len); - } - - left_node.reborrow_mut().as_leaf_mut().len += count as u16; - right_node.reborrow_mut().as_leaf_mut().len -= count as u16; - - match (left_node.force(), right_node.force()) { - (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { - move_edges(right.reborrow_mut(), 0, left, left_len + 1, count); - - // Fix right indexing. - let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); - ptr::copy(right_edges.offset(count as isize), - right_edges, - new_right_len + 1); - right.correct_childrens_parent_links(0, new_right_len + 1); - }, - (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { } - _ => { unreachable!(); } - } - } - } -} - -unsafe fn move_kv( - source: (*mut K, *mut V), source_offset: usize, - dest: (*mut K, *mut V), dest_offset: usize, - count: usize) -{ - ptr::copy_nonoverlapping(source.0.offset(source_offset as isize), - dest.0.offset(dest_offset as isize), - count); - ptr::copy_nonoverlapping(source.1.offset(source_offset as isize), - dest.1.offset(dest_offset as isize), - count); -} - -// Source and destination must have the same height. -unsafe fn move_edges( - mut source: NodeRef, source_offset: usize, - mut dest: NodeRef, dest_offset: usize, - count: usize) -{ - let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); - let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); - ptr::copy_nonoverlapping(source_ptr.offset(source_offset as isize), - dest_ptr.offset(dest_offset as isize), - count); - dest.correct_childrens_parent_links(dest_offset, dest_offset + count); -} - -impl - Handle, HandleType> { - - /// Check whether the underlying node is an `Internal` node or a `Leaf` node. - pub fn force(self) -> ForceResult< - Handle, HandleType>, - Handle, HandleType> - > { - match self.node.force() { - ForceResult::Leaf(node) => ForceResult::Leaf(Handle { - node, - idx: self.idx, - _marker: PhantomData - }), - ForceResult::Internal(node) => ForceResult::Internal(Handle { - node, - idx: self.idx, - _marker: PhantomData - }) - } - } -} - -impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { - /// Move the suffix after `self` from one node to another one. `right` must be empty. - /// The first edge of `right` remains unchanged. - pub fn move_suffix(&mut self, - right: &mut NodeRef, K, V, marker::LeafOrInternal>) { - unsafe { - let left_new_len = self.idx; - let mut left_node = self.reborrow_mut().into_node(); - - let right_new_len = left_node.len() - left_new_len; - let mut right_node = right.reborrow_mut(); - - debug_assert!(right_node.len() == 0); - debug_assert!(left_node.height == right_node.height); - - let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); - let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); - - - move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); - - left_node.reborrow_mut().as_leaf_mut().len = left_new_len as u16; - right_node.reborrow_mut().as_leaf_mut().len = right_new_len as u16; - - match (left_node.force(), right_node.force()) { - (ForceResult::Internal(left), ForceResult::Internal(right)) => { - move_edges(left, left_new_len + 1, right, 1, right_new_len); - }, - (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { } - _ => { unreachable!(); } - } - } - } -} - -pub enum ForceResult { - Leaf(Leaf), - Internal(Internal) -} - -pub enum InsertResult<'a, K, V, Type> { - Fit(Handle, K, V, Type>, marker::KV>), - Split(NodeRef, K, V, Type>, K, V, Root) -} - -pub mod marker { - use core::marker::PhantomData; - - pub enum Leaf { } - pub enum Internal { } - pub enum LeafOrInternal { } - - pub enum Owned { } - pub struct Immut<'a>(PhantomData<&'a ()>); - pub struct Mut<'a>(PhantomData<&'a mut ()>); - - pub enum KV { } - pub enum Edge { } -} - -unsafe fn slice_insert(slice: &mut [T], idx: usize, val: T) { - ptr::copy( - slice.as_ptr().offset(idx as isize), - slice.as_mut_ptr().offset(idx as isize + 1), - slice.len() - idx - ); - ptr::write(slice.get_unchecked_mut(idx), val); -} - -unsafe fn slice_remove(slice: &mut [T], idx: usize) -> T { - let ret = ptr::read(slice.get_unchecked(idx)); - ptr::copy( - slice.as_ptr().offset(idx as isize + 1), - slice.as_mut_ptr().offset(idx as isize), - slice.len() - idx - 1 - ); - ret -} diff --git a/src/liballoc/btree/search.rs b/src/liballoc/btree/search.rs deleted file mode 100644 index bc1272fbc78..00000000000 --- a/src/liballoc/btree/search.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::cmp::Ordering; - -use borrow::Borrow; - -use super::node::{Handle, NodeRef, marker}; - -use super::node::ForceResult::*; -use self::SearchResult::*; - -pub enum SearchResult { - Found(Handle, marker::KV>), - GoDown(Handle, marker::Edge>) -} - -pub fn search_tree( - mut node: NodeRef, - key: &Q -) -> SearchResult - where Q: Ord, K: Borrow { - - loop { - match search_node(node, key) { - Found(handle) => return Found(handle), - GoDown(handle) => match handle.force() { - Leaf(leaf) => return GoDown(leaf), - Internal(internal) => { - node = internal.descend(); - continue; - } - } - } - } -} - -pub fn search_node( - node: NodeRef, - key: &Q -) -> SearchResult - where Q: Ord, K: Borrow { - - match search_linear(&node, key) { - (idx, true) => Found( - Handle::new_kv(node, idx) - ), - (idx, false) => SearchResult::GoDown( - Handle::new_edge(node, idx) - ) - } -} - -pub fn search_linear( - node: &NodeRef, - key: &Q -) -> (usize, bool) - where Q: Ord, K: Borrow { - - for (i, k) in node.keys().iter().enumerate() { - match key.cmp(k.borrow()) { - Ordering::Greater => {}, - Ordering::Equal => return (i, true), - Ordering::Less => return (i, false) - } - } - (node.keys().len(), false) -} diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs deleted file mode 100644 index 2aad476d315..00000000000 --- a/src/liballoc/btree/set.rs +++ /dev/null @@ -1,1153 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface -// to TreeMap - -use core::cmp::Ordering::{self, Less, Greater, Equal}; -use core::cmp::{min, max}; -use core::fmt::Debug; -use core::fmt; -use core::iter::{Peekable, FromIterator, FusedIterator}; -use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; - -use borrow::Borrow; -use btree_map::{BTreeMap, Keys}; -use super::Recover; - -// FIXME(conventions): implement bounded iterators - -/// A set based on a B-Tree. -/// -/// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance -/// benefits and drawbacks. -/// -/// It is a logic error for an item to be modified in such a way that the item's ordering relative -/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is -/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. -/// -/// [`BTreeMap`]: struct.BTreeMap.html -/// [`Ord`]: ../../std/cmp/trait.Ord.html -/// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// -/// # Examples -/// -/// ``` -/// use std::collections::BTreeSet; -/// -/// // Type inference lets us omit an explicit type signature (which -/// // would be `BTreeSet<&str>` in this example). -/// let mut books = BTreeSet::new(); -/// -/// // Add some books. -/// books.insert("A Dance With Dragons"); -/// books.insert("To Kill a Mockingbird"); -/// books.insert("The Odyssey"); -/// books.insert("The Great Gatsby"); -/// -/// // Check for a specific one. -/// if !books.contains("The Winds of Winter") { -/// println!("We have {} books, but The Winds of Winter ain't one.", -/// books.len()); -/// } -/// -/// // Remove a book. -/// books.remove("The Odyssey"); -/// -/// // Iterate over everything. -/// for book in &books { -/// println!("{}", book); -/// } -/// ``` -#[derive(Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BTreeSet { - map: BTreeMap, -} - -/// An iterator over the items of a `BTreeSet`. -/// -/// This `struct` is created by the [`iter`] method on [`BTreeSet`]. -/// See its documentation for more. -/// -/// [`BTreeSet`]: struct.BTreeSet.html -/// [`iter`]: struct.BTreeSet.html#method.iter -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - iter: Keys<'a, T, ()>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.iter.clone()) - .finish() - } -} - -/// An owning iterator over the items of a `BTreeSet`. -/// -/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`BTreeSet`]: struct.BTreeSet.html -/// [`into_iter`]: struct.BTreeSet.html#method.into_iter -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug)] -pub struct IntoIter { - iter: ::btree_map::IntoIter, -} - -/// An iterator over a sub-range of items in a `BTreeSet`. -/// -/// This `struct` is created by the [`range`] method on [`BTreeSet`]. -/// See its documentation for more. -/// -/// [`BTreeSet`]: struct.BTreeSet.html -/// [`range`]: struct.BTreeSet.html#method.range -#[derive(Debug)] -#[stable(feature = "btree_range", since = "1.17.0")] -pub struct Range<'a, T: 'a> { - iter: ::btree_map::Range<'a, T, ()>, -} - -/// A lazy iterator producing elements in the difference of `BTreeSet`s. -/// -/// This `struct` is created by the [`difference`] method on [`BTreeSet`]. -/// See its documentation for more. -/// -/// [`BTreeSet`]: struct.BTreeSet.html -/// [`difference`]: struct.BTreeSet.html#method.difference -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Difference<'a, T: 'a> { - a: Peekable>, - b: Peekable>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Difference") - .field(&self.a) - .field(&self.b) - .finish() - } -} - -/// A lazy iterator producing elements in the symmetric difference of `BTreeSet`s. -/// -/// This `struct` is created by the [`symmetric_difference`] method on -/// [`BTreeSet`]. See its documentation for more. -/// -/// [`BTreeSet`]: struct.BTreeSet.html -/// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SymmetricDifference<'a, T: 'a> { - a: Peekable>, - b: Peekable>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("SymmetricDifference") - .field(&self.a) - .field(&self.b) - .finish() - } -} - -/// A lazy iterator producing elements in the intersection of `BTreeSet`s. -/// -/// This `struct` is created by the [`intersection`] method on [`BTreeSet`]. -/// See its documentation for more. -/// -/// [`BTreeSet`]: struct.BTreeSet.html -/// [`intersection`]: struct.BTreeSet.html#method.intersection -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Intersection<'a, T: 'a> { - a: Peekable>, - b: Peekable>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Intersection") - .field(&self.a) - .field(&self.b) - .finish() - } -} - -/// A lazy iterator producing elements in the union of `BTreeSet`s. -/// -/// This `struct` is created by the [`union`] method on [`BTreeSet`]. -/// See its documentation for more. -/// -/// [`BTreeSet`]: struct.BTreeSet.html -/// [`union`]: struct.BTreeSet.html#method.union -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Union<'a, T: 'a> { - a: Peekable>, - b: Peekable>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Union") - .field(&self.a) - .field(&self.b) - .finish() - } -} - -impl BTreeSet { - /// Makes a new `BTreeSet` with a reasonable choice of B. - /// - /// # Examples - /// - /// ``` - /// # #![allow(unused_mut)] - /// use std::collections::BTreeSet; - /// - /// let mut set: BTreeSet = BTreeSet::new(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> BTreeSet { - BTreeSet { map: BTreeMap::new() } - } - - /// Constructs a double-ended iterator over a sub-range of elements in the set. - /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will - /// yield elements from min (inclusive) to max (exclusive). - /// The range may also be entered as `(Bound, Bound)`, so for example - /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive - /// range from 4 to 10. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// use std::ops::Bound::Included; - /// - /// let mut set = BTreeSet::new(); - /// set.insert(3); - /// set.insert(5); - /// set.insert(8); - /// for &elem in set.range((Included(&4), Included(&8))) { - /// println!("{}", elem); - /// } - /// assert_eq!(Some(&5), set.range(4..).next()); - /// ``` - #[stable(feature = "btree_range", since = "1.17.0")] - pub fn range(&self, range: R) -> Range - where K: Ord, T: Borrow, R: RangeBounds - { - Range { iter: self.map.range(range) } - } - - /// Visits the values representing the difference, - /// i.e. the values that are in `self` but not in `other`, - /// in ascending order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut a = BTreeSet::new(); - /// a.insert(1); - /// a.insert(2); - /// - /// let mut b = BTreeSet::new(); - /// b.insert(2); - /// b.insert(3); - /// - /// let diff: Vec<_> = a.difference(&b).cloned().collect(); - /// assert_eq!(diff, [1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn difference<'a>(&'a self, other: &'a BTreeSet) -> Difference<'a, T> { - Difference { - a: self.iter().peekable(), - b: other.iter().peekable(), - } - } - - /// Visits the values representing the symmetric difference, - /// i.e. the values that are in `self` or in `other` but not in both, - /// in ascending order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut a = BTreeSet::new(); - /// a.insert(1); - /// a.insert(2); - /// - /// let mut b = BTreeSet::new(); - /// b.insert(2); - /// b.insert(3); - /// - /// let sym_diff: Vec<_> = a.symmetric_difference(&b).cloned().collect(); - /// assert_eq!(sym_diff, [1, 3]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn symmetric_difference<'a>(&'a self, - other: &'a BTreeSet) - -> SymmetricDifference<'a, T> { - SymmetricDifference { - a: self.iter().peekable(), - b: other.iter().peekable(), - } - } - - /// Visits the values representing the intersection, - /// i.e. the values that are both in `self` and `other`, - /// in ascending order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut a = BTreeSet::new(); - /// a.insert(1); - /// a.insert(2); - /// - /// let mut b = BTreeSet::new(); - /// b.insert(2); - /// b.insert(3); - /// - /// let intersection: Vec<_> = a.intersection(&b).cloned().collect(); - /// assert_eq!(intersection, [2]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn intersection<'a>(&'a self, other: &'a BTreeSet) -> Intersection<'a, T> { - Intersection { - a: self.iter().peekable(), - b: other.iter().peekable(), - } - } - - /// Visits the values representing the union, - /// i.e. all the values in `self` or `other`, without duplicates, - /// in ascending order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut a = BTreeSet::new(); - /// a.insert(1); - /// - /// let mut b = BTreeSet::new(); - /// b.insert(2); - /// - /// let union: Vec<_> = a.union(&b).cloned().collect(); - /// assert_eq!(union, [1, 2]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn union<'a>(&'a self, other: &'a BTreeSet) -> Union<'a, T> { - Union { - a: self.iter().peekable(), - b: other.iter().peekable(), - } - } - - /// Clears the set, removing all values. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut v = BTreeSet::new(); - /// v.insert(1); - /// v.clear(); - /// assert!(v.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn clear(&mut self) { - self.map.clear() - } - - /// Returns `true` if the set contains a value. - /// - /// The value may be any borrowed form of the set's value type, - /// but the ordering on the borrowed form *must* match the - /// ordering on the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert_eq!(set.contains(&1), true); - /// assert_eq!(set.contains(&4), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains(&self, value: &Q) -> bool - where T: Borrow, - Q: Ord - { - self.map.contains_key(value) - } - - /// Returns a reference to the value in the set, if any, that is equal to the given value. - /// - /// The value may be any borrowed form of the set's value type, - /// but the ordering on the borrowed form *must* match the - /// ordering on the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert_eq!(set.get(&2), Some(&2)); - /// assert_eq!(set.get(&4), None); - /// ``` - #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn get(&self, value: &Q) -> Option<&T> - where T: Borrow, - Q: Ord - { - Recover::get(&self.map, value) - } - - /// Returns `true` if `self` has no elements in common with `other`. - /// This is equivalent to checking for an empty intersection. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let a: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let mut b = BTreeSet::new(); - /// - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(4); - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(1); - /// assert_eq!(a.is_disjoint(&b), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_disjoint(&self, other: &BTreeSet) -> bool { - self.intersection(other).next().is_none() - } - - /// Returns `true` if the set is a subset of another, - /// i.e. `other` contains at least all the values in `self`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let sup: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); - /// let mut set = BTreeSet::new(); - /// - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(2); - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(4); - /// assert_eq!(set.is_subset(&sup), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_subset(&self, other: &BTreeSet) -> bool { - // Stolen from TreeMap - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() { - if b.is_none() { - return false; - } - - let a1 = a.unwrap(); - let b1 = b.unwrap(); - - match b1.cmp(a1) { - Less => (), - Greater => return false, - Equal => a = x.next(), - } - - b = y.next(); - } - true - } - - /// Returns `true` if the set is a superset of another, - /// i.e. `self` contains at least all the values in `other`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let sub: BTreeSet<_> = [1, 2].iter().cloned().collect(); - /// let mut set = BTreeSet::new(); - /// - /// assert_eq!(set.is_superset(&sub), false); - /// - /// set.insert(0); - /// set.insert(1); - /// assert_eq!(set.is_superset(&sub), false); - /// - /// set.insert(2); - /// assert_eq!(set.is_superset(&sub), true); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_superset(&self, other: &BTreeSet) -> bool { - other.is_subset(self) - } - - /// Adds a value to the set. - /// - /// If the set did not have this value present, `true` is returned. - /// - /// If the set did have this value present, `false` is returned, and the - /// entry is not updated. See the [module-level documentation] for more. - /// - /// [module-level documentation]: index.html#insert-and-complex-keys - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut set = BTreeSet::new(); - /// - /// assert_eq!(set.insert(2), true); - /// assert_eq!(set.insert(2), false); - /// assert_eq!(set.len(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, value: T) -> bool { - self.map.insert(value, ()).is_none() - } - - /// Adds a value to the set, replacing the existing value, if any, that is equal to the given - /// one. Returns the replaced value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut set = BTreeSet::new(); - /// set.insert(Vec::::new()); - /// - /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); - /// set.replace(Vec::with_capacity(10)); - /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); - /// ``` - #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn replace(&mut self, value: T) -> Option { - Recover::replace(&mut self.map, value) - } - - /// Removes a value from the set. Returns `true` if the value was - /// present in the set. - /// - /// The value may be any borrowed form of the set's value type, - /// but the ordering on the borrowed form *must* match the - /// ordering on the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut set = BTreeSet::new(); - /// - /// set.insert(2); - /// assert_eq!(set.remove(&2), true); - /// assert_eq!(set.remove(&2), false); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, value: &Q) -> bool - where T: Borrow, - Q: Ord - { - self.map.remove(value).is_some() - } - - /// Removes and returns the value in the set, if any, that is equal to the given one. - /// - /// The value may be any borrowed form of the set's value type, - /// but the ordering on the borrowed form *must* match the - /// ordering on the value type. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert_eq!(set.take(&2), Some(2)); - /// assert_eq!(set.take(&2), None); - /// ``` - #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn take(&mut self, value: &Q) -> Option - where T: Borrow, - Q: Ord - { - Recover::take(&mut self.map, value) - } - - /// Moves all elements from `other` into `Self`, leaving `other` empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut a = BTreeSet::new(); - /// a.insert(1); - /// a.insert(2); - /// a.insert(3); - /// - /// let mut b = BTreeSet::new(); - /// b.insert(3); - /// b.insert(4); - /// b.insert(5); - /// - /// a.append(&mut b); - /// - /// assert_eq!(a.len(), 5); - /// assert_eq!(b.len(), 0); - /// - /// assert!(a.contains(&1)); - /// assert!(a.contains(&2)); - /// assert!(a.contains(&3)); - /// assert!(a.contains(&4)); - /// assert!(a.contains(&5)); - /// ``` - #[stable(feature = "btree_append", since = "1.11.0")] - pub fn append(&mut self, other: &mut Self) { - self.map.append(&mut other.map); - } - - /// Splits the collection into two at the given key. Returns everything after the given key, - /// including the key. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut a = BTreeSet::new(); - /// a.insert(1); - /// a.insert(2); - /// a.insert(3); - /// a.insert(17); - /// a.insert(41); - /// - /// let b = a.split_off(&3); - /// - /// assert_eq!(a.len(), 2); - /// assert_eq!(b.len(), 3); - /// - /// assert!(a.contains(&1)); - /// assert!(a.contains(&2)); - /// - /// assert!(b.contains(&3)); - /// assert!(b.contains(&17)); - /// assert!(b.contains(&41)); - /// ``` - #[stable(feature = "btree_split_off", since = "1.11.0")] - pub fn split_off(&mut self, key: &Q) -> Self where T: Borrow { - BTreeSet { map: self.map.split_off(key) } - } -} - -impl BTreeSet { - /// Gets an iterator that visits the values in the `BTreeSet` in ascending order. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let set: BTreeSet = [1, 2, 3].iter().cloned().collect(); - /// let mut set_iter = set.iter(); - /// assert_eq!(set_iter.next(), Some(&1)); - /// assert_eq!(set_iter.next(), Some(&2)); - /// assert_eq!(set_iter.next(), Some(&3)); - /// assert_eq!(set_iter.next(), None); - /// ``` - /// - /// Values returned by the iterator are returned in ascending order: - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let set: BTreeSet = [3, 1, 2].iter().cloned().collect(); - /// let mut set_iter = set.iter(); - /// assert_eq!(set_iter.next(), Some(&1)); - /// assert_eq!(set_iter.next(), Some(&2)); - /// assert_eq!(set_iter.next(), Some(&3)); - /// assert_eq!(set_iter.next(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { iter: self.map.keys() } - } - - /// Returns the number of elements in the set. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut v = BTreeSet::new(); - /// assert_eq!(v.len(), 0); - /// v.insert(1); - /// assert_eq!(v.len(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { - self.map.len() - } - - /// Returns `true` if the set contains no elements. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let mut v = BTreeSet::new(); - /// assert!(v.is_empty()); - /// v.insert(1); - /// assert!(!v.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromIterator for BTreeSet { - fn from_iter>(iter: I) -> BTreeSet { - let mut set = BTreeSet::new(); - set.extend(iter); - set - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for BTreeSet { - type Item = T; - type IntoIter = IntoIter; - - /// Gets an iterator for moving out the `BTreeSet`'s contents. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let set: BTreeSet = [1, 2, 3, 4].iter().cloned().collect(); - /// - /// let v: Vec<_> = set.into_iter().collect(); - /// assert_eq!(v, [1, 2, 3, 4]); - /// ``` - fn into_iter(self) -> IntoIter { - IntoIter { iter: self.map.into_iter() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a BTreeSet { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Extend for BTreeSet { - #[inline] - fn extend>(&mut self, iter: Iter) { - for elem in iter { - self.insert(elem); - } - } -} - -#[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for BTreeSet { - /// Makes an empty `BTreeSet` with a reasonable choice of B. - fn default() -> BTreeSet { - BTreeSet::new() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> Sub<&'b BTreeSet> for &'a BTreeSet { - type Output = BTreeSet; - - /// Returns the difference of `self` and `rhs` as a new `BTreeSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: BTreeSet<_> = vec![3, 4, 5].into_iter().collect(); - /// - /// let result = &a - &b; - /// let result_vec: Vec<_> = result.into_iter().collect(); - /// assert_eq!(result_vec, [1, 2]); - /// ``` - fn sub(self, rhs: &BTreeSet) -> BTreeSet { - self.difference(rhs).cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> BitXor<&'b BTreeSet> for &'a BTreeSet { - type Output = BTreeSet; - - /// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: BTreeSet<_> = vec![2, 3, 4].into_iter().collect(); - /// - /// let result = &a ^ &b; - /// let result_vec: Vec<_> = result.into_iter().collect(); - /// assert_eq!(result_vec, [1, 4]); - /// ``` - fn bitxor(self, rhs: &BTreeSet) -> BTreeSet { - self.symmetric_difference(rhs).cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> BitAnd<&'b BTreeSet> for &'a BTreeSet { - type Output = BTreeSet; - - /// Returns the intersection of `self` and `rhs` as a new `BTreeSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: BTreeSet<_> = vec![2, 3, 4].into_iter().collect(); - /// - /// let result = &a & &b; - /// let result_vec: Vec<_> = result.into_iter().collect(); - /// assert_eq!(result_vec, [2, 3]); - /// ``` - fn bitand(self, rhs: &BTreeSet) -> BTreeSet { - self.intersection(rhs).cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> BitOr<&'b BTreeSet> for &'a BTreeSet { - type Output = BTreeSet; - - /// Returns the union of `self` and `rhs` as a new `BTreeSet`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeSet; - /// - /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); - /// let b: BTreeSet<_> = vec![3, 4, 5].into_iter().collect(); - /// - /// let result = &a | &b; - /// let result_vec: Vec<_> = result.into_iter().collect(); - /// assert_eq!(result_vec, [1, 2, 3, 4, 5]); - /// ``` - fn bitor(self, rhs: &BTreeSet) -> BTreeSet { - self.union(rhs).cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Debug for BTreeSet { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_set().entries(self.iter()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Iter<'a, T> { - Iter { iter: self.iter.clone() } - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Iter<'a, T> { - fn next_back(&mut self) -> Option<&'a T> { - self.iter.next_back() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> { - fn len(&self) -> usize { self.iter.len() } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { - fn next_back(&mut self) -> Option { - self.iter.next_back().map(|(k, _)| k) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { self.iter.len() } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, T> Clone for Range<'a, T> { - fn clone(&self) -> Range<'a, T> { - Range { iter: self.iter.clone() } - } -} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, T> Iterator for Range<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - self.iter.next().map(|(k, _)| k) - } -} - -#[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, T> DoubleEndedIterator for Range<'a, T> { - fn next_back(&mut self) -> Option<&'a T> { - self.iter.next_back().map(|(k, _)| k) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Range<'a, T> {} - -/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None -fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering { - match (x, y) { - (None, _) => short, - (_, None) => long, - (Some(x1), Some(y1)) => x1.cmp(y1), - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Difference<'a, T> { - fn clone(&self) -> Difference<'a, T> { - Difference { - a: self.a.clone(), - b: self.b.clone(), - } - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Ord> Iterator for Difference<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - loop { - match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) { - Less => return self.a.next(), - Equal => { - self.a.next(); - self.b.next(); - } - Greater => { - self.b.next(); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let a_len = self.a.len(); - let b_len = self.b.len(); - (a_len.saturating_sub(b_len), Some(a_len)) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for SymmetricDifference<'a, T> { - fn clone(&self) -> SymmetricDifference<'a, T> { - SymmetricDifference { - a: self.a.clone(), - b: self.b.clone(), - } - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - loop { - match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) { - Less => return self.a.next(), - Equal => { - self.a.next(); - self.b.next(); - } - Greater => return self.b.next(), - } - } - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.a.len() + self.b.len())) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Intersection<'a, T> { - fn clone(&self) -> Intersection<'a, T> { - Intersection { - a: self.a.clone(), - b: self.b.clone(), - } - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Ord> Iterator for Intersection<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - loop { - match Ord::cmp(self.a.peek()?, self.b.peek()?) { - Less => { - self.a.next(); - } - Equal => { - self.b.next(); - return self.a.next(); - } - Greater => { - self.b.next(); - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(min(self.a.len(), self.b.len()))) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Union<'a, T> { - fn clone(&self) -> Union<'a, T> { - Union { - a: self.a.clone(), - b: self.b.clone(), - } - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Ord> Iterator for Union<'a, T> { - type Item = &'a T; - - fn next(&mut self) -> Option<&'a T> { - match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) { - Less => self.a.next(), - Equal => { - self.b.next(); - self.a.next() - } - Greater => self.b.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - let a_len = self.a.len(); - let b_len = self.b.len(); - (max(a_len, b_len), Some(a_len + b_len)) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs new file mode 100644 index 00000000000..fcadcb544c4 --- /dev/null +++ b/src/liballoc/collections/binary_heap.rs @@ -0,0 +1,1196 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A priority queue implemented with a binary heap. +//! +//! Insertion and popping the largest element have `O(log n)` time complexity. +//! Checking the largest element is `O(1)`. Converting a vector to a binary heap +//! can be done in-place, and has `O(n)` complexity. A binary heap can also be +//! converted to a sorted vector in-place, allowing it to be used for an `O(n +//! log n)` in-place heapsort. +//! +//! # Examples +//! +//! This is a larger example that implements [Dijkstra's algorithm][dijkstra] +//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph]. +//! It shows how to use [`BinaryHeap`] with custom types. +//! +//! [dijkstra]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm +//! [sssp]: http://en.wikipedia.org/wiki/Shortest_path_problem +//! [dir_graph]: http://en.wikipedia.org/wiki/Directed_graph +//! [`BinaryHeap`]: struct.BinaryHeap.html +//! +//! ``` +//! use std::cmp::Ordering; +//! use std::collections::BinaryHeap; +//! use std::usize; +//! +//! #[derive(Copy, Clone, Eq, PartialEq)] +//! struct State { +//! cost: usize, +//! position: usize, +//! } +//! +//! // The priority queue depends on `Ord`. +//! // Explicitly implement the trait so the queue becomes a min-heap +//! // instead of a max-heap. +//! impl Ord for State { +//! fn cmp(&self, other: &State) -> Ordering { +//! // Notice that the we flip the ordering on costs. +//! // In case of a tie we compare positions - this step is necessary +//! // to make implementations of `PartialEq` and `Ord` consistent. +//! other.cost.cmp(&self.cost) +//! .then_with(|| self.position.cmp(&other.position)) +//! } +//! } +//! +//! // `PartialOrd` needs to be implemented as well. +//! impl PartialOrd for State { +//! fn partial_cmp(&self, other: &State) -> Option { +//! Some(self.cmp(other)) +//! } +//! } +//! +//! // Each node is represented as an `usize`, for a shorter implementation. +//! struct Edge { +//! node: usize, +//! cost: usize, +//! } +//! +//! // Dijkstra's shortest path algorithm. +//! +//! // Start at `start` and use `dist` to track the current shortest distance +//! // to each node. This implementation isn't memory-efficient as it may leave duplicate +//! // nodes in the queue. It also uses `usize::MAX` as a sentinel value, +//! // for a simpler implementation. +//! fn shortest_path(adj_list: &Vec>, start: usize, goal: usize) -> Option { +//! // dist[node] = current shortest distance from `start` to `node` +//! let mut dist: Vec<_> = (0..adj_list.len()).map(|_| usize::MAX).collect(); +//! +//! let mut heap = BinaryHeap::new(); +//! +//! // We're at `start`, with a zero cost +//! dist[start] = 0; +//! heap.push(State { cost: 0, position: start }); +//! +//! // Examine the frontier with lower cost nodes first (min-heap) +//! while let Some(State { cost, position }) = heap.pop() { +//! // Alternatively we could have continued to find all shortest paths +//! if position == goal { return Some(cost); } +//! +//! // Important as we may have already found a better way +//! if cost > dist[position] { continue; } +//! +//! // For each node we can reach, see if we can find a way with +//! // a lower cost going through this node +//! for edge in &adj_list[position] { +//! let next = State { cost: cost + edge.cost, position: edge.node }; +//! +//! // If so, add it to the frontier and continue +//! if next.cost < dist[next.position] { +//! heap.push(next); +//! // Relaxation, we have now found a better way +//! dist[next.position] = next.cost; +//! } +//! } +//! } +//! +//! // Goal not reachable +//! None +//! } +//! +//! fn main() { +//! // This is the directed graph we're going to use. +//! // The node numbers correspond to the different states, +//! // and the edge weights symbolize the cost of moving +//! // from one node to another. +//! // Note that the edges are one-way. +//! // +//! // 7 +//! // +-----------------+ +//! // | | +//! // v 1 2 | 2 +//! // 0 -----> 1 -----> 3 ---> 4 +//! // | ^ ^ ^ +//! // | | 1 | | +//! // | | | 3 | 1 +//! // +------> 2 -------+ | +//! // 10 | | +//! // +---------------+ +//! // +//! // The graph is represented as an adjacency list where each index, +//! // corresponding to a node value, has a list of outgoing edges. +//! // Chosen for its efficiency. +//! let graph = vec![ +//! // Node 0 +//! vec![Edge { node: 2, cost: 10 }, +//! Edge { node: 1, cost: 1 }], +//! // Node 1 +//! vec![Edge { node: 3, cost: 2 }], +//! // Node 2 +//! vec![Edge { node: 1, cost: 1 }, +//! Edge { node: 3, cost: 3 }, +//! Edge { node: 4, cost: 1 }], +//! // Node 3 +//! vec![Edge { node: 0, cost: 7 }, +//! Edge { node: 4, cost: 2 }], +//! // Node 4 +//! vec![]]; +//! +//! assert_eq!(shortest_path(&graph, 0, 1), Some(1)); +//! assert_eq!(shortest_path(&graph, 0, 3), Some(3)); +//! assert_eq!(shortest_path(&graph, 3, 0), Some(7)); +//! assert_eq!(shortest_path(&graph, 0, 4), Some(5)); +//! assert_eq!(shortest_path(&graph, 4, 0), None); +//! } +//! ``` + +#![allow(missing_docs)] +#![stable(feature = "rust1", since = "1.0.0")] + +use core::ops::{Deref, DerefMut}; +use core::iter::{FromIterator, FusedIterator}; +use core::mem::{swap, size_of, ManuallyDrop}; +use core::ptr; +use core::fmt; + +use slice; +use vec::{self, Vec}; + +use super::SpecExtend; + +/// A priority queue implemented with a binary heap. +/// +/// This will be a max-heap. +/// +/// It is a logic error for an item to be modified in such a way that the +/// item's ordering relative to any other item, as determined by the `Ord` +/// trait, changes while it is in the heap. This is normally only possible +/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. +/// +/// # Examples +/// +/// ``` +/// use std::collections::BinaryHeap; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `BinaryHeap` in this example). +/// let mut heap = BinaryHeap::new(); +/// +/// // We can use peek to look at the next item in the heap. In this case, +/// // there's no items in there yet so we get None. +/// assert_eq!(heap.peek(), None); +/// +/// // Let's add some scores... +/// heap.push(1); +/// heap.push(5); +/// heap.push(2); +/// +/// // Now peek shows the most important item in the heap. +/// assert_eq!(heap.peek(), Some(&5)); +/// +/// // We can check the length of a heap. +/// assert_eq!(heap.len(), 3); +/// +/// // We can iterate over the items in the heap, although they are returned in +/// // a random order. +/// for x in &heap { +/// println!("{}", x); +/// } +/// +/// // If we instead pop these scores, they should come back in order. +/// assert_eq!(heap.pop(), Some(5)); +/// assert_eq!(heap.pop(), Some(2)); +/// assert_eq!(heap.pop(), Some(1)); +/// assert_eq!(heap.pop(), None); +/// +/// // We can clear the heap of any remaining items. +/// heap.clear(); +/// +/// // The heap should now be empty. +/// assert!(heap.is_empty()) +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BinaryHeap { + data: Vec, +} + +/// Structure wrapping a mutable reference to the greatest item on a +/// `BinaryHeap`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See +/// its documentation for more. +/// +/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut +/// [`BinaryHeap`]: struct.BinaryHeap.html +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] +pub struct PeekMut<'a, T: 'a + Ord> { + heap: &'a mut BinaryHeap, + sift: bool, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: Ord + fmt::Debug> fmt::Debug for PeekMut<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("PeekMut") + .field(&self.heap.data[0]) + .finish() + } +} + +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] +impl<'a, T: Ord> Drop for PeekMut<'a, T> { + fn drop(&mut self) { + if self.sift { + self.heap.sift_down(0); + } + } +} + +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] +impl<'a, T: Ord> Deref for PeekMut<'a, T> { + type Target = T; + fn deref(&self) -> &T { + &self.heap.data[0] + } +} + +#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] +impl<'a, T: Ord> DerefMut for PeekMut<'a, T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.heap.data[0] + } +} + +impl<'a, T: Ord> PeekMut<'a, T> { + /// Removes the peeked value from the heap and returns it. + #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")] + pub fn pop(mut this: PeekMut<'a, T>) -> T { + let value = this.heap.pop().unwrap(); + this.sift = false; + value + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for BinaryHeap { + fn clone(&self) -> Self { + BinaryHeap { data: self.data.clone() } + } + + fn clone_from(&mut self, source: &Self) { + self.data.clone_from(&source.data); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for BinaryHeap { + /// Creates an empty `BinaryHeap`. + #[inline] + fn default() -> BinaryHeap { + BinaryHeap::new() + } +} + +#[stable(feature = "binaryheap_debug", since = "1.4.0")] +impl fmt::Debug for BinaryHeap { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl BinaryHeap { + /// Creates an empty `BinaryHeap` as a max-heap. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new(); + /// heap.push(4); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> BinaryHeap { + BinaryHeap { data: vec![] } + } + + /// Creates an empty `BinaryHeap` with a specific capacity. + /// This preallocates enough memory for `capacity` elements, + /// so that the `BinaryHeap` does not have to be reallocated + /// until it contains at least that many values. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::with_capacity(10); + /// heap.push(4); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize) -> BinaryHeap { + BinaryHeap { data: Vec::with_capacity(capacity) } + } + + /// Returns an iterator visiting all values in the underlying vector, in + /// arbitrary order. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); + /// + /// // Print 1, 2, 3, 4 in arbitrary order + /// for x in heap.iter() { + /// println!("{}", x); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter { + Iter { iter: self.data.iter() } + } + + /// Returns the greatest item in the binary heap, or `None` if it is empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new(); + /// assert_eq!(heap.peek(), None); + /// + /// heap.push(1); + /// heap.push(5); + /// heap.push(2); + /// assert_eq!(heap.peek(), Some(&5)); + /// + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn peek(&self) -> Option<&T> { + self.data.get(0) + } + + /// Returns a mutable reference to the greatest item in the binary heap, or + /// `None` if it is empty. + /// + /// Note: If the `PeekMut` value is leaked, the heap may be in an + /// inconsistent state. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new(); + /// assert!(heap.peek_mut().is_none()); + /// + /// heap.push(1); + /// heap.push(5); + /// heap.push(2); + /// { + /// let mut val = heap.peek_mut().unwrap(); + /// *val = 0; + /// } + /// assert_eq!(heap.peek(), Some(&2)); + /// ``` + #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] + pub fn peek_mut(&mut self) -> Option> { + if self.is_empty() { + None + } else { + Some(PeekMut { + heap: self, + sift: true, + }) + } + } + + /// Returns the number of elements the binary heap can hold without reallocating. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::with_capacity(100); + /// assert!(heap.capacity() >= 100); + /// heap.push(4); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn capacity(&self) -> usize { + self.data.capacity() + } + + /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the + /// given `BinaryHeap`. Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it requests. Therefore + /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future + /// insertions are expected. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new(); + /// heap.reserve_exact(100); + /// assert!(heap.capacity() >= 100); + /// heap.push(4); + /// ``` + /// + /// [`reserve`]: #method.reserve + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve_exact(&mut self, additional: usize) { + self.data.reserve_exact(additional); + } + + /// Reserves capacity for at least `additional` more elements to be inserted in the + /// `BinaryHeap`. The collection may reserve more space to avoid frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new(); + /// heap.reserve(100); + /// assert!(heap.capacity() >= 100); + /// heap.push(4); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve(&mut self, additional: usize) { + self.data.reserve(additional); + } + + /// Discards as much additional capacity as possible. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap: BinaryHeap = BinaryHeap::with_capacity(100); + /// + /// assert!(heap.capacity() >= 100); + /// heap.shrink_to_fit(); + /// assert!(heap.capacity() == 0); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn shrink_to_fit(&mut self) { + self.data.shrink_to_fit(); + } + + /// Discards capacity with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::BinaryHeap; + /// let mut heap: BinaryHeap = BinaryHeap::with_capacity(100); + /// + /// assert!(heap.capacity() >= 100); + /// heap.shrink_to(10); + /// assert!(heap.capacity() >= 10); + /// ``` + #[inline] + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.data.shrink_to(min_capacity) + } + + /// Removes the greatest item from the binary heap and returns it, or `None` if it + /// is empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::from(vec![1, 3]); + /// + /// assert_eq!(heap.pop(), Some(3)); + /// assert_eq!(heap.pop(), Some(1)); + /// assert_eq!(heap.pop(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop(&mut self) -> Option { + self.data.pop().map(|mut item| { + if !self.is_empty() { + swap(&mut item, &mut self.data[0]); + self.sift_down_to_bottom(0); + } + item + }) + } + + /// Pushes an item onto the binary heap. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new(); + /// heap.push(3); + /// heap.push(5); + /// heap.push(1); + /// + /// assert_eq!(heap.len(), 3); + /// assert_eq!(heap.peek(), Some(&5)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn push(&mut self, item: T) { + let old_len = self.len(); + self.data.push(item); + self.sift_up(0, old_len); + } + + /// Consumes the `BinaryHeap` and returns the underlying vector + /// in arbitrary order. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]); + /// let vec = heap.into_vec(); + /// + /// // Will print in some order + /// for x in vec { + /// println!("{}", x); + /// } + /// ``` + #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] + pub fn into_vec(self) -> Vec { + self.into() + } + + /// Consumes the `BinaryHeap` and returns a vector in sorted + /// (ascending) order. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// + /// let mut heap = BinaryHeap::from(vec![1, 2, 4, 5, 7]); + /// heap.push(6); + /// heap.push(3); + /// + /// let vec = heap.into_sorted_vec(); + /// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]); + /// ``` + #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] + pub fn into_sorted_vec(mut self) -> Vec { + let mut end = self.len(); + while end > 1 { + end -= 1; + self.data.swap(0, end); + self.sift_down_range(0, end); + } + self.into_vec() + } + + // The implementations of sift_up and sift_down use unsafe blocks in + // order to move an element out of the vector (leaving behind a + // hole), shift along the others and move the removed element back into the + // vector at the final location of the hole. + // The `Hole` type is used to represent this, and make sure + // the hole is filled back at the end of its scope, even on panic. + // Using a hole reduces the constant factor compared to using swaps, + // which involves twice as many moves. + fn sift_up(&mut self, start: usize, pos: usize) -> usize { + unsafe { + // Take out the value at `pos` and create a hole. + let mut hole = Hole::new(&mut self.data, pos); + + while hole.pos() > start { + let parent = (hole.pos() - 1) / 2; + if hole.element() <= hole.get(parent) { + break; + } + hole.move_to(parent); + } + hole.pos() + } + } + + /// Take an element at `pos` and move it down the heap, + /// while its children are larger. + fn sift_down_range(&mut self, pos: usize, end: usize) { + unsafe { + let mut hole = Hole::new(&mut self.data, pos); + let mut child = 2 * pos + 1; + while child < end { + let right = child + 1; + // compare with the greater of the two children + if right < end && !(hole.get(child) > hole.get(right)) { + child = right; + } + // if we are already in order, stop. + if hole.element() >= hole.get(child) { + break; + } + hole.move_to(child); + child = 2 * hole.pos() + 1; + } + } + } + + fn sift_down(&mut self, pos: usize) { + let len = self.len(); + self.sift_down_range(pos, len); + } + + /// Take an element at `pos` and move it all the way down the heap, + /// then sift it up to its position. + /// + /// Note: This is faster when the element is known to be large / should + /// be closer to the bottom. + fn sift_down_to_bottom(&mut self, mut pos: usize) { + let end = self.len(); + let start = pos; + unsafe { + let mut hole = Hole::new(&mut self.data, pos); + let mut child = 2 * pos + 1; + while child < end { + let right = child + 1; + // compare with the greater of the two children + if right < end && !(hole.get(child) > hole.get(right)) { + child = right; + } + hole.move_to(child); + child = 2 * hole.pos() + 1; + } + pos = hole.pos; + } + self.sift_up(start, pos); + } + + /// Returns the length of the binary heap. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let heap = BinaryHeap::from(vec![1, 3]); + /// + /// assert_eq!(heap.len(), 2); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { + self.data.len() + } + + /// Checks if the binary heap is empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::new(); + /// + /// assert!(heap.is_empty()); + /// + /// heap.push(3); + /// heap.push(5); + /// heap.push(1); + /// + /// assert!(!heap.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the binary heap, returning an iterator over the removed elements. + /// + /// The elements are removed in arbitrary order. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::from(vec![1, 3]); + /// + /// assert!(!heap.is_empty()); + /// + /// for x in heap.drain() { + /// println!("{}", x); + /// } + /// + /// assert!(heap.is_empty()); + /// ``` + #[inline] + #[stable(feature = "drain", since = "1.6.0")] + pub fn drain(&mut self) -> Drain { + Drain { iter: self.data.drain(..) } + } + + /// Drops all items from the binary heap. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let mut heap = BinaryHeap::from(vec![1, 3]); + /// + /// assert!(!heap.is_empty()); + /// + /// heap.clear(); + /// + /// assert!(heap.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { + self.drain(); + } + + fn rebuild(&mut self) { + let mut n = self.len() / 2; + while n > 0 { + n -= 1; + self.sift_down(n); + } + } + + /// Moves all the elements of `other` into `self`, leaving `other` empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// + /// let v = vec![-10, 1, 2, 3, 3]; + /// let mut a = BinaryHeap::from(v); + /// + /// let v = vec![-20, 5, 43]; + /// let mut b = BinaryHeap::from(v); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); + /// assert!(b.is_empty()); + /// ``` + #[stable(feature = "binary_heap_append", since = "1.11.0")] + pub fn append(&mut self, other: &mut Self) { + if self.len() < other.len() { + swap(self, other); + } + + if other.is_empty() { + return; + } + + #[inline(always)] + fn log2_fast(x: usize) -> usize { + 8 * size_of::() - (x.leading_zeros() as usize) - 1 + } + + // `rebuild` takes O(len1 + len2) operations + // and about 2 * (len1 + len2) comparisons in the worst case + // while `extend` takes O(len2 * log_2(len1)) operations + // and about 1 * len2 * log_2(len1) comparisons in the worst case, + // assuming len1 >= len2. + #[inline] + fn better_to_rebuild(len1: usize, len2: usize) -> bool { + 2 * (len1 + len2) < len2 * log2_fast(len1) + } + + if better_to_rebuild(self.len(), other.len()) { + self.data.append(&mut other.data); + self.rebuild(); + } else { + self.extend(other.drain()); + } + } +} + +/// Hole represents a hole in a slice i.e. an index without valid value +/// (because it was moved from or duplicated). +/// In drop, `Hole` will restore the slice by filling the hole +/// position with the value that was originally removed. +struct Hole<'a, T: 'a> { + data: &'a mut [T], + elt: ManuallyDrop, + pos: usize, +} + +impl<'a, T> Hole<'a, T> { + /// Create a new Hole at index `pos`. + /// + /// Unsafe because pos must be within the data slice. + #[inline] + unsafe fn new(data: &'a mut [T], pos: usize) -> Self { + debug_assert!(pos < data.len()); + let elt = ptr::read(&data[pos]); + Hole { + data, + elt: ManuallyDrop::new(elt), + pos, + } + } + + #[inline] + fn pos(&self) -> usize { + self.pos + } + + /// Returns a reference to the element removed. + #[inline] + fn element(&self) -> &T { + &self.elt + } + + /// Returns a reference to the element at `index`. + /// + /// Unsafe because index must be within the data slice and not equal to pos. + #[inline] + unsafe fn get(&self, index: usize) -> &T { + debug_assert!(index != self.pos); + debug_assert!(index < self.data.len()); + self.data.get_unchecked(index) + } + + /// Move hole to new location + /// + /// Unsafe because index must be within the data slice and not equal to pos. + #[inline] + unsafe fn move_to(&mut self, index: usize) { + debug_assert!(index != self.pos); + debug_assert!(index < self.data.len()); + let index_ptr: *const _ = self.data.get_unchecked(index); + let hole_ptr = self.data.get_unchecked_mut(self.pos); + ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + self.pos = index; + } +} + +impl<'a, T> Drop for Hole<'a, T> { + #[inline] + fn drop(&mut self) { + // fill the hole again + unsafe { + let pos = self.pos; + ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1); + } + } +} + +/// An iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.BinaryHeap.html#method.iter +/// [`BinaryHeap`]: struct.BinaryHeap.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + iter: slice::Iter<'a, T>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Iter") + .field(&self.iter.as_slice()) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for Iter<'a, T> { + fn clone(&self) -> Iter<'a, T> { + Iter { iter: self.iter.clone() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a T> { + self.iter.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + +/// An owning iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter +/// [`BinaryHeap`]: struct.BinaryHeap.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct IntoIter { + iter: vec::IntoIter, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IntoIter") + .field(&self.iter.as_slice()) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +/// A draining iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.BinaryHeap.html#method.drain +/// [`BinaryHeap`]: struct.BinaryHeap.html +#[stable(feature = "drain", since = "1.6.0")] +#[derive(Debug)] +pub struct Drain<'a, T: 'a> { + iter: vec::Drain<'a, T>, +} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, T: 'a> Iterator for Drain<'a, T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} + +#[stable(feature = "binary_heap_extras_15", since = "1.5.0")] +impl From> for BinaryHeap { + fn from(vec: Vec) -> BinaryHeap { + let mut heap = BinaryHeap { data: vec }; + heap.rebuild(); + heap + } +} + +#[stable(feature = "binary_heap_extras_15", since = "1.5.0")] +impl From> for Vec { + fn from(heap: BinaryHeap) -> Vec { + heap.data + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator for BinaryHeap { + fn from_iter>(iter: I) -> BinaryHeap { + BinaryHeap::from(iter.into_iter().collect::>()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for BinaryHeap { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out of + /// the binary heap in arbitrary order. The binary heap cannot be used + /// after calling this. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BinaryHeap; + /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]); + /// + /// // Print 1, 2, 3, 4 in arbitrary order + /// for x in heap.into_iter() { + /// // x has type i32, not &i32 + /// println!("{}", x); + /// } + /// ``` + fn into_iter(self) -> IntoIter { + IntoIter { iter: self.data.into_iter() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a BinaryHeap + where T: Ord +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend for BinaryHeap { + #[inline] + fn extend>(&mut self, iter: I) { + >::spec_extend(self, iter); + } +} + +impl> SpecExtend for BinaryHeap { + default fn spec_extend(&mut self, iter: I) { + self.extend_desugared(iter.into_iter()); + } +} + +impl SpecExtend> for BinaryHeap { + fn spec_extend(&mut self, ref mut other: BinaryHeap) { + self.append(other); + } +} + +impl BinaryHeap { + fn extend_desugared>(&mut self, iter: I) { + let iterator = iter.into_iter(); + let (lower, _) = iterator.size_hint(); + + self.reserve(lower); + + for elem in iterator { + self.push(elem); + } + } +} + +#[stable(feature = "extend_ref", since = "1.2.0")] +impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } +} diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs new file mode 100644 index 00000000000..e6e454446e2 --- /dev/null +++ b/src/liballoc/collections/btree/map.rs @@ -0,0 +1,2578 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::cmp::Ordering; +use core::fmt::Debug; +use core::hash::{Hash, Hasher}; +use core::iter::{FromIterator, Peekable, FusedIterator}; +use core::marker::PhantomData; +use core::ops::Bound::{Excluded, Included, Unbounded}; +use core::ops::Index; +use core::ops::RangeBounds; +use core::{fmt, intrinsics, mem, ptr}; + +use borrow::Borrow; + +use super::node::{self, Handle, NodeRef, marker}; +use super::search; + +use super::node::InsertResult::*; +use super::node::ForceResult::*; +use super::search::SearchResult::*; +use self::UnderflowResult::*; +use self::Entry::*; + +/// A map based on a B-Tree. +/// +/// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing +/// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal +/// choice for a sorted map, as a perfectly balanced BST performs the theoretical minimum amount of +/// comparisons necessary to find an element (log2n). However, in practice the way this +/// is done is *very* inefficient for modern computer architectures. In particular, every element +/// is stored in its own individually heap-allocated node. This means that every single insertion +/// triggers a heap-allocation, and every single comparison should be a cache-miss. Since these +/// are both notably expensive things to do in practice, we are forced to at very least reconsider +/// the BST strategy. +/// +/// A B-Tree instead makes each node contain B-1 to 2B-1 elements in a contiguous array. By doing +/// this, we reduce the number of allocations by a factor of B, and improve cache efficiency in +/// searches. However, this does mean that searches will have to do *more* comparisons on average. +/// The precise number of comparisons depends on the node search strategy used. For optimal cache +/// efficiency, one could search the nodes linearly. For optimal comparisons, one could search +/// the node using binary search. As a compromise, one could also perform a linear search +/// that initially only checks every ith element for some choice of i. +/// +/// Currently, our implementation simply performs naive linear search. This provides excellent +/// performance on *small* nodes of elements which are cheap to compare. However in the future we +/// would like to further explore choosing the optimal search strategy based on the choice of B, +/// and possibly other factors. Using linear search, searching for a random element is expected +/// to take O(B logBn) comparisons, which is generally worse than a BST. In practice, +/// however, performance is excellent. +/// +/// It is a logic error for a key to be modified in such a way that the key's ordering relative to +/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// [`Ord`]: ../../std/cmp/trait.Ord.html +/// [`Cell`]: ../../std/cell/struct.Cell.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// +/// # Examples +/// +/// ``` +/// use std::collections::BTreeMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `BTreeMap<&str, &str>` in this example). +/// let mut movie_reviews = BTreeMap::new(); +/// +/// // review some movies. +/// movie_reviews.insert("Office Space", "Deals with real issues in the workplace."); +/// movie_reviews.insert("Pulp Fiction", "Masterpiece."); +/// movie_reviews.insert("The Godfather", "Very enjoyable."); +/// movie_reviews.insert("The Blues Brothers", "Eye lyked it alot."); +/// +/// // check for a specific one. +/// if !movie_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// movie_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// movie_reviews.remove("The Blues Brothers"); +/// +/// // look up the values associated with some keys. +/// let to_find = ["Up!", "Office Space"]; +/// for book in &to_find { +/// match movie_reviews.get(book) { +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) +/// } +/// } +/// +/// // iterate over everything. +/// for (movie, review) in &movie_reviews { +/// println!("{}: \"{}\"", movie, review); +/// } +/// ``` +/// +/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows +/// for more complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use std::collections::BTreeMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `BTreeMap<&str, u8>` in this example). +/// let mut player_stats = BTreeMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BTreeMap { + root: node::Root, + length: usize, +} + +#[stable(feature = "btree_drop", since = "1.7.0")] +unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap { + fn drop(&mut self) { + unsafe { + drop(ptr::read(self).into_iter()); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for BTreeMap { + fn clone(&self) -> BTreeMap { + fn clone_subtree(node: node::NodeRef) + -> BTreeMap { + + match node.force() { + Leaf(leaf) => { + let mut out_tree = BTreeMap { + root: node::Root::new_leaf(), + length: 0, + }; + + { + let mut out_node = match out_tree.root.as_mut().force() { + Leaf(leaf) => leaf, + Internal(_) => unreachable!(), + }; + + let mut in_edge = leaf.first_edge(); + while let Ok(kv) = in_edge.right_kv() { + let (k, v) = kv.into_kv(); + in_edge = kv.right_edge(); + + out_node.push(k.clone(), v.clone()); + out_tree.length += 1; + } + } + + out_tree + } + Internal(internal) => { + let mut out_tree = clone_subtree(internal.first_edge().descend()); + + { + let mut out_node = out_tree.root.push_level(); + let mut in_edge = internal.first_edge(); + while let Ok(kv) = in_edge.right_kv() { + let (k, v) = kv.into_kv(); + in_edge = kv.right_edge(); + + let k = (*k).clone(); + let v = (*v).clone(); + let subtree = clone_subtree(in_edge.descend()); + + // We can't destructure subtree directly + // because BTreeMap implements Drop + let (subroot, sublength) = unsafe { + let root = ptr::read(&subtree.root); + let length = subtree.length; + mem::forget(subtree); + (root, length) + }; + + out_node.push(k, v, subroot); + out_tree.length += 1 + sublength; + } + } + + out_tree + } + } + } + + clone_subtree(self.root.as_ref()) + } +} + +impl super::Recover for BTreeMap + where K: Borrow + Ord, + Q: Ord +{ + type Key = K; + + fn get(&self, key: &Q) -> Option<&K> { + match search::search_tree(self.root.as_ref(), key) { + Found(handle) => Some(handle.into_kv().0), + GoDown(_) => None, + } + } + + fn take(&mut self, key: &Q) -> Option { + match search::search_tree(self.root.as_mut(), key) { + Found(handle) => { + Some(OccupiedEntry { + handle, + length: &mut self.length, + _marker: PhantomData, + } + .remove_kv() + .0) + } + GoDown(_) => None, + } + } + + fn replace(&mut self, key: K) -> Option { + self.ensure_root_is_owned(); + match search::search_tree::(self.root.as_mut(), &key) { + Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)), + GoDown(handle) => { + VacantEntry { + key, + handle, + length: &mut self.length, + _marker: PhantomData, + } + .insert(()); + None + } + } + } +} + +/// An iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`iter`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.BTreeMap.html#method.iter +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, K: 'a, V: 'a> { + range: Range<'a, K, V>, + length: usize, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Iter<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.BTreeMap.html#method.iter_mut +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +pub struct IterMut<'a, K: 'a, V: 'a> { + range: RangeMut<'a, K, V>, + length: usize, +} + +/// An owning iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.BTreeMap.html#method.into_iter +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter { + front: Handle, marker::Edge>, + back: Handle, marker::Edge>, + length: usize, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let range = Range { + front: self.front.reborrow(), + back: self.back.reborrow(), + }; + f.debug_list().entries(range).finish() + } +} + +/// An iterator over the keys of a `BTreeMap`. +/// +/// This `struct` is created by the [`keys`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.BTreeMap.html#method.keys +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Keys<'a, K: 'a, V: 'a> { + inner: Iter<'a, K, V>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, K: 'a + fmt::Debug, V: 'a> fmt::Debug for Keys<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the values of a `BTreeMap`. +/// +/// This `struct` is created by the [`values`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.BTreeMap.html#method.values +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Values<'a, K: 'a, V: 'a> { + inner: Iter<'a, K, V>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, K: 'a, V: 'a + fmt::Debug> fmt::Debug for Values<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the values of a `BTreeMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.BTreeMap.html#method.values_mut +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "map_values_mut", since = "1.10.0")] +#[derive(Debug)] +pub struct ValuesMut<'a, K: 'a, V: 'a> { + inner: IterMut<'a, K, V>, +} + +/// An iterator over a sub-range of entries in a `BTreeMap`. +/// +/// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`range`]: struct.BTreeMap.html#method.range +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "btree_range", since = "1.17.0")] +pub struct Range<'a, K: 'a, V: 'a> { + front: Handle, K, V, marker::Leaf>, marker::Edge>, + back: Handle, K, V, marker::Leaf>, marker::Edge>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over a sub-range of entries in a `BTreeMap`. +/// +/// This `struct` is created by the [`range_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`range_mut`]: struct.BTreeMap.html#method.range_mut +/// [`BTreeMap`]: struct.BTreeMap.html +#[stable(feature = "btree_range", since = "1.17.0")] +pub struct RangeMut<'a, K: 'a, V: 'a> { + front: Handle, K, V, marker::Leaf>, marker::Edge>, + back: Handle, K, V, marker::Leaf>, marker::Edge>, + + // Be invariant in `K` and `V` + _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for RangeMut<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let range = Range { + front: self.front.reborrow(), + back: self.back.reborrow(), + }; + f.debug_list().entries(range).finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. +/// +/// [`BTreeMap`]: struct.BTreeMap.html +/// [`entry`]: struct.BTreeMap.html#method.entry +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Entry<'a, K: 'a, V: 'a> { + /// A vacant entry. + #[stable(feature = "rust1", since = "1.0.0")] + Vacant(#[stable(feature = "rust1", since = "1.0.0")] + VacantEntry<'a, K, V>), + + /// An occupied entry. + #[stable(feature = "rust1", since = "1.0.0")] + Occupied(#[stable(feature = "rust1", since = "1.0.0")] + OccupiedEntry<'a, K, V>), +} + +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry") + .field(v) + .finish(), + Occupied(ref o) => f.debug_tuple("Entry") + .field(o) + .finish(), + } + } +} + +/// A view into a vacant entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct VacantEntry<'a, K: 'a, V: 'a> { + key: K, + handle: Handle, K, V, marker::Leaf>, marker::Edge>, + length: &'a mut usize, + + // Be invariant in `K` and `V` + _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("VacantEntry") + .field(self.key()) + .finish() + } +} + +/// A view into an occupied entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, + + length: &'a mut usize, + + // Be invariant in `K` and `V` + _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +// An iterator for merging two sorted sequences into one +struct MergeIter> { + left: Peekable, + right: Peekable, +} + +impl BTreeMap { + /// Makes a new empty BTreeMap with a reasonable choice for B. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// + /// // entries can now be inserted into the empty map + /// map.insert(1, "a"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> BTreeMap { + BTreeMap { + root: node::Root::shared_empty_root(), + length: 0, + } + } + + /// Clears the map, removing all values. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "a"); + /// a.clear(); + /// assert!(a.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { + *self = BTreeMap::new(); + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self, key: &Q) -> Option<&V> + where K: Borrow, + Q: Ord + { + match search::search_tree(self.root.as_ref(), key) { + Found(handle) => Some(handle.into_kv().1), + GoDown(_) => None, + } + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_get_key_value)] + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[unstable(feature = "map_get_key_value", issue = "49347")] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where K: Borrow, + Q: Ord + { + match search::search_tree(self.root.as_ref(), k) { + Found(handle) => Some(handle.into_kv()), + GoDown(_) => None, + } + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn contains_key(&self, key: &Q) -> bool + where K: Borrow, + Q: Ord + { + self.get(key).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// ``` + // See `get` for implementation notes, this is basically a copy-paste with mut's added + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + where K: Borrow, + Q: Ord + { + match search::search_tree(self.root.as_mut(), key) { + Found(handle) => Some(handle.into_kv_mut().1), + GoDown(_) => None, + } + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [module-level + /// documentation] for more. + /// + /// [module-level documentation]: index.html#insert-and-complex-keys + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, key: K, value: V) -> Option { + match self.entry(key) { + Occupied(mut entry) => Some(entry.insert(value)), + Vacant(entry) => { + entry.insert(value); + None + } + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(&mut self, key: &Q) -> Option + where K: Borrow, + Q: Ord + { + match search::search_tree(self.root.as_mut(), key) { + Found(handle) => { + Some(OccupiedEntry { + handle, + length: &mut self.length, + _marker: PhantomData, + } + .remove()) + } + GoDown(_) => None, + } + } + + /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// + /// let mut b = BTreeMap::new(); + /// b.insert(3, "d"); + /// b.insert(4, "e"); + /// b.insert(5, "f"); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 5); + /// assert_eq!(b.len(), 0); + /// + /// assert_eq!(a[&1], "a"); + /// assert_eq!(a[&2], "b"); + /// assert_eq!(a[&3], "d"); + /// assert_eq!(a[&4], "e"); + /// assert_eq!(a[&5], "f"); + /// ``` + #[stable(feature = "btree_append", since = "1.11.0")] + pub fn append(&mut self, other: &mut Self) { + // Do we have to append anything at all? + if other.len() == 0 { + return; + } + + // We can just swap `self` and `other` if `self` is empty. + if self.len() == 0 { + mem::swap(self, other); + return; + } + + // First, we merge `self` and `other` into a sorted sequence in linear time. + let self_iter = mem::replace(self, BTreeMap::new()).into_iter(); + let other_iter = mem::replace(other, BTreeMap::new()).into_iter(); + let iter = MergeIter { + left: self_iter.peekable(), + right: other_iter.peekable(), + }; + + // Second, we build a tree from the sorted sequence in linear time. + self.from_sorted_iter(iter); + self.fix_right_edge(); + } + + /// Constructs a double-ended iterator over a sub-range of elements in the map. + /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will + /// yield elements from min (inclusive) to max (exclusive). + /// The range may also be entered as `(Bound, Bound)`, so for example + /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive + /// range from 4 to 10. + /// + /// # Panics + /// + /// Panics if range `start > end`. + /// Panics if range `start == end` and both bounds are `Excluded`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::ops::Bound::Included; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(3, "a"); + /// map.insert(5, "b"); + /// map.insert(8, "c"); + /// for (&key, &value) in map.range((Included(&4), Included(&8))) { + /// println!("{}: {}", key, value); + /// } + /// assert_eq!(Some((&5, &"b")), map.range(4..).next()); + /// ``` + #[stable(feature = "btree_range", since = "1.17.0")] + pub fn range(&self, range: R) -> Range + where T: Ord, K: Borrow, R: RangeBounds + { + let root1 = self.root.as_ref(); + let root2 = self.root.as_ref(); + let (f, b) = range_search(root1, root2, range); + + Range { front: f, back: b} + } + + /// Constructs a mutable double-ended iterator over a sub-range of elements in the map. + /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will + /// yield elements from min (inclusive) to max (exclusive). + /// The range may also be entered as `(Bound, Bound)`, so for example + /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive + /// range from 4 to 10. + /// + /// # Panics + /// + /// Panics if range `start > end`. + /// Panics if range `start == end` and both bounds are `Excluded`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"].iter() + /// .map(|&s| (s, 0)) + /// .collect(); + /// for (_, balance) in map.range_mut("B".."Cheryl") { + /// *balance += 100; + /// } + /// for (name, balance) in &map { + /// println!("{} => {}", name, balance); + /// } + /// ``` + #[stable(feature = "btree_range", since = "1.17.0")] + pub fn range_mut(&mut self, range: R) -> RangeMut + where T: Ord, K: Borrow, R: RangeBounds + { + let root1 = self.root.as_mut(); + let root2 = unsafe { ptr::read(&root1) }; + let (f, b) = range_search(root1, root2, range); + + RangeMut { + front: f, + back: b, + _marker: PhantomData, + } + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// // count the number of occurrences of letters in the vec + /// for x in vec!["a","b","a","c","a","b"] { + /// *count.entry(x).or_insert(0) += 1; + /// } + /// + /// assert_eq!(count["a"], 3); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn entry(&mut self, key: K) -> Entry { + // FIXME(@porglezomp) Avoid allocating if we don't insert + self.ensure_root_is_owned(); + match search::search_tree(self.root.as_mut(), &key) { + Found(handle) => { + Occupied(OccupiedEntry { + handle, + length: &mut self.length, + _marker: PhantomData, + }) + } + GoDown(handle) => { + Vacant(VacantEntry { + key, + handle, + length: &mut self.length, + _marker: PhantomData, + }) + } + } + } + + fn from_sorted_iter>(&mut self, iter: I) { + self.ensure_root_is_owned(); + let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node(); + // Iterate through all key-value pairs, pushing them into nodes at the right level. + for (key, value) in iter { + // Try to push key-value pair into the current leaf node. + if cur_node.len() < node::CAPACITY { + cur_node.push(key, value); + } else { + // No space left, go up and push there. + let mut open_node; + let mut test_node = cur_node.forget_type(); + loop { + match test_node.ascend() { + Ok(parent) => { + let parent = parent.into_node(); + if parent.len() < node::CAPACITY { + // Found a node with space left, push here. + open_node = parent; + break; + } else { + // Go up again. + test_node = parent.forget_type(); + } + } + Err(node) => { + // We are at the top, create a new root node and push there. + open_node = node.into_root_mut().push_level(); + break; + } + } + } + + // Push key-value pair and new right subtree. + let tree_height = open_node.height() - 1; + let mut right_tree = node::Root::new_leaf(); + for _ in 0..tree_height { + right_tree.push_level(); + } + open_node.push(key, value, right_tree); + + // Go down to the right-most leaf again. + cur_node = last_leaf_edge(open_node.forget_type()).into_node(); + } + + self.length += 1; + } + } + + fn fix_right_edge(&mut self) { + // Handle underfull nodes, start from the top. + let mut cur_node = self.root.as_mut(); + while let Internal(internal) = cur_node.force() { + // Check if right-most child is underfull. + let mut last_edge = internal.last_edge(); + let right_child_len = last_edge.reborrow().descend().len(); + if right_child_len < node::MIN_LEN { + // We need to steal. + let mut last_kv = match last_edge.left_kv() { + Ok(left) => left, + Err(_) => unreachable!(), + }; + last_kv.bulk_steal_left(node::MIN_LEN - right_child_len); + last_edge = last_kv.right_edge(); + } + + // Go further down. + cur_node = last_edge.descend(); + } + } + + /// Splits the collection into two at the given key. Returns everything after the given key, + /// including the key. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// a.insert(17, "d"); + /// a.insert(41, "e"); + /// + /// let b = a.split_off(&3); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 3); + /// + /// assert_eq!(a[&1], "a"); + /// assert_eq!(a[&2], "b"); + /// + /// assert_eq!(b[&3], "c"); + /// assert_eq!(b[&17], "d"); + /// assert_eq!(b[&41], "e"); + /// ``` + #[stable(feature = "btree_split_off", since = "1.11.0")] + pub fn split_off(&mut self, key: &Q) -> Self + where K: Borrow + { + if self.is_empty() { + return Self::new(); + } + + let total_num = self.len(); + + let mut right = Self::new(); + right.root = node::Root::new_leaf(); + for _ in 0..(self.root.as_ref().height()) { + right.root.push_level(); + } + + { + let mut left_node = self.root.as_mut(); + let mut right_node = right.root.as_mut(); + + loop { + let mut split_edge = match search::search_node(left_node, key) { + // key is going to the right tree + Found(handle) => handle.left_edge(), + GoDown(handle) => handle, + }; + + split_edge.move_suffix(&mut right_node); + + match (split_edge.force(), right_node.force()) { + (Internal(edge), Internal(node)) => { + left_node = edge.descend(); + right_node = node.first_edge().descend(); + } + (Leaf(_), Leaf(_)) => { + break; + } + _ => { + unreachable!(); + } + } + } + } + + self.fix_right_border(); + right.fix_left_border(); + + if self.root.as_ref().height() < right.root.as_ref().height() { + self.recalc_length(); + right.length = total_num - self.len(); + } else { + right.recalc_length(); + self.length = total_num - right.len(); + } + + right + } + + /// Calculates the number of elements if it is incorrect. + fn recalc_length(&mut self) { + fn dfs(node: NodeRef) -> usize { + let mut res = node.len(); + + if let Internal(node) = node.force() { + let mut edge = node.first_edge(); + loop { + res += dfs(edge.reborrow().descend()); + match edge.right_kv() { + Ok(right_kv) => { + edge = right_kv.right_edge(); + } + Err(_) => { + break; + } + } + } + } + + res + } + + self.length = dfs(self.root.as_ref()); + } + + /// Removes empty levels on the top. + fn fix_top(&mut self) { + loop { + { + let node = self.root.as_ref(); + if node.height() == 0 || node.len() > 0 { + break; + } + } + self.root.pop_level(); + } + } + + fn fix_right_border(&mut self) { + self.fix_top(); + + { + let mut cur_node = self.root.as_mut(); + + while let Internal(node) = cur_node.force() { + let mut last_kv = node.last_kv(); + + if last_kv.can_merge() { + cur_node = last_kv.merge().descend(); + } else { + let right_len = last_kv.reborrow().right_edge().descend().len(); + // `MINLEN + 1` to avoid readjust if merge happens on the next level. + if right_len < node::MIN_LEN + 1 { + last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len); + } + cur_node = last_kv.right_edge().descend(); + } + } + } + + self.fix_top(); + } + + /// The symmetric clone of `fix_right_border`. + fn fix_left_border(&mut self) { + self.fix_top(); + + { + let mut cur_node = self.root.as_mut(); + + while let Internal(node) = cur_node.force() { + let mut first_kv = node.first_kv(); + + if first_kv.can_merge() { + cur_node = first_kv.merge().descend(); + } else { + let left_len = first_kv.reborrow().left_edge().descend().len(); + if left_len < node::MIN_LEN + 1 { + first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len); + } + cur_node = first_kv.left_edge().descend(); + } + } + } + + self.fix_top(); + } + + /// If the root node is the shared root node, allocate our own node. + fn ensure_root_is_owned(&mut self) { + if self.root.is_shared_root() { + self.root = node::Root::new_leaf(); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + fn next(&mut self) -> Option<(&'a K, &'a V)> { + if self.length == 0 { + None + } else { + self.length -= 1; + unsafe { Some(self.range.next_unchecked()) } + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.length, Some(self.length)) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K, &'a V)> { + if self.length == 0 { + None + } else { + self.length -= 1; + unsafe { Some(self.range.next_back_unchecked()) } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> { + fn len(&self) -> usize { + self.length + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Clone for Iter<'a, K, V> { + fn clone(&self) -> Iter<'a, K, V> { + Iter { + range: self.range.clone(), + length: self.length, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + fn into_iter(self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + if self.length == 0 { + None + } else { + self.length -= 1; + unsafe { Some(self.range.next_unchecked()) } + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.length, Some(self.length)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { + if self.length == 0 { + None + } else { + self.length -= 1; + unsafe { Some(self.range.next_back_unchecked()) } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { + fn len(&self) -> usize { + self.length + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for BTreeMap { + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + let root1 = unsafe { ptr::read(&self.root).into_ref() }; + let root2 = unsafe { ptr::read(&self.root).into_ref() }; + let len = self.length; + mem::forget(self); + + IntoIter { + front: first_leaf_edge(root1), + back: last_leaf_edge(root2), + length: len, + } + } +} + +#[stable(feature = "btree_drop", since = "1.7.0")] +impl Drop for IntoIter { + fn drop(&mut self) { + self.for_each(drop); + unsafe { + let leaf_node = ptr::read(&self.front).into_node(); + if leaf_node.is_shared_root() { + return; + } + + if let Some(first_parent) = leaf_node.deallocate_and_ascend() { + let mut cur_node = first_parent.into_node(); + while let Some(parent) = cur_node.deallocate_and_ascend() { + cur_node = parent.into_node() + } + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = (K, V); + + fn next(&mut self) -> Option<(K, V)> { + if self.length == 0 { + return None; + } else { + self.length -= 1; + } + + let handle = unsafe { ptr::read(&self.front) }; + + let mut cur_handle = match handle.right_kv() { + Ok(kv) => { + let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; + let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; + self.front = kv.right_edge(); + return Some((k, v)); + } + Err(last_edge) => unsafe { + unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()) + }, + }; + + loop { + match cur_handle.right_kv() { + Ok(kv) => { + let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; + let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; + self.front = first_leaf_edge(kv.right_edge().descend()); + return Some((k, v)); + } + Err(last_edge) => unsafe { + cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()); + }, + } + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.length, Some(self.length)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option<(K, V)> { + if self.length == 0 { + return None; + } else { + self.length -= 1; + } + + let handle = unsafe { ptr::read(&self.back) }; + + let mut cur_handle = match handle.left_kv() { + Ok(kv) => { + let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; + let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; + self.back = kv.left_edge(); + return Some((k, v)); + } + Err(last_edge) => unsafe { + unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()) + }, + }; + + loop { + match cur_handle.left_kv() { + Ok(kv) => { + let k = unsafe { ptr::read(kv.reborrow().into_kv().0) }; + let v = unsafe { ptr::read(kv.reborrow().into_kv().1) }; + self.back = last_leaf_edge(kv.left_edge().descend()); + return Some((k, v)); + } + Err(last_edge) => unsafe { + cur_handle = unwrap_unchecked(last_edge.into_node().deallocate_and_ascend()); + }, + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { + self.length + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + fn next(&mut self) -> Option<&'a K> { + self.inner.next().map(|(k, _)| k) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> { + fn next_back(&mut self) -> Option<&'a K> { + self.inner.next_back().map(|(k, _)| k) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Clone for Keys<'a, K, V> { + fn clone(&self) -> Keys<'a, K, V> { + Keys { inner: self.inner.clone() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + fn next(&mut self) -> Option<&'a V> { + self.inner.next().map(|(_, v)| v) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { + fn next_back(&mut self) -> Option<&'a V> { + self.inner.next_back().map(|(_, v)| v) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, K, V> FusedIterator for Values<'a, K, V> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K, V> Clone for Values<'a, K, V> { + fn clone(&self) -> Values<'a, K, V> { + Values { inner: self.inner.clone() } + } +} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, K, V> Iterator for Range<'a, K, V> { + type Item = (&'a K, &'a V); + + fn next(&mut self) -> Option<(&'a K, &'a V)> { + if self.front == self.back { + None + } else { + unsafe { Some(self.next_unchecked()) } + } + } +} + +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + fn next(&mut self) -> Option<&'a mut V> { + self.inner.next().map(|(_, v)| v) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> { + fn next_back(&mut self) -> Option<&'a mut V> { + self.inner.next_back().map(|(_, v)| v) + } +} + +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} + + +impl<'a, K, V> Range<'a, K, V> { + unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { + let handle = self.front; + + let mut cur_handle = match handle.right_kv() { + Ok(kv) => { + let ret = kv.into_kv(); + self.front = kv.right_edge(); + return ret; + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + unwrap_unchecked(next_level) + } + }; + + loop { + match cur_handle.right_kv() { + Ok(kv) => { + let ret = kv.into_kv(); + self.front = first_leaf_edge(kv.right_edge().descend()); + return ret; + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + cur_handle = unwrap_unchecked(next_level); + } + } + } + } +} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K, &'a V)> { + if self.front == self.back { + None + } else { + unsafe { Some(self.next_back_unchecked()) } + } + } +} + +impl<'a, K, V> Range<'a, K, V> { + unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { + let handle = self.back; + + let mut cur_handle = match handle.left_kv() { + Ok(kv) => { + let ret = kv.into_kv(); + self.back = kv.left_edge(); + return ret; + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + unwrap_unchecked(next_level) + } + }; + + loop { + match cur_handle.left_kv() { + Ok(kv) => { + let ret = kv.into_kv(); + self.back = last_leaf_edge(kv.left_edge().descend()); + return ret; + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + cur_handle = unwrap_unchecked(next_level); + } + } + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, K, V> FusedIterator for Range<'a, K, V> {} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, K, V> Clone for Range<'a, K, V> { + fn clone(&self) -> Range<'a, K, V> { + Range { + front: self.front, + back: self.back, + } + } +} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, K, V> Iterator for RangeMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + if self.front == self.back { + None + } else { + unsafe { Some(self.next_unchecked()) } + } + } +} + +impl<'a, K, V> RangeMut<'a, K, V> { + unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { + let handle = ptr::read(&self.front); + + let mut cur_handle = match handle.right_kv() { + Ok(kv) => { + let (k, v) = ptr::read(&kv).into_kv_mut(); + self.front = kv.right_edge(); + return (k, v); + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + unwrap_unchecked(next_level) + } + }; + + loop { + match cur_handle.right_kv() { + Ok(kv) => { + let (k, v) = ptr::read(&kv).into_kv_mut(); + self.front = first_leaf_edge(kv.right_edge().descend()); + return (k, v); + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + cur_handle = unwrap_unchecked(next_level); + } + } + } + } +} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { + if self.front == self.back { + None + } else { + unsafe { Some(self.next_back_unchecked()) } + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} + +impl<'a, K, V> RangeMut<'a, K, V> { + unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { + let handle = ptr::read(&self.back); + + let mut cur_handle = match handle.left_kv() { + Ok(kv) => { + let (k, v) = ptr::read(&kv).into_kv_mut(); + self.back = kv.left_edge(); + return (k, v); + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + unwrap_unchecked(next_level) + } + }; + + loop { + match cur_handle.left_kv() { + Ok(kv) => { + let (k, v) = ptr::read(&kv).into_kv_mut(); + self.back = last_leaf_edge(kv.left_edge().descend()); + return (k, v); + } + Err(last_edge) => { + let next_level = last_edge.into_node().ascend().ok(); + cur_handle = unwrap_unchecked(next_level); + } + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator<(K, V)> for BTreeMap { + fn from_iter>(iter: T) -> BTreeMap { + let mut map = BTreeMap::new(); + map.extend(iter); + map + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend<(K, V)> for BTreeMap { + #[inline] + fn extend>(&mut self, iter: T) { + for (k, v) in iter { + self.insert(k, v); + } + } +} + +#[stable(feature = "extend_ref", since = "1.2.0")] +impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for BTreeMap { + fn hash(&self, state: &mut H) { + for elt in self { + elt.hash(state); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for BTreeMap { + /// Creates an empty `BTreeMap`. + fn default() -> BTreeMap { + BTreeMap::new() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for BTreeMap { + fn eq(&self, other: &BTreeMap) -> bool { + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for BTreeMap {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for BTreeMap { + #[inline] + fn partial_cmp(&self, other: &BTreeMap) -> Option { + self.iter().partial_cmp(other.iter()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for BTreeMap { + #[inline] + fn cmp(&self, other: &BTreeMap) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Debug for BTreeMap { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap + where K: Borrow, + Q: Ord +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `BTreeMap`. + #[inline] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +fn first_leaf_edge + (mut node: NodeRef) + -> Handle, marker::Edge> { + loop { + match node.force() { + Leaf(leaf) => return leaf.first_edge(), + Internal(internal) => { + node = internal.first_edge().descend(); + } + } + } +} + +fn last_leaf_edge + (mut node: NodeRef) + -> Handle, marker::Edge> { + loop { + match node.force() { + Leaf(leaf) => return leaf.last_edge(), + Internal(internal) => { + node = internal.last_edge().descend(); + } + } + } +} + +fn range_search>( + root1: NodeRef, + root2: NodeRef, + range: R +)-> (Handle, marker::Edge>, + Handle, marker::Edge>) + where Q: Ord, K: Borrow +{ + match (range.start_bound(), range.end_bound()) { + (Excluded(s), Excluded(e)) if s==e => + panic!("range start and end are equal and excluded in BTreeMap"), + (Included(s), Included(e)) | + (Included(s), Excluded(e)) | + (Excluded(s), Included(e)) | + (Excluded(s), Excluded(e)) if s>e => + panic!("range start is greater than range end in BTreeMap"), + _ => {}, + }; + + let mut min_node = root1; + let mut max_node = root2; + let mut min_found = false; + let mut max_found = false; + let mut diverged = false; + + loop { + let min_edge = match (min_found, range.start_bound()) { + (false, Included(key)) => match search::search_linear(&min_node, key) { + (i, true) => { min_found = true; i }, + (i, false) => i, + }, + (false, Excluded(key)) => match search::search_linear(&min_node, key) { + (i, true) => { min_found = true; i+1 }, + (i, false) => i, + }, + (_, Unbounded) => 0, + (true, Included(_)) => min_node.keys().len(), + (true, Excluded(_)) => 0, + }; + + let max_edge = match (max_found, range.end_bound()) { + (false, Included(key)) => match search::search_linear(&max_node, key) { + (i, true) => { max_found = true; i+1 }, + (i, false) => i, + }, + (false, Excluded(key)) => match search::search_linear(&max_node, key) { + (i, true) => { max_found = true; i }, + (i, false) => i, + }, + (_, Unbounded) => max_node.keys().len(), + (true, Included(_)) => 0, + (true, Excluded(_)) => max_node.keys().len(), + }; + + if !diverged { + if max_edge < min_edge { panic!("Ord is ill-defined in BTreeMap range") } + if min_edge != max_edge { diverged = true; } + } + + let front = Handle::new_edge(min_node, min_edge); + let back = Handle::new_edge(max_node, max_edge); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + }, + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + }, + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + +#[inline(always)] +unsafe fn unwrap_unchecked(val: Option) -> T { + val.unwrap_or_else(|| { + if cfg!(debug_assertions) { + panic!("'unchecked' unwrap on None in BTreeMap"); + } else { + intrinsics::unreachable(); + } + }) +} + +impl BTreeMap { + /// Gets an iterator over the entries of the map, sorted by key. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(3, "c"); + /// map.insert(2, "b"); + /// map.insert(1, "a"); + /// + /// for (key, value) in map.iter() { + /// println!("{}: {}", key, value); + /// } + /// + /// let (first_key, first_value) = map.iter().next().unwrap(); + /// assert_eq!((*first_key, *first_value), (1, "a")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter { + Iter { + range: Range { + front: first_leaf_edge(self.root.as_ref()), + back: last_leaf_edge(self.root.as_ref()), + }, + length: self.length, + } + } + + /// Gets a mutable iterator over the entries of the map, sorted by key. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // add 10 to the value if the key isn't "a" + /// for (key, value) in map.iter_mut() { + /// if key != &"a" { + /// *value += 10; + /// } + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter_mut(&mut self) -> IterMut { + let root1 = self.root.as_mut(); + let root2 = unsafe { ptr::read(&root1) }; + IterMut { + range: RangeMut { + front: first_leaf_edge(root1), + back: last_leaf_edge(root2), + _marker: PhantomData, + }, + length: self.length, + } + } + + /// Gets an iterator over the keys of the map, in sorted order. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(2, "b"); + /// a.insert(1, "a"); + /// + /// let keys: Vec<_> = a.keys().cloned().collect(); + /// assert_eq!(keys, [1, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { + Keys { inner: self.iter() } + } + + /// Gets an iterator over the values of the map, in order by key. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, "hello"); + /// a.insert(2, "goodbye"); + /// + /// let values: Vec<&str> = a.values().cloned().collect(); + /// assert_eq!(values, ["hello", "goodbye"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn values<'a>(&'a self) -> Values<'a, K, V> { + Values { inner: self.iter() } + } + + /// Gets a mutable iterator over the values of the map, in order by key. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, String::from("hello")); + /// a.insert(2, String::from("goodbye")); + /// + /// for value in a.values_mut() { + /// value.push_str("!"); + /// } + /// + /// let values: Vec = a.values().cloned().collect(); + /// assert_eq!(values, [String::from("hello!"), + /// String::from("goodbye!")]); + /// ``` + #[stable(feature = "map_values_mut", since = "1.10.0")] + pub fn values_mut(&mut self) -> ValuesMut { + ValuesMut { inner: self.iter_mut() } + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { + self.length + } + + /// Returns `true` if the map contains no elements. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl<'a, K: Ord, V> Entry<'a, K, V> { + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert_with V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[stable(feature = "entry_and_modify", since = "1.26.0")] + pub fn and_modify(self, f: F) -> Self + where F: FnOnce(&mut V) + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + }, + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K: Ord, V: Default> Entry<'a, K, V> { + #[stable(feature = "entry_or_default", since = "1.28.0")] + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, Option> = BTreeMap::new(); + /// map.entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + pub fn or_default(self) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } + +} + +impl<'a, K: Ord, V> VacantEntry<'a, K, V> { + /// Gets a reference to the key that would be used when inserting a value + /// through the VacantEntry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// // count the number of occurrences of letters in the vec + /// for x in vec!["a","b","a","c","a","b"] { + /// *count.entry(x).or_insert(0) += 1; + /// } + /// + /// assert_eq!(count["a"], 3); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(self, value: V) -> &'a mut V { + *self.length += 1; + + let out_ptr; + + let mut ins_k; + let mut ins_v; + let mut ins_edge; + + let mut cur_parent = match self.handle.insert(self.key, value) { + (Fit(handle), _) => return handle.into_kv_mut().1, + (Split(left, k, v, right), ptr) => { + ins_k = k; + ins_v = v; + ins_edge = right; + out_ptr = ptr; + left.ascend().map_err(|n| n.into_root_mut()) + } + }; + + loop { + match cur_parent { + Ok(parent) => { + match parent.insert(ins_k, ins_v, ins_edge) { + Fit(_) => return unsafe { &mut *out_ptr }, + Split(left, k, v, right) => { + ins_k = k; + ins_v = v; + ins_edge = right; + cur_parent = left.ascend().map_err(|n| n.into_root_mut()); + } + } + } + Err(root) => { + root.push_level().push(ins_k, ins_v, ins_edge); + return unsafe { &mut *out_ptr }; + } + } + } + } +} + +impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + self.handle.reborrow().into_kv().0 + } + + /// Take ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// // If now try to get the value, it will panic: + /// // println!("{}", map["poneyland"]); + /// ``` + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { + self.remove_kv() + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self) -> &V { + self.handle.reborrow().into_kv().1 + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut V { + self.handle.kv_mut().1 + } + + /// Converts the entry into a mutable reference to its value. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_mut(self) -> &'a mut V { + self.handle.into_kv_mut().1 + } + + /// Sets the value of the entry with the `OccupiedEntry`'s key, + /// and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value of the entry out of the map, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// // If we try to get "poneyland"'s value, it'll panic: + /// // println!("{}", map["poneyland"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(self) -> V { + self.remove_kv().1 + } + + fn remove_kv(self) -> (K, V) { + *self.length -= 1; + + let (small_leaf, old_key, old_val) = match self.handle.force() { + Leaf(leaf) => { + let (hole, old_key, old_val) = leaf.remove(); + (hole.into_node(), old_key, old_val) + } + Internal(mut internal) => { + let key_loc = internal.kv_mut().0 as *mut K; + let val_loc = internal.kv_mut().1 as *mut V; + + let to_remove = first_leaf_edge(internal.right_edge().descend()).right_kv().ok(); + let to_remove = unsafe { unwrap_unchecked(to_remove) }; + + let (hole, key, val) = to_remove.remove(); + + let old_key = unsafe { mem::replace(&mut *key_loc, key) }; + let old_val = unsafe { mem::replace(&mut *val_loc, val) }; + + (hole.into_node(), old_key, old_val) + } + }; + + // Handle underflow + let mut cur_node = small_leaf.forget_type(); + while cur_node.len() < node::CAPACITY / 2 { + match handle_underfull_node(cur_node) { + AtRoot => break, + EmptyParent(_) => unreachable!(), + Merged(parent) => { + if parent.len() == 0 { + // We must be at the root + parent.into_root_mut().pop_level(); + break; + } else { + cur_node = parent.forget_type(); + } + } + Stole(_) => break, + } + } + + (old_key, old_val) + } +} + +enum UnderflowResult<'a, K, V> { + AtRoot, + EmptyParent(NodeRef, K, V, marker::Internal>), + Merged(NodeRef, K, V, marker::Internal>), + Stole(NodeRef, K, V, marker::Internal>), +} + +fn handle_underfull_node<'a, K, V>(node: NodeRef, K, V, marker::LeafOrInternal>) + -> UnderflowResult<'a, K, V> { + let parent = if let Ok(parent) = node.ascend() { + parent + } else { + return AtRoot; + }; + + let (is_left, mut handle) = match parent.left_kv() { + Ok(left) => (true, left), + Err(parent) => { + match parent.right_kv() { + Ok(right) => (false, right), + Err(parent) => { + return EmptyParent(parent.into_node()); + } + } + } + }; + + if handle.can_merge() { + Merged(handle.merge().into_node()) + } else { + if is_left { + handle.steal_left(); + } else { + handle.steal_right(); + } + Stole(handle.into_node()) + } +} + +impl> Iterator for MergeIter { + type Item = (K, V); + + fn next(&mut self) -> Option<(K, V)> { + let res = match (self.left.peek(), self.right.peek()) { + (Some(&(ref left_key, _)), Some(&(ref right_key, _))) => left_key.cmp(right_key), + (Some(_), None) => Ordering::Less, + (None, Some(_)) => Ordering::Greater, + (None, None) => return None, + }; + + // Check which elements comes first and only advance the corresponding iterator. + // If two keys are equal, take the value from `right`. + match res { + Ordering::Less => self.left.next(), + Ordering::Greater => self.right.next(), + Ordering::Equal => { + self.left.next(); + self.right.next() + } + } + } +} diff --git a/src/liballoc/collections/btree/mod.rs b/src/liballoc/collections/btree/mod.rs new file mode 100644 index 00000000000..087c9f228d4 --- /dev/null +++ b/src/liballoc/collections/btree/mod.rs @@ -0,0 +1,23 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod node; +mod search; +pub mod map; +pub mod set; + +#[doc(hidden)] +trait Recover { + type Key; + + fn get(&self, key: &Q) -> Option<&Self::Key>; + fn take(&mut self, key: &Q) -> Option; + fn replace(&mut self, key: Self::Key) -> Option; +} diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs new file mode 100644 index 00000000000..19bdcbc6ad6 --- /dev/null +++ b/src/liballoc/collections/btree/node.rs @@ -0,0 +1,1622 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is an attempt at an implementation following the ideal +// +// ``` +// struct BTreeMap { +// height: usize, +// root: Option>> +// } +// +// struct Node { +// keys: [K; 2 * B - 1], +// vals: [V; 2 * B - 1], +// edges: if height > 0 { +// [Box>; 2 * B] +// } else { () }, +// parent: *const Node, +// parent_idx: u16, +// len: u16, +// } +// ``` +// +// Since Rust doesn't actually have dependent types and polymorphic recursion, +// we make do with lots of unsafety. + +// A major goal of this module is to avoid complexity by treating the tree as a generic (if +// weirdly shaped) container and avoiding dealing with most of the B-Tree invariants. As such, +// this module doesn't care whether the entries are sorted, which nodes can be underfull, or +// even what underfull means. However, we do rely on a few invariants: +// +// - Trees must have uniform depth/height. This means that every path down to a leaf from a +// given node has exactly the same length. +// - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges. +// This implies that even an empty internal node has at least one edge. + +use core::marker::PhantomData; +use core::mem; +use core::ptr::{self, Unique, NonNull}; +use core::slice; + +use alloc::{Global, Alloc, Layout}; +use boxed::Box; + +const B: usize = 6; +pub const MIN_LEN: usize = B - 1; +pub const CAPACITY: usize = 2 * B - 1; + +/// The underlying representation of leaf nodes. Note that it is often unsafe to actually store +/// these, since only the first `len` keys and values are assumed to be initialized. As such, +/// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned +/// case. +/// +/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by +/// avoiding accidentally dropping unused and uninitialized keys and values. +/// +/// We put the metadata first so that its position is the same for every `K` and `V`, in order +/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to +/// prevent them from being reordered. +#[repr(C)] +struct LeafNode { + /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. + /// This either points to an actual node or is null. + parent: *const InternalNode, + + /// This node's index into the parent node's `edges` array. + /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. + /// This is only guaranteed to be initialized when `parent` is nonnull. + parent_idx: u16, + + /// The number of keys and values this node stores. + /// + /// This next to `parent_idx` to encourage the compiler to join `len` and + /// `parent_idx` into the same 32-bit word, reducing space overhead. + len: u16, + + /// The arrays storing the actual data of the node. Only the first `len` elements of each + /// array are initialized and valid. + keys: [K; CAPACITY], + vals: [V; CAPACITY], +} + +impl LeafNode { + /// Creates a new `LeafNode`. Unsafe because all nodes should really be hidden behind + /// `BoxedNode`, preventing accidental dropping of uninitialized keys and values. + unsafe fn new() -> Self { + LeafNode { + // As a general policy, we leave fields uninitialized if they can be, as this should + // be both slightly faster and easier to track in Valgrind. + keys: mem::uninitialized(), + vals: mem::uninitialized(), + parent: ptr::null(), + parent_idx: mem::uninitialized(), + len: 0 + } + } + + fn is_shared_root(&self) -> bool { + self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode + } +} + +// We need to implement Sync here in order to make a static instance. +unsafe impl Sync for LeafNode<(), ()> {} + +// An empty node used as a placeholder for the root node, to avoid allocations. +// We use () in order to save space, since no operation on an empty tree will +// ever take a pointer past the first key. +static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode { + parent: ptr::null(), + parent_idx: 0, + len: 0, + keys: [(); CAPACITY], + vals: [(); CAPACITY], +}; + +/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden +/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an +/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the +/// node, allowing code to act on leaf and internal nodes generically without having to even check +/// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`. +#[repr(C)] +struct InternalNode { + data: LeafNode, + + /// The pointers to the children of this node. `len + 1` of these are considered + /// initialized and valid. + edges: [BoxedNode; 2 * B], +} + +impl InternalNode { + /// Creates a new `InternalNode`. + /// + /// This is unsafe for two reasons. First, it returns an `InternalNode` by value, risking + /// dropping of uninitialized fields. Second, an invariant of internal nodes is that `len + 1` + /// edges are initialized and valid, meaning that even when the node is empty (having a + /// `len` of 0), there must be one initialized and valid edge. This function does not set up + /// such an edge. + unsafe fn new() -> Self { + InternalNode { + data: LeafNode::new(), + edges: mem::uninitialized() + } + } +} + +/// An owned pointer to a node. This basically is either `Box>` or +/// `Box>`. However, it contains no information as to which of the two types +/// of nodes is actually behind the box, and, partially due to this lack of information, has no +/// destructor. +struct BoxedNode { + ptr: Unique> +} + +impl BoxedNode { + fn from_leaf(node: Box>) -> Self { + BoxedNode { ptr: Box::into_unique(node) } + } + + fn from_internal(node: Box>) -> Self { + unsafe { + BoxedNode { ptr: Unique::new_unchecked(Box::into_raw(node) as *mut LeafNode) } + } + } + + unsafe fn from_ptr(ptr: NonNull>) -> Self { + BoxedNode { ptr: Unique::from(ptr) } + } + + fn as_ptr(&self) -> NonNull> { + NonNull::from(self.ptr) + } +} + +/// An owned tree. Note that despite being owned, this does not have a destructor, +/// and must be cleaned up manually. +pub struct Root { + node: BoxedNode, + height: usize +} + +unsafe impl Sync for Root { } +unsafe impl Send for Root { } + +impl Root { + pub fn is_shared_root(&self) -> bool { + self.as_ref().is_shared_root() + } + + pub fn shared_empty_root() -> Self { + Root { + node: unsafe { + BoxedNode::from_ptr(NonNull::new_unchecked( + &EMPTY_ROOT_NODE as *const _ as *const LeafNode as *mut _ + )) + }, + height: 0, + } + } + + pub fn new_leaf() -> Self { + Root { + node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), + height: 0 + } + } + + pub fn as_ref(&self) + -> NodeRef { + NodeRef { + height: self.height, + node: self.node.as_ptr(), + root: self as *const _ as *mut _, + _marker: PhantomData, + } + } + + pub fn as_mut(&mut self) + -> NodeRef { + NodeRef { + height: self.height, + node: self.node.as_ptr(), + root: self as *mut _, + _marker: PhantomData, + } + } + + pub fn into_ref(self) + -> NodeRef { + NodeRef { + height: self.height, + node: self.node.as_ptr(), + root: ptr::null_mut(), // FIXME: Is there anything better to do here? + _marker: PhantomData, + } + } + + /// Adds a new internal node with a single edge, pointing to the previous root, and make that + /// new node the root. This increases the height by 1 and is the opposite of `pop_level`. + pub fn push_level(&mut self) + -> NodeRef { + debug_assert!(!self.is_shared_root()); + let mut new_node = Box::new(unsafe { InternalNode::new() }); + new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }; + + self.node = BoxedNode::from_internal(new_node); + self.height += 1; + + let mut ret = NodeRef { + height: self.height, + node: self.node.as_ptr(), + root: self as *mut _, + _marker: PhantomData + }; + + unsafe { + ret.reborrow_mut().first_edge().correct_parent_link(); + } + + ret + } + + /// Removes the root node, using its first child as the new root. This cannot be called when + /// the tree consists only of a leaf node. As it is intended only to be called when the root + /// has only one edge, no cleanup is done on any of the other children are elements of the root. + /// This decreases the height by 1 and is the opposite of `push_level`. + pub fn pop_level(&mut self) { + debug_assert!(self.height > 0); + + let top = self.node.ptr; + + self.node = unsafe { + BoxedNode::from_ptr(self.as_mut() + .cast_unchecked::() + .first_edge() + .descend() + .node) + }; + self.height -= 1; + self.as_mut().as_leaf_mut().parent = ptr::null(); + + unsafe { + Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); + } + } +} + +// N.B. `NodeRef` is always covariant in `K` and `V`, even when the `BorrowType` +// is `Mut`. This is technically wrong, but cannot result in any unsafety due to +// internal use of `NodeRef` because we stay completely generic over `K` and `V`. +// However, whenever a public type wraps `NodeRef`, make sure that it has the +// correct variance. +/// A reference to a node. +/// +/// This type has a number of parameters that controls how it acts: +/// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`. +/// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`, +/// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`, +/// and when this is `Owned`, the `NodeRef` acts roughly like `Box`. +/// - `K` and `V`: These control what types of things are stored in the nodes. +/// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is +/// `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the +/// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the +/// `NodeRef` could be pointing to either type of node. +pub struct NodeRef { + height: usize, + node: NonNull>, + // This is null unless the borrow type is `Mut` + root: *const Root, + _marker: PhantomData<(BorrowType, Type)> +} + +impl<'a, K: 'a, V: 'a, Type> Copy for NodeRef, K, V, Type> { } +impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef, K, V, Type> { + fn clone(&self) -> Self { + *self + } +} + +unsafe impl Sync + for NodeRef { } + +unsafe impl<'a, K: Sync + 'a, V: Sync + 'a, Type> Send + for NodeRef, K, V, Type> { } +unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send + for NodeRef, K, V, Type> { } +unsafe impl Send + for NodeRef { } + +impl NodeRef { + fn as_internal(&self) -> &InternalNode { + unsafe { + &*(self.node.as_ptr() as *mut InternalNode) + } + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + fn as_internal_mut(&mut self) -> &mut InternalNode { + unsafe { + &mut *(self.node.as_ptr() as *mut InternalNode) + } + } +} + + +impl NodeRef { + /// Finds the length of the node. This is the number of keys or values. In an + /// internal node, the number of edges is `len() + 1`. + pub fn len(&self) -> usize { + self.as_leaf().len as usize + } + + /// Returns the height of this node in the whole tree. Zero height denotes the + /// leaf level. + pub fn height(&self) -> usize { + self.height + } + + /// Removes any static information about whether this node is a `Leaf` or an + /// `Internal` node. + pub fn forget_type(self) -> NodeRef { + NodeRef { + height: self.height, + node: self.node, + root: self.root, + _marker: PhantomData + } + } + + /// Temporarily takes out another, immutable reference to the same node. + fn reborrow<'a>(&'a self) -> NodeRef, K, V, Type> { + NodeRef { + height: self.height, + node: self.node, + root: self.root, + _marker: PhantomData + } + } + + fn as_leaf(&self) -> &LeafNode { + unsafe { + self.node.as_ref() + } + } + + pub fn is_shared_root(&self) -> bool { + self.as_leaf().is_shared_root() + } + + pub fn keys(&self) -> &[K] { + self.reborrow().into_key_slice() + } + + fn vals(&self) -> &[V] { + self.reborrow().into_val_slice() + } + + /// Finds the parent of the current node. Returns `Ok(handle)` if the current + /// node actually has a parent, where `handle` points to the edge of the parent + /// that points to the current node. Returns `Err(self)` if the current node has + /// no parent, giving back the original `NodeRef`. + /// + /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should + /// both, upon success, do nothing. + pub fn ascend(self) -> Result< + Handle< + NodeRef< + BorrowType, + K, V, + marker::Internal + >, + marker::Edge + >, + Self + > { + let parent_as_leaf = self.as_leaf().parent as *const LeafNode; + if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { + Ok(Handle { + node: NodeRef { + height: self.height + 1, + node: non_zero, + root: self.root, + _marker: PhantomData + }, + idx: self.as_leaf().parent_idx as usize, + _marker: PhantomData + }) + } else { + Err(self) + } + } + + pub fn first_edge(self) -> Handle { + Handle::new_edge(self, 0) + } + + pub fn last_edge(self) -> Handle { + let len = self.len(); + Handle::new_edge(self, len) + } + + /// Note that `self` must be nonempty. + pub fn first_kv(self) -> Handle { + debug_assert!(self.len() > 0); + Handle::new_kv(self, 0) + } + + /// Note that `self` must be nonempty. + pub fn last_kv(self) -> Handle { + let len = self.len(); + debug_assert!(len > 0); + Handle::new_kv(self, len - 1) + } +} + +impl NodeRef { + /// Similar to `ascend`, gets a reference to a node's parent node, but also + /// deallocate the current node in the process. This is unsafe because the + /// current node will still be accessible despite being deallocated. + pub unsafe fn deallocate_and_ascend(self) -> Option< + Handle< + NodeRef< + marker::Owned, + K, V, + marker::Internal + >, + marker::Edge + > + > { + debug_assert!(!self.is_shared_root()); + let node = self.node; + let ret = self.ascend().ok(); + Global.dealloc(node.cast(), Layout::new::>()); + ret + } +} + +impl NodeRef { + /// Similar to `ascend`, gets a reference to a node's parent node, but also + /// deallocate the current node in the process. This is unsafe because the + /// current node will still be accessible despite being deallocated. + pub unsafe fn deallocate_and_ascend(self) -> Option< + Handle< + NodeRef< + marker::Owned, + K, V, + marker::Internal + >, + marker::Edge + > + > { + let node = self.node; + let ret = self.ascend().ok(); + Global.dealloc(node.cast(), Layout::new::>()); + ret + } +} + +impl<'a, K, V, Type> NodeRef, K, V, Type> { + /// Unsafely asserts to the compiler some static information about whether this + /// node is a `Leaf`. + unsafe fn cast_unchecked(&mut self) + -> NodeRef { + + NodeRef { + height: self.height, + node: self.node, + root: self.root, + _marker: PhantomData + } + } + + /// Temporarily takes out another, mutable reference to the same node. Beware, as + /// this method is very dangerous, doubly so since it may not immediately appear + /// dangerous. + /// + /// Because mutable pointers can roam anywhere around the tree and can even (through + /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` + /// can easily be used to make the original mutable pointer dangling, or, in the case + /// of a reborrowed handle, out of bounds. + // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts + // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + unsafe fn reborrow_mut(&mut self) -> NodeRef { + NodeRef { + height: self.height, + node: self.node, + root: self.root, + _marker: PhantomData + } + } + + fn as_leaf_mut(&mut self) -> &mut LeafNode { + unsafe { + self.node.as_mut() + } + } + + fn keys_mut(&mut self) -> &mut [K] { + unsafe { self.reborrow_mut().into_key_slice_mut() } + } + + fn vals_mut(&mut self) -> &mut [V] { + unsafe { self.reborrow_mut().into_val_slice_mut() } + } +} + +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + fn into_key_slice(self) -> &'a [K] { + // When taking a pointer to the keys, if our key has a stricter + // alignment requirement than the shared root does, then the pointer + // would be out of bounds, which LLVM assumes will not happen. If the + // alignment is more strict, we need to make an empty slice that doesn't + // use an out of bounds pointer. + if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { + &[] + } else { + // Here either it's not the root, or the alignment is less strict, + // in which case the keys pointer will point "one-past-the-end" of + // the node, which is allowed by LLVM. + unsafe { + slice::from_raw_parts( + self.as_leaf().keys.as_ptr(), + self.len() + ) + } + } + } + + fn into_val_slice(self) -> &'a [V] { + debug_assert!(!self.is_shared_root()); + unsafe { + slice::from_raw_parts( + self.as_leaf().vals.as_ptr(), + self.len() + ) + } + } + + fn into_slices(self) -> (&'a [K], &'a [V]) { + let k = unsafe { ptr::read(&self) }; + (k.into_key_slice(), self.into_val_slice()) + } +} + +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// Gets a mutable reference to the root itself. This is useful primarily when the + /// height of the tree needs to be adjusted. Never call this on a reborrowed pointer. + pub fn into_root_mut(self) -> &'a mut Root { + unsafe { + &mut *(self.root as *mut Root) + } + } + + fn into_key_slice_mut(mut self) -> &'a mut [K] { + if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { + &mut [] + } else { + unsafe { + slice::from_raw_parts_mut( + &mut self.as_leaf_mut().keys as *mut [K] as *mut K, + self.len() + ) + } + } + } + + fn into_val_slice_mut(mut self) -> &'a mut [V] { + debug_assert!(!self.is_shared_root()); + unsafe { + slice::from_raw_parts_mut( + &mut self.as_leaf_mut().vals as *mut [V] as *mut V, + self.len() + ) + } + } + + fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) { + let k = unsafe { ptr::read(&self) }; + (k.into_key_slice_mut(), self.into_val_slice_mut()) + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Leaf> { + /// Adds a key/value pair the end of the node. + pub fn push(&mut self, key: K, val: V) { + // Necessary for correctness, but this is an internal module + debug_assert!(self.len() < CAPACITY); + debug_assert!(!self.is_shared_root()); + + let idx = self.len(); + + unsafe { + ptr::write(self.keys_mut().get_unchecked_mut(idx), key); + ptr::write(self.vals_mut().get_unchecked_mut(idx), val); + } + + self.as_leaf_mut().len += 1; + } + + /// Adds a key/value pair to the beginning of the node. + pub fn push_front(&mut self, key: K, val: V) { + // Necessary for correctness, but this is an internal module + debug_assert!(self.len() < CAPACITY); + debug_assert!(!self.is_shared_root()); + + unsafe { + slice_insert(self.keys_mut(), 0, key); + slice_insert(self.vals_mut(), 0, val); + } + + self.as_leaf_mut().len += 1; + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Adds a key/value pair and an edge to go to the right of that pair to + /// the end of the node. + pub fn push(&mut self, key: K, val: V, edge: Root) { + // Necessary for correctness, but this is an internal module + debug_assert!(edge.height == self.height - 1); + debug_assert!(self.len() < CAPACITY); + + let idx = self.len(); + + unsafe { + ptr::write(self.keys_mut().get_unchecked_mut(idx), key); + ptr::write(self.vals_mut().get_unchecked_mut(idx), val); + ptr::write(self.as_internal_mut().edges.get_unchecked_mut(idx + 1), edge.node); + + self.as_leaf_mut().len += 1; + + Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); + } + } + + fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) { + for i in first..after_last { + Handle::new_edge(unsafe { self.reborrow_mut() }, i).correct_parent_link(); + } + } + + fn correct_all_childrens_parent_links(&mut self) { + let len = self.len(); + self.correct_childrens_parent_links(0, len + 1); + } + + /// Adds a key/value pair and an edge to go to the left of that pair to + /// the beginning of the node. + pub fn push_front(&mut self, key: K, val: V, edge: Root) { + // Necessary for correctness, but this is an internal module + debug_assert!(edge.height == self.height - 1); + debug_assert!(self.len() < CAPACITY); + + unsafe { + slice_insert(self.keys_mut(), 0, key); + slice_insert(self.vals_mut(), 0, val); + slice_insert( + slice::from_raw_parts_mut( + self.as_internal_mut().edges.as_mut_ptr(), + self.len()+1 + ), + 0, + edge.node + ); + + self.as_leaf_mut().len += 1; + + self.correct_all_childrens_parent_links(); + } + } +} + +impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { + /// Removes a key/value pair from the end of this node. If this is an internal node, + /// also removes the edge that was to the right of that pair. + pub fn pop(&mut self) -> (K, V, Option>) { + // Necessary for correctness, but this is an internal module + debug_assert!(self.len() > 0); + + let idx = self.len() - 1; + + unsafe { + let key = ptr::read(self.keys().get_unchecked(idx)); + let val = ptr::read(self.vals().get_unchecked(idx)); + let edge = match self.reborrow_mut().force() { + ForceResult::Leaf(_) => None, + ForceResult::Internal(internal) => { + let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1)); + let mut new_root = Root { node: edge, height: internal.height - 1 }; + new_root.as_mut().as_leaf_mut().parent = ptr::null(); + Some(new_root) + } + }; + + self.as_leaf_mut().len -= 1; + (key, val, edge) + } + } + + /// Removes a key/value pair from the beginning of this node. If this is an internal node, + /// also removes the edge that was to the left of that pair. + pub fn pop_front(&mut self) -> (K, V, Option>) { + // Necessary for correctness, but this is an internal module + debug_assert!(self.len() > 0); + + let old_len = self.len(); + + unsafe { + let key = slice_remove(self.keys_mut(), 0); + let val = slice_remove(self.vals_mut(), 0); + let edge = match self.reborrow_mut().force() { + ForceResult::Leaf(_) => None, + ForceResult::Internal(mut internal) => { + let edge = slice_remove( + slice::from_raw_parts_mut( + internal.as_internal_mut().edges.as_mut_ptr(), + old_len+1 + ), + 0 + ); + + let mut new_root = Root { node: edge, height: internal.height - 1 }; + new_root.as_mut().as_leaf_mut().parent = ptr::null(); + + for i in 0..old_len { + Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); + } + + Some(new_root) + } + }; + + self.as_leaf_mut().len -= 1; + + (key, val, edge) + } + } + + fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) { + ( + self.keys_mut().as_mut_ptr(), + self.vals_mut().as_mut_ptr() + ) + } +} + +impl NodeRef { + /// Checks whether a node is an `Internal` node or a `Leaf` node. + pub fn force(self) -> ForceResult< + NodeRef, + NodeRef + > { + if self.height == 0 { + ForceResult::Leaf(NodeRef { + height: self.height, + node: self.node, + root: self.root, + _marker: PhantomData + }) + } else { + ForceResult::Internal(NodeRef { + height: self.height, + node: self.node, + root: self.root, + _marker: PhantomData + }) + } + } +} + +/// A reference to a specific key/value pair or edge within a node. The `Node` parameter +/// must be a `NodeRef`, while the `Type` can either be `KV` (signifying a handle on a key/value +/// pair) or `Edge` (signifying a handle on an edge). +/// +/// Note that even `Leaf` nodes can have `Edge` handles. Instead of representing a pointer to +/// a child node, these represent the spaces where child pointers would go between the key/value +/// pairs. For example, in a node with length 2, there would be 3 possible edge locations - one +/// to the left of the node, one between the two pairs, and one at the right of the node. +pub struct Handle { + node: Node, + idx: usize, + _marker: PhantomData +} + +impl Copy for Handle { } +// We don't need the full generality of `#[derive(Clone)]`, as the only time `Node` will be +// `Clone`able is when it is an immutable reference and therefore `Copy`. +impl Clone for Handle { + fn clone(&self) -> Self { + *self + } +} + +impl Handle { + /// Retrieves the node that contains the edge of key/value pair this handle points to. + pub fn into_node(self) -> Node { + self.node + } +} + +impl Handle, marker::KV> { + /// Creates a new handle to a key/value pair in `node`. `idx` must be less than `node.len()`. + pub fn new_kv(node: NodeRef, idx: usize) -> Self { + // Necessary for correctness, but in a private module + debug_assert!(idx < node.len()); + + Handle { + node, + idx, + _marker: PhantomData + } + } + + pub fn left_edge(self) -> Handle, marker::Edge> { + Handle::new_edge(self.node, self.idx) + } + + pub fn right_edge(self) -> Handle, marker::Edge> { + Handle::new_edge(self.node, self.idx + 1) + } +} + +impl PartialEq + for Handle, HandleType> { + + fn eq(&self, other: &Self) -> bool { + self.node.node == other.node.node && self.idx == other.idx + } +} + +impl + Handle, HandleType> { + + /// Temporarily takes out another, immutable handle on the same location. + pub fn reborrow(&self) + -> Handle, HandleType> { + + // We can't use Handle::new_kv or Handle::new_edge because we don't know our type + Handle { + node: self.node.reborrow(), + idx: self.idx, + _marker: PhantomData + } + } +} + +impl<'a, K, V, NodeType, HandleType> + Handle, K, V, NodeType>, HandleType> { + + /// Temporarily takes out another, mutable handle on the same location. Beware, as + /// this method is very dangerous, doubly so since it may not immediately appear + /// dangerous. + /// + /// Because mutable pointers can roam anywhere around the tree and can even (through + /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` + /// can easily be used to make the original mutable pointer dangling, or, in the case + /// of a reborrowed handle, out of bounds. + // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts + // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + pub unsafe fn reborrow_mut(&mut self) + -> Handle, HandleType> { + + // We can't use Handle::new_kv or Handle::new_edge because we don't know our type + Handle { + node: self.node.reborrow_mut(), + idx: self.idx, + _marker: PhantomData + } + } +} + +impl + Handle, marker::Edge> { + + /// Creates a new handle to an edge in `node`. `idx` must be less than or equal to + /// `node.len()`. + pub fn new_edge(node: NodeRef, idx: usize) -> Self { + // Necessary for correctness, but in a private module + debug_assert!(idx <= node.len()); + + Handle { + node, + idx, + _marker: PhantomData + } + } + + pub fn left_kv(self) + -> Result, marker::KV>, Self> { + + if self.idx > 0 { + Ok(Handle::new_kv(self.node, self.idx - 1)) + } else { + Err(self) + } + } + + pub fn right_kv(self) + -> Result, marker::KV>, Self> { + + if self.idx < self.node.len() { + Ok(Handle::new_kv(self.node, self.idx)) + } else { + Err(self) + } + } +} + +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { + /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// this edge. This method assumes that there is enough space in the node for the new + /// pair to fit. + /// + /// The returned pointer points to the inserted value. + fn insert_fit(&mut self, key: K, val: V) -> *mut V { + // Necessary for correctness, but in a private module + debug_assert!(self.node.len() < CAPACITY); + debug_assert!(!self.node.is_shared_root()); + + unsafe { + slice_insert(self.node.keys_mut(), self.idx, key); + slice_insert(self.node.vals_mut(), self.idx, val); + + self.node.as_leaf_mut().len += 1; + + self.node.vals_mut().get_unchecked_mut(self.idx) + } + } + + /// Inserts a new key/value pair between the key/value pairs to the right and left of + /// this edge. This method splits the node if there isn't enough room. + /// + /// The returned pointer points to the inserted value. + pub fn insert(mut self, key: K, val: V) + -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) { + + if self.node.len() < CAPACITY { + let ptr = self.insert_fit(key, val); + (InsertResult::Fit(Handle::new_kv(self.node, self.idx)), ptr) + } else { + let middle = Handle::new_kv(self.node, B); + let (mut left, k, v, mut right) = middle.split(); + let ptr = if self.idx <= B { + unsafe { + Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val) + } + } else { + unsafe { + Handle::new_edge( + right.as_mut().cast_unchecked::(), + self.idx - (B + 1) + ).insert_fit(key, val) + } + }; + (InsertResult::Split(left, k, v, right), ptr) + } + } +} + +impl<'a, K, V> Handle, K, V, marker::Internal>, marker::Edge> { + /// Fixes the parent pointer and index in the child node below this edge. This is useful + /// when the ordering of edges has been changed, such as in the various `insert` methods. + fn correct_parent_link(mut self) { + let idx = self.idx as u16; + let ptr = self.node.as_internal_mut() as *mut _; + let mut child = self.descend(); + child.as_leaf_mut().parent = ptr; + child.as_leaf_mut().parent_idx = idx; + } + + /// Unsafely asserts to the compiler some static information about whether the underlying + /// node of this handle is a `Leaf`. + unsafe fn cast_unchecked(&mut self) + -> Handle, marker::Edge> { + + Handle::new_edge(self.node.cast_unchecked(), self.idx) + } + + /// Inserts a new key/value pair and an edge that will go to the right of that new pair + /// between this edge and the key/value pair to the right of this edge. This method assumes + /// that there is enough space in the node for the new pair to fit. + fn insert_fit(&mut self, key: K, val: V, edge: Root) { + // Necessary for correctness, but in an internal module + debug_assert!(self.node.len() < CAPACITY); + debug_assert!(edge.height == self.node.height - 1); + + unsafe { + // This cast is a lie, but it allows us to reuse the key/value insertion logic. + self.cast_unchecked::().insert_fit(key, val); + + slice_insert( + slice::from_raw_parts_mut( + self.node.as_internal_mut().edges.as_mut_ptr(), + self.node.len() + ), + self.idx + 1, + edge.node + ); + + for i in (self.idx+1)..(self.node.len()+1) { + Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); + } + } + } + + /// Inserts a new key/value pair and an edge that will go to the right of that new pair + /// between this edge and the key/value pair to the right of this edge. This method splits + /// the node if there isn't enough room. + pub fn insert(mut self, key: K, val: V, edge: Root) + -> InsertResult<'a, K, V, marker::Internal> { + + // Necessary for correctness, but this is an internal module + debug_assert!(edge.height == self.node.height - 1); + + if self.node.len() < CAPACITY { + self.insert_fit(key, val, edge); + InsertResult::Fit(Handle::new_kv(self.node, self.idx)) + } else { + let middle = Handle::new_kv(self.node, B); + let (mut left, k, v, mut right) = middle.split(); + if self.idx <= B { + unsafe { + Handle::new_edge(left.reborrow_mut(), self.idx).insert_fit(key, val, edge); + } + } else { + unsafe { + Handle::new_edge( + right.as_mut().cast_unchecked::(), + self.idx - (B + 1) + ).insert_fit(key, val, edge); + } + } + InsertResult::Split(left, k, v, right) + } + } +} + +impl + Handle, marker::Edge> { + + /// Finds the node pointed to by this edge. + /// + /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should + /// both, upon success, do nothing. + pub fn descend(self) -> NodeRef { + NodeRef { + height: self.node.height - 1, + node: unsafe { self.node.as_internal().edges.get_unchecked(self.idx).as_ptr() }, + root: self.node.root, + _marker: PhantomData + } + } +} + +impl<'a, K: 'a, V: 'a, NodeType> + Handle, K, V, NodeType>, marker::KV> { + + pub fn into_kv(self) -> (&'a K, &'a V) { + let (keys, vals) = self.node.into_slices(); + unsafe { + (keys.get_unchecked(self.idx), vals.get_unchecked(self.idx)) + } + } +} + +impl<'a, K: 'a, V: 'a, NodeType> + Handle, K, V, NodeType>, marker::KV> { + + pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { + let (keys, vals) = self.node.into_slices_mut(); + unsafe { + (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) + } + } +} + +impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { + pub fn kv_mut(&mut self) -> (&mut K, &mut V) { + unsafe { + let (keys, vals) = self.node.reborrow_mut().into_slices_mut(); + (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) + } + } +} + +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> { + /// Splits the underlying node into three parts: + /// + /// - The node is truncated to only contain the key/value pairs to the right of + /// this handle. + /// - The key and value pointed to by this handle and extracted. + /// - All the key/value pairs to the right of this handle are put into a newly + /// allocated node. + pub fn split(mut self) + -> (NodeRef, K, V, marker::Leaf>, K, V, Root) { + debug_assert!(!self.node.is_shared_root()); + unsafe { + let mut new_node = Box::new(LeafNode::new()); + + let k = ptr::read(self.node.keys().get_unchecked(self.idx)); + let v = ptr::read(self.node.vals().get_unchecked(self.idx)); + + let new_len = self.node.len() - self.idx - 1; + + ptr::copy_nonoverlapping( + self.node.keys().as_ptr().offset(self.idx as isize + 1), + new_node.keys.as_mut_ptr(), + new_len + ); + ptr::copy_nonoverlapping( + self.node.vals().as_ptr().offset(self.idx as isize + 1), + new_node.vals.as_mut_ptr(), + new_len + ); + + self.node.as_leaf_mut().len = self.idx as u16; + new_node.len = new_len as u16; + + ( + self.node, + k, v, + Root { + node: BoxedNode::from_leaf(new_node), + height: 0 + } + ) + } + } + + /// Removes the key/value pair pointed to by this handle, returning the edge between the + /// now adjacent key/value pairs to the left and right of this handle. + pub fn remove(mut self) + -> (Handle, K, V, marker::Leaf>, marker::Edge>, K, V) { + debug_assert!(!self.node.is_shared_root()); + unsafe { + let k = slice_remove(self.node.keys_mut(), self.idx); + let v = slice_remove(self.node.vals_mut(), self.idx); + self.node.as_leaf_mut().len -= 1; + (self.left_edge(), k, v) + } + } +} + +impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { + /// Splits the underlying node into three parts: + /// + /// - The node is truncated to only contain the edges and key/value pairs to the + /// right of this handle. + /// - The key and value pointed to by this handle and extracted. + /// - All the edges and key/value pairs to the right of this handle are put into + /// a newly allocated node. + pub fn split(mut self) + -> (NodeRef, K, V, marker::Internal>, K, V, Root) { + unsafe { + let mut new_node = Box::new(InternalNode::new()); + + let k = ptr::read(self.node.keys().get_unchecked(self.idx)); + let v = ptr::read(self.node.vals().get_unchecked(self.idx)); + + let height = self.node.height; + let new_len = self.node.len() - self.idx - 1; + + ptr::copy_nonoverlapping( + self.node.keys().as_ptr().offset(self.idx as isize + 1), + new_node.data.keys.as_mut_ptr(), + new_len + ); + ptr::copy_nonoverlapping( + self.node.vals().as_ptr().offset(self.idx as isize + 1), + new_node.data.vals.as_mut_ptr(), + new_len + ); + ptr::copy_nonoverlapping( + self.node.as_internal().edges.as_ptr().offset(self.idx as isize + 1), + new_node.edges.as_mut_ptr(), + new_len + 1 + ); + + self.node.as_leaf_mut().len = self.idx as u16; + new_node.data.len = new_len as u16; + + let mut new_root = Root { + node: BoxedNode::from_internal(new_node), + height, + }; + + for i in 0..(new_len+1) { + Handle::new_edge(new_root.as_mut().cast_unchecked(), i).correct_parent_link(); + } + + ( + self.node, + k, v, + new_root + ) + } + } + + /// Returns whether it is valid to call `.merge()`, i.e., whether there is enough room in + /// a node to hold the combination of the nodes to the left and right of this handle along + /// with the key/value pair at this handle. + pub fn can_merge(&self) -> bool { + ( + self.reborrow() + .left_edge() + .descend() + .len() + + self.reborrow() + .right_edge() + .descend() + .len() + + 1 + ) <= CAPACITY + } + + /// Combines the node immediately to the left of this handle, the key/value pair pointed + /// to by this handle, and the node immediately to the right of this handle into one new + /// child of the underlying node, returning an edge referencing that new child. + /// + /// Assumes that this edge `.can_merge()`. + pub fn merge(mut self) + -> Handle, K, V, marker::Internal>, marker::Edge> { + let self1 = unsafe { ptr::read(&self) }; + let self2 = unsafe { ptr::read(&self) }; + let mut left_node = self1.left_edge().descend(); + let left_len = left_node.len(); + let mut right_node = self2.right_edge().descend(); + let right_len = right_node.len(); + + // necessary for correctness, but in a private module + debug_assert!(left_len + right_len + 1 <= CAPACITY); + + unsafe { + ptr::write(left_node.keys_mut().get_unchecked_mut(left_len), + slice_remove(self.node.keys_mut(), self.idx)); + ptr::copy_nonoverlapping( + right_node.keys().as_ptr(), + left_node.keys_mut().as_mut_ptr().offset(left_len as isize + 1), + right_len + ); + ptr::write(left_node.vals_mut().get_unchecked_mut(left_len), + slice_remove(self.node.vals_mut(), self.idx)); + ptr::copy_nonoverlapping( + right_node.vals().as_ptr(), + left_node.vals_mut().as_mut_ptr().offset(left_len as isize + 1), + right_len + ); + + slice_remove(&mut self.node.as_internal_mut().edges, self.idx + 1); + for i in self.idx+1..self.node.len() { + Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); + } + self.node.as_leaf_mut().len -= 1; + + left_node.as_leaf_mut().len += right_len as u16 + 1; + + if self.node.height > 1 { + ptr::copy_nonoverlapping( + right_node.cast_unchecked().as_internal().edges.as_ptr(), + left_node.cast_unchecked() + .as_internal_mut() + .edges + .as_mut_ptr() + .offset(left_len as isize + 1), + right_len + 1 + ); + + for i in left_len+1..left_len+right_len+2 { + Handle::new_edge( + left_node.cast_unchecked().reborrow_mut(), + i + ).correct_parent_link(); + } + + Global.dealloc( + right_node.node.cast(), + Layout::new::>(), + ); + } else { + Global.dealloc( + right_node.node.cast(), + Layout::new::>(), + ); + } + + Handle::new_edge(self.node, self.idx) + } + } + + /// This removes a key/value pair from the left child and replaces it with the key/value pair + /// pointed to by this handle while pushing the old key/value pair of this handle into the right + /// child. + pub fn steal_left(&mut self) { + unsafe { + let (k, v, edge) = self.reborrow_mut().left_edge().descend().pop(); + + let k = mem::replace(self.reborrow_mut().into_kv_mut().0, k); + let v = mem::replace(self.reborrow_mut().into_kv_mut().1, v); + + match self.reborrow_mut().right_edge().descend().force() { + ForceResult::Leaf(mut leaf) => leaf.push_front(k, v), + ForceResult::Internal(mut internal) => internal.push_front(k, v, edge.unwrap()) + } + } + } + + /// This removes a key/value pair from the right child and replaces it with the key/value pair + /// pointed to by this handle while pushing the old key/value pair of this handle into the left + /// child. + pub fn steal_right(&mut self) { + unsafe { + let (k, v, edge) = self.reborrow_mut().right_edge().descend().pop_front(); + + let k = mem::replace(self.reborrow_mut().into_kv_mut().0, k); + let v = mem::replace(self.reborrow_mut().into_kv_mut().1, v); + + match self.reborrow_mut().left_edge().descend().force() { + ForceResult::Leaf(mut leaf) => leaf.push(k, v), + ForceResult::Internal(mut internal) => internal.push(k, v, edge.unwrap()) + } + } + } + + /// This does stealing similar to `steal_left` but steals multiple elements at once. + pub fn bulk_steal_left(&mut self, count: usize) { + unsafe { + let mut left_node = ptr::read(self).left_edge().descend(); + let left_len = left_node.len(); + let mut right_node = ptr::read(self).right_edge().descend(); + let right_len = right_node.len(); + + // Make sure that we may steal safely. + debug_assert!(right_len + count <= CAPACITY); + debug_assert!(left_len >= count); + + let new_left_len = left_len - count; + + // Move data. + { + let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); + let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); + let parent_kv = { + let kv = self.reborrow_mut().into_kv_mut(); + (kv.0 as *mut K, kv.1 as *mut V) + }; + + // Make room for stolen elements in the right child. + ptr::copy(right_kv.0, + right_kv.0.offset(count as isize), + right_len); + ptr::copy(right_kv.1, + right_kv.1.offset(count as isize), + right_len); + + // Move elements from the left child to the right one. + move_kv(left_kv, new_left_len + 1, right_kv, 0, count - 1); + + // Move parent's key/value pair to the right child. + move_kv(parent_kv, 0, right_kv, count - 1, 1); + + // Move the left-most stolen pair to the parent. + move_kv(left_kv, new_left_len, parent_kv, 0, 1); + } + + left_node.reborrow_mut().as_leaf_mut().len -= count as u16; + right_node.reborrow_mut().as_leaf_mut().len += count as u16; + + match (left_node.force(), right_node.force()) { + (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { + // Make room for stolen edges. + let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); + ptr::copy(right_edges, + right_edges.offset(count as isize), + right_len + 1); + right.correct_childrens_parent_links(count, count + right_len + 1); + + move_edges(left, new_left_len + 1, right, 0, count); + }, + (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { } + _ => { unreachable!(); } + } + } + } + + /// The symmetric clone of `bulk_steal_left`. + pub fn bulk_steal_right(&mut self, count: usize) { + unsafe { + let mut left_node = ptr::read(self).left_edge().descend(); + let left_len = left_node.len(); + let mut right_node = ptr::read(self).right_edge().descend(); + let right_len = right_node.len(); + + // Make sure that we may steal safely. + debug_assert!(left_len + count <= CAPACITY); + debug_assert!(right_len >= count); + + let new_right_len = right_len - count; + + // Move data. + { + let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); + let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); + let parent_kv = { + let kv = self.reborrow_mut().into_kv_mut(); + (kv.0 as *mut K, kv.1 as *mut V) + }; + + // Move parent's key/value pair to the left child. + move_kv(parent_kv, 0, left_kv, left_len, 1); + + // Move elements from the right child to the left one. + move_kv(right_kv, 0, left_kv, left_len + 1, count - 1); + + // Move the right-most stolen pair to the parent. + move_kv(right_kv, count - 1, parent_kv, 0, 1); + + // Fix right indexing + ptr::copy(right_kv.0.offset(count as isize), + right_kv.0, + new_right_len); + ptr::copy(right_kv.1.offset(count as isize), + right_kv.1, + new_right_len); + } + + left_node.reborrow_mut().as_leaf_mut().len += count as u16; + right_node.reborrow_mut().as_leaf_mut().len -= count as u16; + + match (left_node.force(), right_node.force()) { + (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { + move_edges(right.reborrow_mut(), 0, left, left_len + 1, count); + + // Fix right indexing. + let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); + ptr::copy(right_edges.offset(count as isize), + right_edges, + new_right_len + 1); + right.correct_childrens_parent_links(0, new_right_len + 1); + }, + (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { } + _ => { unreachable!(); } + } + } + } +} + +unsafe fn move_kv( + source: (*mut K, *mut V), source_offset: usize, + dest: (*mut K, *mut V), dest_offset: usize, + count: usize) +{ + ptr::copy_nonoverlapping(source.0.offset(source_offset as isize), + dest.0.offset(dest_offset as isize), + count); + ptr::copy_nonoverlapping(source.1.offset(source_offset as isize), + dest.1.offset(dest_offset as isize), + count); +} + +// Source and destination must have the same height. +unsafe fn move_edges( + mut source: NodeRef, source_offset: usize, + mut dest: NodeRef, dest_offset: usize, + count: usize) +{ + let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); + let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); + ptr::copy_nonoverlapping(source_ptr.offset(source_offset as isize), + dest_ptr.offset(dest_offset as isize), + count); + dest.correct_childrens_parent_links(dest_offset, dest_offset + count); +} + +impl + Handle, HandleType> { + + /// Check whether the underlying node is an `Internal` node or a `Leaf` node. + pub fn force(self) -> ForceResult< + Handle, HandleType>, + Handle, HandleType> + > { + match self.node.force() { + ForceResult::Leaf(node) => ForceResult::Leaf(Handle { + node, + idx: self.idx, + _marker: PhantomData + }), + ForceResult::Internal(node) => ForceResult::Internal(Handle { + node, + idx: self.idx, + _marker: PhantomData + }) + } + } +} + +impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { + /// Move the suffix after `self` from one node to another one. `right` must be empty. + /// The first edge of `right` remains unchanged. + pub fn move_suffix(&mut self, + right: &mut NodeRef, K, V, marker::LeafOrInternal>) { + unsafe { + let left_new_len = self.idx; + let mut left_node = self.reborrow_mut().into_node(); + + let right_new_len = left_node.len() - left_new_len; + let mut right_node = right.reborrow_mut(); + + debug_assert!(right_node.len() == 0); + debug_assert!(left_node.height == right_node.height); + + let left_kv = left_node.reborrow_mut().into_kv_pointers_mut(); + let right_kv = right_node.reborrow_mut().into_kv_pointers_mut(); + + + move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); + + left_node.reborrow_mut().as_leaf_mut().len = left_new_len as u16; + right_node.reborrow_mut().as_leaf_mut().len = right_new_len as u16; + + match (left_node.force(), right_node.force()) { + (ForceResult::Internal(left), ForceResult::Internal(right)) => { + move_edges(left, left_new_len + 1, right, 1, right_new_len); + }, + (ForceResult::Leaf(_), ForceResult::Leaf(_)) => { } + _ => { unreachable!(); } + } + } + } +} + +pub enum ForceResult { + Leaf(Leaf), + Internal(Internal) +} + +pub enum InsertResult<'a, K, V, Type> { + Fit(Handle, K, V, Type>, marker::KV>), + Split(NodeRef, K, V, Type>, K, V, Root) +} + +pub mod marker { + use core::marker::PhantomData; + + pub enum Leaf { } + pub enum Internal { } + pub enum LeafOrInternal { } + + pub enum Owned { } + pub struct Immut<'a>(PhantomData<&'a ()>); + pub struct Mut<'a>(PhantomData<&'a mut ()>); + + pub enum KV { } + pub enum Edge { } +} + +unsafe fn slice_insert(slice: &mut [T], idx: usize, val: T) { + ptr::copy( + slice.as_ptr().offset(idx as isize), + slice.as_mut_ptr().offset(idx as isize + 1), + slice.len() - idx + ); + ptr::write(slice.get_unchecked_mut(idx), val); +} + +unsafe fn slice_remove(slice: &mut [T], idx: usize) -> T { + let ret = ptr::read(slice.get_unchecked(idx)); + ptr::copy( + slice.as_ptr().offset(idx as isize + 1), + slice.as_mut_ptr().offset(idx as isize), + slice.len() - idx - 1 + ); + ret +} diff --git a/src/liballoc/collections/btree/search.rs b/src/liballoc/collections/btree/search.rs new file mode 100644 index 00000000000..bc1272fbc78 --- /dev/null +++ b/src/liballoc/collections/btree/search.rs @@ -0,0 +1,75 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::cmp::Ordering; + +use borrow::Borrow; + +use super::node::{Handle, NodeRef, marker}; + +use super::node::ForceResult::*; +use self::SearchResult::*; + +pub enum SearchResult { + Found(Handle, marker::KV>), + GoDown(Handle, marker::Edge>) +} + +pub fn search_tree( + mut node: NodeRef, + key: &Q +) -> SearchResult + where Q: Ord, K: Borrow { + + loop { + match search_node(node, key) { + Found(handle) => return Found(handle), + GoDown(handle) => match handle.force() { + Leaf(leaf) => return GoDown(leaf), + Internal(internal) => { + node = internal.descend(); + continue; + } + } + } + } +} + +pub fn search_node( + node: NodeRef, + key: &Q +) -> SearchResult + where Q: Ord, K: Borrow { + + match search_linear(&node, key) { + (idx, true) => Found( + Handle::new_kv(node, idx) + ), + (idx, false) => SearchResult::GoDown( + Handle::new_edge(node, idx) + ) + } +} + +pub fn search_linear( + node: &NodeRef, + key: &Q +) -> (usize, bool) + where Q: Ord, K: Borrow { + + for (i, k) in node.keys().iter().enumerate() { + match key.cmp(k.borrow()) { + Ordering::Greater => {}, + Ordering::Equal => return (i, true), + Ordering::Less => return (i, false) + } + } + (node.keys().len(), false) +} diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs new file mode 100644 index 00000000000..af9a7074e4a --- /dev/null +++ b/src/liballoc/collections/btree/set.rs @@ -0,0 +1,1153 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface +// to TreeMap + +use core::cmp::Ordering::{self, Less, Greater, Equal}; +use core::cmp::{min, max}; +use core::fmt::Debug; +use core::fmt; +use core::iter::{Peekable, FromIterator, FusedIterator}; +use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; + +use borrow::Borrow; +use collections::btree_map::{self, BTreeMap, Keys}; +use super::Recover; + +// FIXME(conventions): implement bounded iterators + +/// A set based on a B-Tree. +/// +/// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance +/// benefits and drawbacks. +/// +/// It is a logic error for an item to be modified in such a way that the item's ordering relative +/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// [`BTreeMap`]: struct.BTreeMap.html +/// [`Ord`]: ../../std/cmp/trait.Ord.html +/// [`Cell`]: ../../std/cell/struct.Cell.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// +/// # Examples +/// +/// ``` +/// use std::collections::BTreeSet; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `BTreeSet<&str>` in this example). +/// let mut books = BTreeSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons"); +/// books.insert("To Kill a Mockingbird"); +/// books.insert("The Odyssey"); +/// books.insert("The Great Gatsby"); +/// +/// // Check for a specific one. +/// if !books.contains("The Winds of Winter") { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove("The Odyssey"); +/// +/// // Iterate over everything. +/// for book in &books { +/// println!("{}", book); +/// } +/// ``` +#[derive(Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BTreeSet { + map: BTreeMap, +} + +/// An iterator over the items of a `BTreeSet`. +/// +/// This `struct` is created by the [`iter`] method on [`BTreeSet`]. +/// See its documentation for more. +/// +/// [`BTreeSet`]: struct.BTreeSet.html +/// [`iter`]: struct.BTreeSet.html#method.iter +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + iter: Keys<'a, T, ()>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Iter") + .field(&self.iter.clone()) + .finish() + } +} + +/// An owning iterator over the items of a `BTreeSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`BTreeSet`]: struct.BTreeSet.html +/// [`into_iter`]: struct.BTreeSet.html#method.into_iter +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] +pub struct IntoIter { + iter: btree_map::IntoIter, +} + +/// An iterator over a sub-range of items in a `BTreeSet`. +/// +/// This `struct` is created by the [`range`] method on [`BTreeSet`]. +/// See its documentation for more. +/// +/// [`BTreeSet`]: struct.BTreeSet.html +/// [`range`]: struct.BTreeSet.html#method.range +#[derive(Debug)] +#[stable(feature = "btree_range", since = "1.17.0")] +pub struct Range<'a, T: 'a> { + iter: btree_map::Range<'a, T, ()>, +} + +/// A lazy iterator producing elements in the difference of `BTreeSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`BTreeSet`]. +/// See its documentation for more. +/// +/// [`BTreeSet`]: struct.BTreeSet.html +/// [`difference`]: struct.BTreeSet.html#method.difference +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Difference<'a, T: 'a> { + a: Peekable>, + b: Peekable>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Difference") + .field(&self.a) + .field(&self.b) + .finish() + } +} + +/// A lazy iterator producing elements in the symmetric difference of `BTreeSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`BTreeSet`]. See its documentation for more. +/// +/// [`BTreeSet`]: struct.BTreeSet.html +/// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SymmetricDifference<'a, T: 'a> { + a: Peekable>, + b: Peekable>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SymmetricDifference") + .field(&self.a) + .field(&self.b) + .finish() + } +} + +/// A lazy iterator producing elements in the intersection of `BTreeSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`BTreeSet`]. +/// See its documentation for more. +/// +/// [`BTreeSet`]: struct.BTreeSet.html +/// [`intersection`]: struct.BTreeSet.html#method.intersection +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Intersection<'a, T: 'a> { + a: Peekable>, + b: Peekable>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Intersection") + .field(&self.a) + .field(&self.b) + .finish() + } +} + +/// A lazy iterator producing elements in the union of `BTreeSet`s. +/// +/// This `struct` is created by the [`union`] method on [`BTreeSet`]. +/// See its documentation for more. +/// +/// [`BTreeSet`]: struct.BTreeSet.html +/// [`union`]: struct.BTreeSet.html#method.union +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Union<'a, T: 'a> { + a: Peekable>, + b: Peekable>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Union") + .field(&self.a) + .field(&self.b) + .finish() + } +} + +impl BTreeSet { + /// Makes a new `BTreeSet` with a reasonable choice of B. + /// + /// # Examples + /// + /// ``` + /// # #![allow(unused_mut)] + /// use std::collections::BTreeSet; + /// + /// let mut set: BTreeSet = BTreeSet::new(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> BTreeSet { + BTreeSet { map: BTreeMap::new() } + } + + /// Constructs a double-ended iterator over a sub-range of elements in the set. + /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will + /// yield elements from min (inclusive) to max (exclusive). + /// The range may also be entered as `(Bound, Bound)`, so for example + /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive + /// range from 4 to 10. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// use std::ops::Bound::Included; + /// + /// let mut set = BTreeSet::new(); + /// set.insert(3); + /// set.insert(5); + /// set.insert(8); + /// for &elem in set.range((Included(&4), Included(&8))) { + /// println!("{}", elem); + /// } + /// assert_eq!(Some(&5), set.range(4..).next()); + /// ``` + #[stable(feature = "btree_range", since = "1.17.0")] + pub fn range(&self, range: R) -> Range + where K: Ord, T: Borrow, R: RangeBounds + { + Range { iter: self.map.range(range) } + } + + /// Visits the values representing the difference, + /// i.e. the values that are in `self` but not in `other`, + /// in ascending order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1); + /// a.insert(2); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2); + /// b.insert(3); + /// + /// let diff: Vec<_> = a.difference(&b).cloned().collect(); + /// assert_eq!(diff, [1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn difference<'a>(&'a self, other: &'a BTreeSet) -> Difference<'a, T> { + Difference { + a: self.iter().peekable(), + b: other.iter().peekable(), + } + } + + /// Visits the values representing the symmetric difference, + /// i.e. the values that are in `self` or in `other` but not in both, + /// in ascending order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1); + /// a.insert(2); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2); + /// b.insert(3); + /// + /// let sym_diff: Vec<_> = a.symmetric_difference(&b).cloned().collect(); + /// assert_eq!(sym_diff, [1, 3]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn symmetric_difference<'a>(&'a self, + other: &'a BTreeSet) + -> SymmetricDifference<'a, T> { + SymmetricDifference { + a: self.iter().peekable(), + b: other.iter().peekable(), + } + } + + /// Visits the values representing the intersection, + /// i.e. the values that are both in `self` and `other`, + /// in ascending order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1); + /// a.insert(2); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2); + /// b.insert(3); + /// + /// let intersection: Vec<_> = a.intersection(&b).cloned().collect(); + /// assert_eq!(intersection, [2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn intersection<'a>(&'a self, other: &'a BTreeSet) -> Intersection<'a, T> { + Intersection { + a: self.iter().peekable(), + b: other.iter().peekable(), + } + } + + /// Visits the values representing the union, + /// i.e. all the values in `self` or `other`, without duplicates, + /// in ascending order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(2); + /// + /// let union: Vec<_> = a.union(&b).cloned().collect(); + /// assert_eq!(union, [1, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn union<'a>(&'a self, other: &'a BTreeSet) -> Union<'a, T> { + Union { + a: self.iter().peekable(), + b: other.iter().peekable(), + } + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut v = BTreeSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { + self.map.clear() + } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, + /// but the ordering on the borrowed form *must* match the + /// ordering on the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn contains(&self, value: &Q) -> bool + where T: Borrow, + Q: Ord + { + self.map.contains_key(value) + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, + /// but the ordering on the borrowed form *must* match the + /// ordering on the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.get(&2), Some(&2)); + /// assert_eq!(set.get(&4), None); + /// ``` + #[stable(feature = "set_recovery", since = "1.9.0")] + pub fn get(&self, value: &Q) -> Option<&T> + where T: Borrow, + Q: Ord + { + Recover::get(&self.map, value) + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut b = BTreeSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_disjoint(&self, other: &BTreeSet) -> bool { + self.intersection(other).next().is_none() + } + + /// Returns `true` if the set is a subset of another, + /// i.e. `other` contains at least all the values in `self`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let sup: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); + /// let mut set = BTreeSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_subset(&self, other: &BTreeSet) -> bool { + // Stolen from TreeMap + let mut x = self.iter(); + let mut y = other.iter(); + let mut a = x.next(); + let mut b = y.next(); + while a.is_some() { + if b.is_none() { + return false; + } + + let a1 = a.unwrap(); + let b1 = b.unwrap(); + + match b1.cmp(a1) { + Less => (), + Greater => return false, + Equal => a = x.next(), + } + + b = y.next(); + } + true + } + + /// Returns `true` if the set is a superset of another, + /// i.e. `self` contains at least all the values in `other`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let sub: BTreeSet<_> = [1, 2].iter().cloned().collect(); + /// let mut set = BTreeSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_superset(&self, other: &BTreeSet) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, `true` is returned. + /// + /// If the set did have this value present, `false` is returned, and the + /// entry is not updated. See the [module-level documentation] for more. + /// + /// [module-level documentation]: index.html#insert-and-complex-keys + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::new(); + /// set.insert(Vec::::new()); + /// + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); + /// set.replace(Vec::with_capacity(10)); + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); + /// ``` + #[stable(feature = "set_recovery", since = "1.9.0")] + pub fn replace(&mut self, value: T) -> Option { + Recover::replace(&mut self.map, value) + } + + /// Removes a value from the set. Returns `true` if the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, + /// but the ordering on the borrowed form *must* match the + /// ordering on the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut set = BTreeSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(&mut self, value: &Q) -> bool + where T: Borrow, + Q: Ord + { + self.map.remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, + /// but the ordering on the borrowed form *must* match the + /// ordering on the value type. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.take(&2), Some(2)); + /// assert_eq!(set.take(&2), None); + /// ``` + #[stable(feature = "set_recovery", since = "1.9.0")] + pub fn take(&mut self, value: &Q) -> Option + where T: Borrow, + Q: Ord + { + Recover::take(&mut self.map, value) + } + + /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1); + /// a.insert(2); + /// a.insert(3); + /// + /// let mut b = BTreeSet::new(); + /// b.insert(3); + /// b.insert(4); + /// b.insert(5); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 5); + /// assert_eq!(b.len(), 0); + /// + /// assert!(a.contains(&1)); + /// assert!(a.contains(&2)); + /// assert!(a.contains(&3)); + /// assert!(a.contains(&4)); + /// assert!(a.contains(&5)); + /// ``` + #[stable(feature = "btree_append", since = "1.11.0")] + pub fn append(&mut self, other: &mut Self) { + self.map.append(&mut other.map); + } + + /// Splits the collection into two at the given key. Returns everything after the given key, + /// including the key. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut a = BTreeSet::new(); + /// a.insert(1); + /// a.insert(2); + /// a.insert(3); + /// a.insert(17); + /// a.insert(41); + /// + /// let b = a.split_off(&3); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 3); + /// + /// assert!(a.contains(&1)); + /// assert!(a.contains(&2)); + /// + /// assert!(b.contains(&3)); + /// assert!(b.contains(&17)); + /// assert!(b.contains(&41)); + /// ``` + #[stable(feature = "btree_split_off", since = "1.11.0")] + pub fn split_off(&mut self, key: &Q) -> Self where T: Borrow { + BTreeSet { map: self.map.split_off(key) } + } +} + +impl BTreeSet { + /// Gets an iterator that visits the values in the `BTreeSet` in ascending order. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let set: BTreeSet = [1, 2, 3].iter().cloned().collect(); + /// let mut set_iter = set.iter(); + /// assert_eq!(set_iter.next(), Some(&1)); + /// assert_eq!(set_iter.next(), Some(&2)); + /// assert_eq!(set_iter.next(), Some(&3)); + /// assert_eq!(set_iter.next(), None); + /// ``` + /// + /// Values returned by the iterator are returned in ascending order: + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let set: BTreeSet = [3, 1, 2].iter().cloned().collect(); + /// let mut set_iter = set.iter(); + /// assert_eq!(set_iter.next(), Some(&1)); + /// assert_eq!(set_iter.next(), Some(&2)); + /// assert_eq!(set_iter.next(), Some(&3)); + /// assert_eq!(set_iter.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter { + Iter { iter: self.map.keys() } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut v = BTreeSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let mut v = BTreeSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator for BTreeSet { + fn from_iter>(iter: I) -> BTreeSet { + let mut set = BTreeSet::new(); + set.extend(iter); + set + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for BTreeSet { + type Item = T; + type IntoIter = IntoIter; + + /// Gets an iterator for moving out the `BTreeSet`'s contents. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let set: BTreeSet = [1, 2, 3, 4].iter().cloned().collect(); + /// + /// let v: Vec<_> = set.into_iter().collect(); + /// assert_eq!(v, [1, 2, 3, 4]); + /// ``` + fn into_iter(self) -> IntoIter { + IntoIter { iter: self.map.into_iter() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a BTreeSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend for BTreeSet { + #[inline] + fn extend>(&mut self, iter: Iter) { + for elem in iter { + self.insert(elem); + } + } +} + +#[stable(feature = "extend_ref", since = "1.2.0")] +impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for BTreeSet { + /// Makes an empty `BTreeSet` with a reasonable choice of B. + fn default() -> BTreeSet { + BTreeSet::new() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T: Ord + Clone> Sub<&'b BTreeSet> for &'a BTreeSet { + type Output = BTreeSet; + + /// Returns the difference of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let result = &a - &b; + /// let result_vec: Vec<_> = result.into_iter().collect(); + /// assert_eq!(result_vec, [1, 2]); + /// ``` + fn sub(self, rhs: &BTreeSet) -> BTreeSet { + self.difference(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T: Ord + Clone> BitXor<&'b BTreeSet> for &'a BTreeSet { + type Output = BTreeSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let result = &a ^ &b; + /// let result_vec: Vec<_> = result.into_iter().collect(); + /// assert_eq!(result_vec, [1, 4]); + /// ``` + fn bitxor(self, rhs: &BTreeSet) -> BTreeSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T: Ord + Clone> BitAnd<&'b BTreeSet> for &'a BTreeSet { + type Output = BTreeSet; + + /// Returns the intersection of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let result = &a & &b; + /// let result_vec: Vec<_> = result.into_iter().collect(); + /// assert_eq!(result_vec, [2, 3]); + /// ``` + fn bitand(self, rhs: &BTreeSet) -> BTreeSet { + self.intersection(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b, T: Ord + Clone> BitOr<&'b BTreeSet> for &'a BTreeSet { + type Output = BTreeSet; + + /// Returns the union of `self` and `rhs` as a new `BTreeSet`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeSet; + /// + /// let a: BTreeSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: BTreeSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let result = &a | &b; + /// let result_vec: Vec<_> = result.into_iter().collect(); + /// assert_eq!(result_vec, [1, 2, 3, 4, 5]); + /// ``` + fn bitor(self, rhs: &BTreeSet) -> BTreeSet { + self.union(rhs).cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Debug for BTreeSet { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for Iter<'a, T> { + fn clone(&self) -> Iter<'a, T> { + Iter { iter: self.iter.clone() } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + fn next_back(&mut self) -> Option<&'a T> { + self.iter.next_back() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn len(&self) -> usize { self.iter.len() } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.iter.next().map(|(k, _)| k) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|(k, _)| k) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + fn len(&self) -> usize { self.iter.len() } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, T> Clone for Range<'a, T> { + fn clone(&self) -> Range<'a, T> { + Range { iter: self.iter.clone() } + } +} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, T> Iterator for Range<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + self.iter.next().map(|(k, _)| k) + } +} + +#[stable(feature = "btree_range", since = "1.17.0")] +impl<'a, T> DoubleEndedIterator for Range<'a, T> { + fn next_back(&mut self) -> Option<&'a T> { + self.iter.next_back().map(|(k, _)| k) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T> FusedIterator for Range<'a, T> {} + +/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None +fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering { + match (x, y) { + (None, _) => short, + (_, None) => long, + (Some(x1), Some(y1)) => x1.cmp(y1), + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for Difference<'a, T> { + fn clone(&self) -> Difference<'a, T> { + Difference { + a: self.a.clone(), + b: self.b.clone(), + } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: Ord> Iterator for Difference<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + loop { + match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) { + Less => return self.a.next(), + Equal => { + self.a.next(); + self.b.next(); + } + Greater => { + self.b.next(); + } + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let a_len = self.a.len(); + let b_len = self.b.len(); + (a_len.saturating_sub(b_len), Some(a_len)) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for SymmetricDifference<'a, T> { + fn clone(&self) -> SymmetricDifference<'a, T> { + SymmetricDifference { + a: self.a.clone(), + b: self.b.clone(), + } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + loop { + match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) { + Less => return self.a.next(), + Equal => { + self.a.next(); + self.b.next(); + } + Greater => return self.b.next(), + } + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.a.len() + self.b.len())) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for Intersection<'a, T> { + fn clone(&self) -> Intersection<'a, T> { + Intersection { + a: self.a.clone(), + b: self.b.clone(), + } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: Ord> Iterator for Intersection<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + loop { + match Ord::cmp(self.a.peek()?, self.b.peek()?) { + Less => { + self.a.next(); + } + Equal => { + self.b.next(); + return self.a.next(); + } + Greater => { + self.b.next(); + } + } + } + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(min(self.a.len(), self.b.len()))) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for Union<'a, T> { + fn clone(&self) -> Union<'a, T> { + Union { + a: self.a.clone(), + b: self.b.clone(), + } + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: Ord> Iterator for Union<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) { + Less => self.a.next(), + Equal => { + self.b.next(); + self.a.next() + } + Greater => self.b.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + let a_len = self.a.len(); + let b_len = self.b.len(); + (max(a_len, b_len), Some(a_len + b_len)) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T: Ord> FusedIterator for Union<'a, T> {} diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs new file mode 100644 index 00000000000..9844de9a57d --- /dev/null +++ b/src/liballoc/collections/linked_list.rs @@ -0,0 +1,1486 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A doubly-linked list with owned nodes. +//! +//! The `LinkedList` allows pushing and popping elements at either end +//! in constant time. +//! +//! Almost always it is better to use `Vec` or [`VecDeque`] instead of +//! [`LinkedList`]. In general, array-based containers are faster, +//! more memory efficient and make better use of CPU cache. +//! +//! [`LinkedList`]: ../linked_list/struct.LinkedList.html +//! [`VecDeque`]: ../vec_deque/struct.VecDeque.html + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hasher, Hash}; +use core::iter::{FromIterator, FusedIterator}; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; + +use boxed::Box; +use super::SpecExtend; + +/// A doubly-linked list with owned nodes. +/// +/// The `LinkedList` allows pushing and popping elements at either end +/// in constant time. +/// +/// Almost always it is better to use `Vec` or `VecDeque` instead of +/// `LinkedList`. In general, array-based containers are faster, +/// more memory efficient and make better use of CPU cache. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct LinkedList { + head: Option>>, + tail: Option>>, + len: usize, + marker: PhantomData>>, +} + +struct Node { + next: Option>>, + prev: Option>>, + element: T, +} + +/// An iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`iter`] method on [`LinkedList`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.LinkedList.html#method.iter +/// [`LinkedList`]: struct.LinkedList.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + head: Option>>, + tail: Option>>, + len: usize, + marker: PhantomData<&'a Node>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Iter") + .field(&self.len) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for Iter<'a, T> { + fn clone(&self) -> Self { + Iter { ..*self } + } +} + +/// A mutable iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`LinkedList`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.LinkedList.html#method.iter_mut +/// [`LinkedList`]: struct.LinkedList.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + list: &'a mut LinkedList, + head: Option>>, + tail: Option>>, + len: usize, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IterMut") + .field(&self.list) + .field(&self.len) + .finish() + } +} + +/// An owning iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.LinkedList.html#method.into_iter +/// [`LinkedList`]: struct.LinkedList.html +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter { + list: LinkedList, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IntoIter") + .field(&self.list) + .finish() + } +} + +impl Node { + fn new(element: T) -> Self { + Node { + next: None, + prev: None, + element, + } + } + + fn into_element(self: Box) -> T { + self.element + } +} + +// private methods +impl LinkedList { + /// Adds the given node to the front of the list. + #[inline] + fn push_front_node(&mut self, mut node: Box>) { + unsafe { + node.next = self.head; + node.prev = None; + let node = Some(Box::into_raw_non_null(node)); + + match self.head { + None => self.tail = node, + Some(mut head) => head.as_mut().prev = node, + } + + self.head = node; + self.len += 1; + } + } + + /// Removes and returns the node at the front of the list. + #[inline] + fn pop_front_node(&mut self) -> Option>> { + self.head.map(|node| unsafe { + let node = Box::from_raw(node.as_ptr()); + self.head = node.next; + + match self.head { + None => self.tail = None, + Some(mut head) => head.as_mut().prev = None, + } + + self.len -= 1; + node + }) + } + + /// Adds the given node to the back of the list. + #[inline] + fn push_back_node(&mut self, mut node: Box>) { + unsafe { + node.next = None; + node.prev = self.tail; + let node = Some(Box::into_raw_non_null(node)); + + match self.tail { + None => self.head = node, + Some(mut tail) => tail.as_mut().next = node, + } + + self.tail = node; + self.len += 1; + } + } + + /// Removes and returns the node at the back of the list. + #[inline] + fn pop_back_node(&mut self) -> Option>> { + self.tail.map(|node| unsafe { + let node = Box::from_raw(node.as_ptr()); + self.tail = node.prev; + + match self.tail { + None => self.head = None, + Some(mut tail) => tail.as_mut().next = None, + } + + self.len -= 1; + node + }) + } + + /// Unlinks the specified node from the current list. + /// + /// Warning: this will not check that the provided node belongs to the current list. + #[inline] + unsafe fn unlink_node(&mut self, mut node: NonNull>) { + let node = node.as_mut(); + + match node.prev { + Some(mut prev) => prev.as_mut().next = node.next.clone(), + // this node is the head node + None => self.head = node.next.clone(), + }; + + match node.next { + Some(mut next) => next.as_mut().prev = node.prev.clone(), + // this node is the tail node + None => self.tail = node.prev.clone(), + }; + + self.len -= 1; + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for LinkedList { + /// Creates an empty `LinkedList`. + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl LinkedList { + /// Creates an empty `LinkedList`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let list: LinkedList = LinkedList::new(); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> Self { + LinkedList { + head: None, + tail: None, + len: 0, + marker: PhantomData, + } + } + + /// Moves all elements from `other` to the end of the list. + /// + /// This reuses all the nodes from `other` and moves them into `self`. After + /// this operation, `other` becomes empty. + /// + /// This operation should compute in O(1) time and O(1) memory. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list1 = LinkedList::new(); + /// list1.push_back('a'); + /// + /// let mut list2 = LinkedList::new(); + /// list2.push_back('b'); + /// list2.push_back('c'); + /// + /// list1.append(&mut list2); + /// + /// let mut iter = list1.iter(); + /// assert_eq!(iter.next(), Some(&'a')); + /// assert_eq!(iter.next(), Some(&'b')); + /// assert_eq!(iter.next(), Some(&'c')); + /// assert!(iter.next().is_none()); + /// + /// assert!(list2.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn append(&mut self, other: &mut Self) { + match self.tail { + None => mem::swap(self, other), + Some(mut tail) => { + if let Some(mut other_head) = other.head.take() { + unsafe { + tail.as_mut().next = Some(other_head); + other_head.as_mut().prev = Some(tail); + } + + self.tail = other.tail.take(); + self.len += mem::replace(&mut other.len, 0); + } + } + } + } + + /// Provides a forward iterator. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&0)); + /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter { + Iter { + head: self.head, + tail: self.tail, + len: self.len, + marker: PhantomData, + } + } + + /// Provides a forward iterator with mutable references. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// for element in list.iter_mut() { + /// *element += 10; + /// } + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&10)); + /// assert_eq!(iter.next(), Some(&11)); + /// assert_eq!(iter.next(), Some(&12)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + head: self.head, + tail: self.tail, + len: self.len, + list: self, + } + } + + /// Returns `true` if the `LinkedList` is empty. + /// + /// This operation should compute in O(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert!(dl.is_empty()); + /// + /// dl.push_front("foo"); + /// assert!(!dl.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.head.is_none() + } + + /// Returns the length of the `LinkedList`. + /// + /// This operation should compute in O(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// assert_eq!(dl.len(), 1); + /// + /// dl.push_front(1); + /// assert_eq!(dl.len(), 2); + /// + /// dl.push_back(3); + /// assert_eq!(dl.len(), 3); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { + self.len + } + + /// Removes all elements from the `LinkedList`. + /// + /// This operation should compute in O(n) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// dl.push_front(1); + /// assert_eq!(dl.len(), 2); + /// assert_eq!(dl.front(), Some(&1)); + /// + /// dl.clear(); + /// assert_eq!(dl.len(), 0); + /// assert_eq!(dl.front(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { + *self = Self::new(); + } + + /// Returns `true` if the `LinkedList` contains an element equal to the + /// given value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// assert_eq!(list.contains(&0), true); + /// assert_eq!(list.contains(&10), false); + /// ``` + #[stable(feature = "linked_list_contains", since = "1.12.0")] + pub fn contains(&self, x: &T) -> bool + where T: PartialEq + { + self.iter().any(|e| e == x) + } + + /// Provides a reference to the front element, or `None` if the list is + /// empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.front(), None); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front(), Some(&1)); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn front(&self) -> Option<&T> { + unsafe { + self.head.as_ref().map(|node| &node.as_ref().element) + } + } + + /// Provides a mutable reference to the front element, or `None` if the list + /// is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.front(), None); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front(), Some(&1)); + /// + /// match dl.front_mut() { + /// None => {}, + /// Some(x) => *x = 5, + /// } + /// assert_eq!(dl.front(), Some(&5)); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn front_mut(&mut self) -> Option<&mut T> { + unsafe { + self.head.as_mut().map(|node| &mut node.as_mut().element) + } + } + + /// Provides a reference to the back element, or `None` if the list is + /// empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.back(), None); + /// + /// dl.push_back(1); + /// assert_eq!(dl.back(), Some(&1)); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn back(&self) -> Option<&T> { + unsafe { + self.tail.as_ref().map(|node| &node.as_ref().element) + } + } + + /// Provides a mutable reference to the back element, or `None` if the list + /// is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.back(), None); + /// + /// dl.push_back(1); + /// assert_eq!(dl.back(), Some(&1)); + /// + /// match dl.back_mut() { + /// None => {}, + /// Some(x) => *x = 5, + /// } + /// assert_eq!(dl.back(), Some(&5)); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn back_mut(&mut self) -> Option<&mut T> { + unsafe { + self.tail.as_mut().map(|node| &mut node.as_mut().element) + } + } + + /// Adds an element first in the list. + /// + /// This operation should compute in O(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// assert_eq!(dl.front().unwrap(), &2); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front().unwrap(), &1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn push_front(&mut self, elt: T) { + self.push_front_node(box Node::new(elt)); + } + + /// Removes the first element and returns it, or `None` if the list is + /// empty. + /// + /// This operation should compute in O(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// assert_eq!(d.pop_front(), None); + /// + /// d.push_front(1); + /// d.push_front(3); + /// assert_eq!(d.pop_front(), Some(3)); + /// assert_eq!(d.pop_front(), Some(1)); + /// assert_eq!(d.pop_front(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_front(&mut self) -> Option { + self.pop_front_node().map(Node::into_element) + } + + /// Appends an element to the back of a list + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// d.push_back(1); + /// d.push_back(3); + /// assert_eq!(3, *d.back().unwrap()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn push_back(&mut self, elt: T) { + self.push_back_node(box Node::new(elt)); + } + + /// Removes the last element from a list and returns it, or `None` if + /// it is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// assert_eq!(d.pop_back(), None); + /// d.push_back(1); + /// d.push_back(3); + /// assert_eq!(d.pop_back(), Some(3)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_back(&mut self) -> Option { + self.pop_back_node().map(Node::into_element) + } + + /// Splits the list into two at the given index. Returns everything after the given index, + /// including the index. + /// + /// This operation should compute in O(n) time. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// let mut splitted = d.split_off(2); + /// + /// assert_eq!(splitted.pop_front(), Some(1)); + /// assert_eq!(splitted.pop_front(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn split_off(&mut self, at: usize) -> LinkedList { + let len = self.len(); + assert!(at <= len, "Cannot split off at a nonexistent index"); + if at == 0 { + return mem::replace(self, Self::new()); + } else if at == len { + return Self::new(); + } + + // Below, we iterate towards the `i-1`th node, either from the start or the end, + // depending on which would be faster. + let split_node = if at - 1 <= len - 1 - (at - 1) { + let mut iter = self.iter_mut(); + // instead of skipping using .skip() (which creates a new struct), + // we skip manually so we can access the head field without + // depending on implementation details of Skip + for _ in 0..at - 1 { + iter.next(); + } + iter.head + } else { + // better off starting from the end + let mut iter = self.iter_mut(); + for _ in 0..len - 1 - (at - 1) { + iter.next_back(); + } + iter.tail + }; + + // The split node is the new tail node of the first part and owns + // the head of the second part. + let second_part_head; + + unsafe { + second_part_head = split_node.unwrap().as_mut().next.take(); + if let Some(mut head) = second_part_head { + head.as_mut().prev = None; + } + } + + let second_part = LinkedList { + head: second_part_head, + tail: self.tail, + len: len - at, + marker: PhantomData, + }; + + // Fix the tail ptr of the first part + self.tail = split_node; + self.len = at; + + second_part + } + + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns true, then the element is removed and yielded. + /// If the closure returns false, the element will remain in the list and will not be yielded + /// by the iterator. + /// + /// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// # Examples + /// + /// Splitting a list into evens and odds, reusing the original list: + /// + /// ``` + /// #![feature(drain_filter)] + /// use std::collections::LinkedList; + /// + /// let mut numbers: LinkedList = LinkedList::new(); + /// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); + /// + /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::>(); + /// let odds = numbers; + /// + /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); + /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); + /// ``` + #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] + pub fn drain_filter(&mut self, filter: F) -> DrainFilter + where F: FnMut(&mut T) -> bool + { + // avoid borrow issues. + let it = self.head; + let old_len = self.len; + + DrainFilter { + list: self, + it: it, + pred: filter, + idx: 0, + old_len: old_len, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T> Drop for LinkedList { + fn drop(&mut self) { + while let Some(_) = self.pop_front_node() {} + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + if self.len == 0 { + None + } else { + self.head.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &*node.as_ptr(); + self.len -= 1; + self.head = node.next; + &node.element + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a T> { + if self.len == 0 { + None + } else { + self.tail.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &*node.as_ptr(); + self.len -= 1; + self.tail = node.prev; + &node.element + }) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> ExactSizeIterator for Iter<'a, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + #[inline] + fn next(&mut self) -> Option<&'a mut T> { + if self.len == 0 { + None + } else { + self.head.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &mut *node.as_ptr(); + self.len -= 1; + self.head = node.next; + &mut node.element + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut T> { + if self.len == 0 { + None + } else { + self.tail.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &mut *node.as_ptr(); + self.len -= 1; + self.tail = node.prev; + &mut node.element + }) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T> FusedIterator for IterMut<'a, T> {} + +impl<'a, T> IterMut<'a, T> { + /// Inserts the given element just after the element most recently returned by `.next()`. + /// The inserted element does not appear in the iteration. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_extras)] + /// + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList<_> = vec![1, 3, 4].into_iter().collect(); + /// + /// { + /// let mut it = list.iter_mut(); + /// assert_eq!(it.next().unwrap(), &1); + /// // insert `2` after `1` + /// it.insert_next(2); + /// } + /// { + /// let vec: Vec<_> = list.into_iter().collect(); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// } + /// ``` + #[inline] + #[unstable(feature = "linked_list_extras", + reason = "this is probably better handled by a cursor type -- we'll see", + issue = "27794")] + pub fn insert_next(&mut self, element: T) { + match self.head { + None => self.list.push_back(element), + Some(mut head) => unsafe { + let mut prev = match head.as_ref().prev { + None => return self.list.push_front(element), + Some(prev) => prev, + }; + + let node = Some(Box::into_raw_non_null(box Node { + next: Some(head), + prev: Some(prev), + element, + })); + + prev.as_mut().next = node; + head.as_mut().prev = node; + + self.list.len += 1; + }, + } + } + + /// Provides a reference to the next element, without changing the iterator. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_extras)] + /// + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList<_> = vec![1, 2, 3].into_iter().collect(); + /// + /// let mut it = list.iter_mut(); + /// assert_eq!(it.next().unwrap(), &1); + /// assert_eq!(it.peek_next().unwrap(), &2); + /// // We just peeked at 2, so it was not consumed from the iterator. + /// assert_eq!(it.next().unwrap(), &2); + /// ``` + #[inline] + #[unstable(feature = "linked_list_extras", + reason = "this is probably better handled by a cursor type -- we'll see", + issue = "27794")] + pub fn peek_next(&mut self) -> Option<&mut T> { + if self.len == 0 { + None + } else { + unsafe { + self.head.as_mut().map(|node| &mut node.as_mut().element) + } + } + } +} + +/// An iterator produced by calling `drain_filter` on LinkedList. +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +pub struct DrainFilter<'a, T: 'a, F: 'a> + where F: FnMut(&mut T) -> bool, +{ + list: &'a mut LinkedList, + it: Option>>, + pred: F, + idx: usize, + old_len: usize, +} + +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +impl<'a, T, F> Iterator for DrainFilter<'a, T, F> + where F: FnMut(&mut T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + while let Some(mut node) = self.it { + unsafe { + self.it = node.as_ref().next; + self.idx += 1; + + if (self.pred)(&mut node.as_mut().element) { + self.list.unlink_node(node); + return Some(Box::from_raw(node.as_ptr()).element); + } + } + } + + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.old_len - self.idx)) + } +} + +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +impl<'a, T, F> Drop for DrainFilter<'a, T, F> + where F: FnMut(&mut T) -> bool, +{ + fn drop(&mut self) { + self.for_each(drop); + } +} + +#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] +impl<'a, T: 'a + fmt::Debug, F> fmt::Debug for DrainFilter<'a, T, F> + where F: FnMut(&mut T) -> bool +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("DrainFilter") + .field(&self.list) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.list.pop_front() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.list.len, Some(self.list.len)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.list.pop_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator for LinkedList { + fn from_iter>(iter: I) -> Self { + let mut list = Self::new(); + list.extend(iter); + list + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for LinkedList { + type Item = T; + type IntoIter = IntoIter; + + /// Consumes the list into an iterator yielding elements by value. + #[inline] + fn into_iter(self) -> IntoIter { + IntoIter { list: self } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a LinkedList { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a mut LinkedList { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend for LinkedList { + fn extend>(&mut self, iter: I) { + >::spec_extend(self, iter); + } +} + +impl SpecExtend for LinkedList { + default fn spec_extend(&mut self, iter: I) { + for elt in iter { + self.push_back(elt); + } + } +} + +impl SpecExtend> for LinkedList { + fn spec_extend(&mut self, ref mut other: LinkedList) { + self.append(other); + } +} + +#[stable(feature = "extend_ref", since = "1.2.0")] +impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for LinkedList { + fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.iter().eq(other) + } + + fn ne(&self, other: &Self) -> bool { + self.len() != other.len() || self.iter().ne(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for LinkedList {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for LinkedList { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for LinkedList { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for LinkedList { + fn clone(&self) -> Self { + self.iter().cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for LinkedList { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for LinkedList { + fn hash(&self, state: &mut H) { + self.len().hash(state); + for elt in self { + elt.hash(state); + } + } +} + +// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters. +#[allow(dead_code)] +fn assert_covariance() { + fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { + x + } + fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { + x + } + fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { + x + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for LinkedList {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for LinkedList {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} + +#[cfg(test)] +mod tests { + use std::thread; + use std::vec::Vec; + + use rand::{thread_rng, Rng}; + + use super::{LinkedList, Node}; + + #[cfg(test)] + fn list_from(v: &[T]) -> LinkedList { + v.iter().cloned().collect() + } + + pub fn check_links(list: &LinkedList) { + unsafe { + let mut len = 0; + let mut last_ptr: Option<&Node> = None; + let mut node_ptr: &Node; + match list.head { + None => { + // tail node should also be None. + assert!(list.tail.is_none()); + assert_eq!(0, list.len); + return; + } + Some(node) => node_ptr = &*node.as_ptr(), + } + loop { + match (last_ptr, node_ptr.prev) { + (None, None) => {} + (None, _) => panic!("prev link for head"), + (Some(p), Some(pptr)) => { + assert_eq!(p as *const Node, pptr.as_ptr() as *const Node); + } + _ => panic!("prev link is none, not good"), + } + match node_ptr.next { + Some(next) => { + last_ptr = Some(node_ptr); + node_ptr = &*next.as_ptr(); + len += 1; + } + None => { + len += 1; + break; + } + } + } + + // verify that the tail node points to the last node. + let tail = list.tail.as_ref().expect("some tail node").as_ref(); + assert_eq!(tail as *const Node, node_ptr as *const Node); + // check that len matches interior links. + assert_eq!(len, list.len); + } + } + + #[test] + fn test_append() { + // Empty to empty + { + let mut m = LinkedList::::new(); + let mut n = LinkedList::new(); + m.append(&mut n); + check_links(&m); + assert_eq!(m.len(), 0); + assert_eq!(n.len(), 0); + } + // Non-empty to empty + { + let mut m = LinkedList::new(); + let mut n = LinkedList::new(); + n.push_back(2); + m.append(&mut n); + check_links(&m); + assert_eq!(m.len(), 1); + assert_eq!(m.pop_back(), Some(2)); + assert_eq!(n.len(), 0); + check_links(&m); + } + // Empty to non-empty + { + let mut m = LinkedList::new(); + let mut n = LinkedList::new(); + m.push_back(2); + m.append(&mut n); + check_links(&m); + assert_eq!(m.len(), 1); + assert_eq!(m.pop_back(), Some(2)); + check_links(&m); + } + + // Non-empty to non-empty + let v = vec![1, 2, 3, 4, 5]; + let u = vec![9, 8, 1, 2, 3, 4, 5]; + let mut m = list_from(&v); + let mut n = list_from(&u); + m.append(&mut n); + check_links(&m); + let mut sum = v; + sum.extend_from_slice(&u); + assert_eq!(sum.len(), m.len()); + for elt in sum { + assert_eq!(m.pop_front(), Some(elt)) + } + assert_eq!(n.len(), 0); + // let's make sure it's working properly, since we + // did some direct changes to private members + n.push_back(3); + assert_eq!(n.len(), 1); + assert_eq!(n.pop_front(), Some(3)); + check_links(&n); + } + + #[test] + fn test_insert_prev() { + let mut m = list_from(&[0, 2, 4, 6, 8]); + let len = m.len(); + { + let mut it = m.iter_mut(); + it.insert_next(-2); + loop { + match it.next() { + None => break, + Some(elt) => { + it.insert_next(*elt + 1); + match it.peek_next() { + Some(x) => assert_eq!(*x, *elt + 2), + None => assert_eq!(8, *elt), + } + } + } + } + it.insert_next(0); + it.insert_next(1); + } + check_links(&m); + assert_eq!(m.len(), 3 + len * 2); + assert_eq!(m.into_iter().collect::>(), + [-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn test_send() { + let n = list_from(&[1, 2, 3]); + thread::spawn(move || { + check_links(&n); + let a: &[_] = &[&1, &2, &3]; + assert_eq!(a, &*n.iter().collect::>()); + }) + .join() + .ok() + .unwrap(); + } + + #[test] + fn test_fuzz() { + for _ in 0..25 { + fuzz_test(3); + fuzz_test(16); + fuzz_test(189); + } + } + + #[test] + fn test_26021() { + // There was a bug in split_off that failed to null out the RHS's head's prev ptr. + // This caused the RHS's dtor to walk up into the LHS at drop and delete all of + // its nodes. + // + // https://github.com/rust-lang/rust/issues/26021 + let mut v1 = LinkedList::new(); + v1.push_front(1); + v1.push_front(1); + v1.push_front(1); + v1.push_front(1); + let _ = v1.split_off(3); // Dropping this now should not cause laundry consumption + assert_eq!(v1.len(), 3); + + assert_eq!(v1.iter().len(), 3); + assert_eq!(v1.iter().collect::>().len(), 3); + } + + #[test] + fn test_split_off() { + let mut v1 = LinkedList::new(); + v1.push_front(1); + v1.push_front(1); + v1.push_front(1); + v1.push_front(1); + + // test all splits + for ix in 0..1 + v1.len() { + let mut a = v1.clone(); + let b = a.split_off(ix); + check_links(&a); + check_links(&b); + a.extend(b); + assert_eq!(v1, a); + } + } + + #[cfg(test)] + fn fuzz_test(sz: i32) { + let mut m: LinkedList<_> = LinkedList::new(); + let mut v = vec![]; + for i in 0..sz { + check_links(&m); + let r: u8 = thread_rng().next_u32() as u8; + match r % 6 { + 0 => { + m.pop_back(); + v.pop(); + } + 1 => { + if !v.is_empty() { + m.pop_front(); + v.remove(0); + } + } + 2 | 4 => { + m.push_front(-i); + v.insert(0, -i); + } + 3 | 5 | _ => { + m.push_back(i); + v.push(i); + } + } + } + + check_links(&m); + + let mut i = 0; + for (a, &b) in m.into_iter().zip(&v) { + i += 1; + assert_eq!(a, b); + } + assert_eq!(i, v.len()); + } + + #[test] + fn drain_filter_test() { + let mut m: LinkedList = LinkedList::new(); + m.extend(&[1, 2, 3, 4, 5, 6]); + let deleted = m.drain_filter(|v| *v < 4).collect::>(); + + check_links(&m); + + assert_eq!(deleted, &[1, 2, 3]); + assert_eq!(m.into_iter().collect::>(), &[4, 5, 6]); + } + + #[test] + fn drain_to_empty_test() { + let mut m: LinkedList = LinkedList::new(); + m.extend(&[1, 2, 3, 4, 5, 6]); + let deleted = m.drain_filter(|_| true).collect::>(); + + check_links(&m); + + assert_eq!(deleted, &[1, 2, 3, 4, 5, 6]); + assert_eq!(m.into_iter().collect::>(), &[]); + } +} diff --git a/src/liballoc/collections/mod.rs b/src/liballoc/collections/mod.rs new file mode 100644 index 00000000000..35c816a1ceb --- /dev/null +++ b/src/liballoc/collections/mod.rs @@ -0,0 +1,59 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Collection types. + +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod binary_heap; +mod btree; +pub mod linked_list; +pub mod vec_deque; + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod btree_map { + //! A map based on a B-Tree. + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::btree::map::*; +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod btree_set { + //! A set based on a B-Tree. + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::btree::set::*; +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::binary_heap::BinaryHeap; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::btree_map::BTreeMap; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::btree_set::BTreeSet; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::linked_list::LinkedList; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::vec_deque::VecDeque; + +/// An intermediate trait for specialization of `Extend`. +#[doc(hidden)] +trait SpecExtend { + /// Extends `self` with the contents of the given iterator. + fn spec_extend(&mut self, iter: I); +} diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs new file mode 100644 index 00000000000..4753d36415c --- /dev/null +++ b/src/liballoc/collections/vec_deque.rs @@ -0,0 +1,2970 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A double-ended queue implemented with a growable ring buffer. +//! +//! This queue has `O(1)` amortized inserts and removals from both ends of the +//! container. It also has `O(1)` indexing like a vector. The contained elements +//! are not required to be copyable, and the queue will be sendable if the +//! contained type is sendable. + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::cmp::Ordering; +use core::fmt; +use core::iter::{repeat, FromIterator, FusedIterator}; +use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; +use core::ops::{Index, IndexMut, RangeBounds}; +use core::ptr; +use core::ptr::NonNull; +use core::slice; + +use core::hash::{Hash, Hasher}; +use core::cmp; + +use alloc::CollectionAllocErr; +use raw_vec::RawVec; +use vec::Vec; + +const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 +const MINIMUM_CAPACITY: usize = 1; // 2 - 1 +#[cfg(target_pointer_width = "32")] +const MAXIMUM_ZST_CAPACITY: usize = 1 << (32 - 1); // Largest possible power of two +#[cfg(target_pointer_width = "64")] +const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of two + +/// A double-ended queue implemented with a growable ring buffer. +/// +/// The "default" usage of this type as a queue is to use [`push_back`] to add to +/// the queue, and [`pop_front`] to remove from the queue. [`extend`] and [`append`] +/// push onto the back in this manner, and iterating over `VecDeque` goes front +/// to back. +/// +/// [`push_back`]: #method.push_back +/// [`pop_front`]: #method.pop_front +/// [`extend`]: #method.extend +/// [`append`]: #method.append +#[stable(feature = "rust1", since = "1.0.0")] +pub struct VecDeque { + // tail and head are pointers into the buffer. Tail always points + // to the first element that could be read, Head always points + // to where data should be written. + // If tail == head the buffer is empty. The length of the ringbuffer + // is defined as the distance between the two. + tail: usize, + head: usize, + buf: RawVec, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for VecDeque { + fn clone(&self) -> VecDeque { + self.iter().cloned().collect() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T> Drop for VecDeque { + fn drop(&mut self) { + let (front, back) = self.as_mut_slices(); + unsafe { + // use drop for [T] + ptr::drop_in_place(front); + ptr::drop_in_place(back); + } + // RawVec handles deallocation + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for VecDeque { + /// Creates an empty `VecDeque`. + #[inline] + fn default() -> VecDeque { + VecDeque::new() + } +} + +impl VecDeque { + /// Marginally more convenient + #[inline] + fn ptr(&self) -> *mut T { + self.buf.ptr() + } + + /// Marginally more convenient + #[inline] + fn cap(&self) -> usize { + if mem::size_of::() == 0 { + // For zero sized types, we are always at maximum capacity + MAXIMUM_ZST_CAPACITY + } else { + self.buf.cap() + } + } + + /// Turn ptr into a slice + #[inline] + unsafe fn buffer_as_slice(&self) -> &[T] { + slice::from_raw_parts(self.ptr(), self.cap()) + } + + /// Turn ptr into a mut slice + #[inline] + unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] { + slice::from_raw_parts_mut(self.ptr(), self.cap()) + } + + /// Moves an element out of the buffer + #[inline] + unsafe fn buffer_read(&mut self, off: usize) -> T { + ptr::read(self.ptr().offset(off as isize)) + } + + /// Writes an element into the buffer, moving it. + #[inline] + unsafe fn buffer_write(&mut self, off: usize, value: T) { + ptr::write(self.ptr().offset(off as isize), value); + } + + /// Returns `true` if and only if the buffer is at full capacity. + #[inline] + fn is_full(&self) -> bool { + self.cap() - self.len() == 1 + } + + /// Returns the index in the underlying buffer for a given logical element + /// index. + #[inline] + fn wrap_index(&self, idx: usize) -> usize { + wrap_index(idx, self.cap()) + } + + /// Returns the index in the underlying buffer for a given logical element + /// index + addend. + #[inline] + fn wrap_add(&self, idx: usize, addend: usize) -> usize { + wrap_index(idx.wrapping_add(addend), self.cap()) + } + + /// Returns the index in the underlying buffer for a given logical element + /// index - subtrahend. + #[inline] + fn wrap_sub(&self, idx: usize, subtrahend: usize) -> usize { + wrap_index(idx.wrapping_sub(subtrahend), self.cap()) + } + + /// Copies a contiguous block of memory len long from src to dst + #[inline] + unsafe fn copy(&self, dst: usize, src: usize, len: usize) { + debug_assert!(dst + len <= self.cap(), + "cpy dst={} src={} len={} cap={}", + dst, + src, + len, + self.cap()); + debug_assert!(src + len <= self.cap(), + "cpy dst={} src={} len={} cap={}", + dst, + src, + len, + self.cap()); + ptr::copy(self.ptr().offset(src as isize), + self.ptr().offset(dst as isize), + len); + } + + /// Copies a contiguous block of memory len long from src to dst + #[inline] + unsafe fn copy_nonoverlapping(&self, dst: usize, src: usize, len: usize) { + debug_assert!(dst + len <= self.cap(), + "cno dst={} src={} len={} cap={}", + dst, + src, + len, + self.cap()); + debug_assert!(src + len <= self.cap(), + "cno dst={} src={} len={} cap={}", + dst, + src, + len, + self.cap()); + ptr::copy_nonoverlapping(self.ptr().offset(src as isize), + self.ptr().offset(dst as isize), + len); + } + + /// Copies a potentially wrapping block of memory len long from src to dest. + /// (abs(dst - src) + len) must be no larger than cap() (There must be at + /// most one continuous overlapping region between src and dest). + unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) { + #[allow(dead_code)] + fn diff(a: usize, b: usize) -> usize { + if a <= b { b - a } else { a - b } + } + debug_assert!(cmp::min(diff(dst, src), self.cap() - diff(dst, src)) + len <= self.cap(), + "wrc dst={} src={} len={} cap={}", + dst, + src, + len, + self.cap()); + + if src == dst || len == 0 { + return; + } + + let dst_after_src = self.wrap_sub(dst, src) < len; + + let src_pre_wrap_len = self.cap() - src; + let dst_pre_wrap_len = self.cap() - dst; + let src_wraps = src_pre_wrap_len < len; + let dst_wraps = dst_pre_wrap_len < len; + + match (dst_after_src, src_wraps, dst_wraps) { + (_, false, false) => { + // src doesn't wrap, dst doesn't wrap + // + // S . . . + // 1 [_ _ A A B B C C _] + // 2 [_ _ A A A A B B _] + // D . . . + // + self.copy(dst, src, len); + } + (false, false, true) => { + // dst before src, src doesn't wrap, dst wraps + // + // S . . . + // 1 [A A B B _ _ _ C C] + // 2 [A A B B _ _ _ A A] + // 3 [B B B B _ _ _ A A] + // . . D . + // + self.copy(dst, src, dst_pre_wrap_len); + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + } + (true, false, true) => { + // src before dst, src doesn't wrap, dst wraps + // + // S . . . + // 1 [C C _ _ _ A A B B] + // 2 [B B _ _ _ A A B B] + // 3 [B B _ _ _ A A A A] + // . . D . + // + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + self.copy(dst, src, dst_pre_wrap_len); + } + (false, true, false) => { + // dst before src, src wraps, dst doesn't wrap + // + // . . S . + // 1 [C C _ _ _ A A B B] + // 2 [C C _ _ _ B B B B] + // 3 [C C _ _ _ B B C C] + // D . . . + // + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + } + (true, true, false) => { + // src before dst, src wraps, dst doesn't wrap + // + // . . S . + // 1 [A A B B _ _ _ C C] + // 2 [A A A A _ _ _ C C] + // 3 [C C A A _ _ _ C C] + // D . . . + // + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + self.copy(dst, src, src_pre_wrap_len); + } + (false, true, true) => { + // dst before src, src wraps, dst wraps + // + // . . . S . + // 1 [A B C D _ E F G H] + // 2 [A B C D _ E G H H] + // 3 [A B C D _ E G H A] + // 4 [B C C D _ E G H A] + // . . D . . + // + debug_assert!(dst_pre_wrap_len > src_pre_wrap_len); + let delta = dst_pre_wrap_len - src_pre_wrap_len; + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, delta); + self.copy(0, delta, len - dst_pre_wrap_len); + } + (true, true, true) => { + // src before dst, src wraps, dst wraps + // + // . . S . . + // 1 [A B C D _ E F G H] + // 2 [A A B D _ E F G H] + // 3 [H A B D _ E F G H] + // 4 [H A B D _ E F F G] + // . . . D . + // + debug_assert!(src_pre_wrap_len > dst_pre_wrap_len); + let delta = src_pre_wrap_len - dst_pre_wrap_len; + self.copy(delta, 0, len - src_pre_wrap_len); + self.copy(0, self.cap() - delta, delta); + self.copy(dst, src, dst_pre_wrap_len); + } + } + } + + /// Frobs the head and tail sections around to handle the fact that we + /// just reallocated. Unsafe because it trusts old_cap. + #[inline] + unsafe fn handle_cap_increase(&mut self, old_cap: usize) { + let new_cap = self.cap(); + + // Move the shortest contiguous section of the ring buffer + // T H + // [o o o o o o o . ] + // T H + // A [o o o o o o o . . . . . . . . . ] + // H T + // [o o . o o o o o ] + // T H + // B [. . . o o o o o o o . . . . . . ] + // H T + // [o o o o o . o o ] + // H T + // C [o o o o o . . . . . . . . . o o ] + + if self.tail <= self.head { + // A + // Nop + } else if self.head < old_cap - self.tail { + // B + self.copy_nonoverlapping(old_cap, 0, self.head); + self.head += old_cap; + debug_assert!(self.head > self.tail); + } else { + // C + let new_tail = new_cap - (old_cap - self.tail); + self.copy_nonoverlapping(new_tail, self.tail, old_cap - self.tail); + self.tail = new_tail; + debug_assert!(self.head < self.tail); + } + debug_assert!(self.head < self.cap()); + debug_assert!(self.tail < self.cap()); + debug_assert!(self.cap().count_ones() == 1); + } +} + +impl VecDeque { + /// Creates an empty `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque = VecDeque::new(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new() -> VecDeque { + VecDeque::with_capacity(INITIAL_CAPACITY) + } + + /// Creates an empty `VecDeque` with space for at least `n` elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque = VecDeque::with_capacity(10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(n: usize) -> VecDeque { + // +1 since the ringbuffer always leaves one space empty + let cap = cmp::max(n + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); + assert!(cap > n, "capacity overflow"); + + VecDeque { + tail: 0, + head: 0, + buf: RawVec::with_capacity(cap), + } + } + + /// Retrieves an element in the `VecDeque` by index. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(3); + /// buf.push_back(4); + /// buf.push_back(5); + /// assert_eq!(buf.get(1), Some(&4)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self, index: usize) -> Option<&T> { + if index < self.len() { + let idx = self.wrap_add(self.tail, index); + unsafe { Some(&*self.ptr().offset(idx as isize)) } + } else { + None + } + } + + /// Retrieves an element in the `VecDeque` mutably by index. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(3); + /// buf.push_back(4); + /// buf.push_back(5); + /// if let Some(elem) = buf.get_mut(1) { + /// *elem = 7; + /// } + /// + /// assert_eq!(buf[1], 7); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { + if index < self.len() { + let idx = self.wrap_add(self.tail, index); + unsafe { Some(&mut *self.ptr().offset(idx as isize)) } + } else { + None + } + } + + /// Swaps elements at indices `i` and `j`. + /// + /// `i` and `j` may be equal. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Panics + /// + /// Panics if either index is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(3); + /// buf.push_back(4); + /// buf.push_back(5); + /// assert_eq!(buf, [3, 4, 5]); + /// buf.swap(0, 2); + /// assert_eq!(buf, [5, 4, 3]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn swap(&mut self, i: usize, j: usize) { + assert!(i < self.len()); + assert!(j < self.len()); + let ri = self.wrap_add(self.tail, i); + let rj = self.wrap_add(self.tail, j); + unsafe { + ptr::swap(self.ptr().offset(ri as isize), + self.ptr().offset(rj as isize)) + } + } + + /// Returns the number of elements the `VecDeque` can hold without + /// reallocating. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let buf: VecDeque = VecDeque::with_capacity(10); + /// assert!(buf.capacity() >= 10); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn capacity(&self) -> usize { + self.cap() - 1 + } + + /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the + /// given `VecDeque`. Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it requests. Therefore + /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future + /// insertions are expected. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf: VecDeque = vec![1].into_iter().collect(); + /// buf.reserve_exact(10); + /// assert!(buf.capacity() >= 11); + /// ``` + /// + /// [`reserve`]: #method.reserve + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve_exact(&mut self, additional: usize) { + self.reserve(additional); + } + + /// Reserves capacity for at least `additional` more elements to be inserted in the given + /// `VecDeque`. The collection may reserve more space to avoid frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf: VecDeque = vec![1].into_iter().collect(); + /// buf.reserve(10); + /// assert!(buf.capacity() >= 11); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn reserve(&mut self, additional: usize) { + let old_cap = self.cap(); + let used_cap = self.len() + 1; + let new_cap = used_cap.checked_add(additional) + .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) + .expect("capacity overflow"); + + if new_cap > old_cap { + self.buf.reserve_exact(used_cap, new_cap - used_cap); + unsafe { + self.handle_cap_increase(old_cap); + } + } + } + + /// Tries to reserves the minimum capacity for exactly `additional` more elements to + /// be inserted in the given `VecDeque`. After calling `reserve_exact`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer `reserve` if future insertions are expected. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// use std::collections::VecDeque; + /// + /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// let mut output = VecDeque::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve_exact(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.try_reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `VecDeque`. The collection may reserve more space to avoid + /// frequent reallocations. After calling `reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// use std::collections::VecDeque; + /// + /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// let mut output = VecDeque::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + let old_cap = self.cap(); + let used_cap = self.len() + 1; + let new_cap = used_cap.checked_add(additional) + .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) + .ok_or(CollectionAllocErr::CapacityOverflow)?; + + if new_cap > old_cap { + self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?; + unsafe { + self.handle_cap_increase(old_cap); + } + } + Ok(()) + } + + /// Shrinks the capacity of the `VecDeque` as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator may still inform the + /// `VecDeque` that there is space for a few more elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::with_capacity(15); + /// buf.extend(0..4); + /// assert_eq!(buf.capacity(), 15); + /// buf.shrink_to_fit(); + /// assert!(buf.capacity() >= 4); + /// ``` + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn shrink_to_fit(&mut self) { + self.shrink_to(0); + } + + /// Shrinks the capacity of the `VecDeque` with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(shrink_to)] + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::with_capacity(15); + /// buf.extend(0..4); + /// assert_eq!(buf.capacity(), 15); + /// buf.shrink_to(6); + /// assert!(buf.capacity() >= 6); + /// buf.shrink_to(0); + /// assert!(buf.capacity() >= 4); + /// ``` + #[unstable(feature = "shrink_to", reason = "new API", issue="0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); + + // +1 since the ringbuffer always leaves one space empty + // len + 1 can't overflow for an existing, well-formed ringbuffer. + let target_cap = cmp::max( + cmp::max(min_capacity, self.len()) + 1, + MINIMUM_CAPACITY + 1 + ).next_power_of_two(); + + if target_cap < self.cap() { + // There are three cases of interest: + // All elements are out of desired bounds + // Elements are contiguous, and head is out of desired bounds + // Elements are discontiguous, and tail is out of desired bounds + // + // At all other times, element positions are unaffected. + // + // Indicates that elements at the head should be moved. + let head_outside = self.head == 0 || self.head >= target_cap; + // Move elements from out of desired bounds (positions after target_cap) + if self.tail >= target_cap && head_outside { + // T H + // [. . . . . . . . o o o o o o o . ] + // T H + // [o o o o o o o . ] + unsafe { + self.copy_nonoverlapping(0, self.tail, self.len()); + } + self.head = self.len(); + self.tail = 0; + } else if self.tail != 0 && self.tail < target_cap && head_outside { + // T H + // [. . . o o o o o o o . . . . . . ] + // H T + // [o o . o o o o o ] + let len = self.wrap_sub(self.head, target_cap); + unsafe { + self.copy_nonoverlapping(0, target_cap, len); + } + self.head = len; + debug_assert!(self.head < self.tail); + } else if self.tail >= target_cap { + // H T + // [o o o o o . . . . . . . . . o o ] + // H T + // [o o o o o . o o ] + debug_assert!(self.wrap_sub(self.head, 1) < target_cap); + let len = self.cap() - self.tail; + let new_tail = target_cap - len; + unsafe { + self.copy_nonoverlapping(new_tail, self.tail, len); + } + self.tail = new_tail; + debug_assert!(self.head < self.tail); + } + + self.buf.shrink_to_fit(target_cap); + + debug_assert!(self.head < self.cap()); + debug_assert!(self.tail < self.cap()); + debug_assert!(self.cap().count_ones() == 1); + } + } + + /// Shortens the `VecDeque`, dropping excess elements from the back. + /// + /// If `len` is greater than the `VecDeque`'s current length, this has no + /// effect. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(5); + /// buf.push_back(10); + /// buf.push_back(15); + /// assert_eq!(buf, [5, 10, 15]); + /// buf.truncate(1); + /// assert_eq!(buf, [5]); + /// ``` + #[stable(feature = "deque_extras", since = "1.16.0")] + pub fn truncate(&mut self, len: usize) { + for _ in len..self.len() { + self.pop_back(); + } + } + + /// Returns a front-to-back iterator. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(5); + /// buf.push_back(3); + /// buf.push_back(4); + /// let b: &[_] = &[&5, &3, &4]; + /// let c: Vec<&i32> = buf.iter().collect(); + /// assert_eq!(&c[..], b); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter { + Iter { + tail: self.tail, + head: self.head, + ring: unsafe { self.buffer_as_slice() }, + } + } + + /// Returns a front-to-back iterator that returns mutable references. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(5); + /// buf.push_back(3); + /// buf.push_back(4); + /// for num in buf.iter_mut() { + /// *num = *num - 2; + /// } + /// let b: &[_] = &[&mut 3, &mut 1, &mut 2]; + /// assert_eq!(&buf.iter_mut().collect::>()[..], b); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + tail: self.tail, + head: self.head, + ring: unsafe { self.buffer_as_mut_slice() }, + } + } + + /// Returns a pair of slices which contain, in order, the contents of the + /// `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vector = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// vector.push_back(2); + /// + /// assert_eq!(vector.as_slices(), (&[0, 1, 2][..], &[][..])); + /// + /// vector.push_front(10); + /// vector.push_front(9); + /// + /// assert_eq!(vector.as_slices(), (&[9, 10][..], &[0, 1, 2][..])); + /// ``` + #[inline] + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn as_slices(&self) -> (&[T], &[T]) { + unsafe { + let buf = self.buffer_as_slice(); + RingSlices::ring_slices(buf, self.head, self.tail) + } + } + + /// Returns a pair of slices which contain, in order, the contents of the + /// `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vector = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// + /// vector.push_front(10); + /// vector.push_front(9); + /// + /// vector.as_mut_slices().0[0] = 42; + /// vector.as_mut_slices().1[0] = 24; + /// assert_eq!(vector.as_slices(), (&[42, 10][..], &[24, 1][..])); + /// ``` + #[inline] + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + unsafe { + let head = self.head; + let tail = self.tail; + let buf = self.buffer_as_mut_slice(); + RingSlices::ring_slices(buf, head, tail) + } + } + + /// Returns the number of elements in the `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut v = VecDeque::new(); + /// assert_eq!(v.len(), 0); + /// v.push_back(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn len(&self) -> usize { + count(self.tail, self.head, self.cap()) + } + + /// Returns `true` if the `VecDeque` is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut v = VecDeque::new(); + /// assert!(v.is_empty()); + /// v.push_front(1); + /// assert!(!v.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.tail == self.head + } + + /// Create a draining iterator that removes the specified range in the + /// `VecDeque` and yields the removed items. + /// + /// Note 1: The element range is removed even if the iterator is not + /// consumed until the end. + /// + /// Note 2: It is unspecified how many elements are removed from the deque, + /// if the `Drain` value is not dropped, but the borrow it holds expires + /// (eg. due to mem::forget). + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); + /// let drained = v.drain(2..).collect::>(); + /// assert_eq!(drained, [3]); + /// assert_eq!(v, [1, 2]); + /// + /// // A full range clears all contents + /// v.drain(..); + /// assert!(v.is_empty()); + /// ``` + #[inline] + #[stable(feature = "drain", since = "1.6.0")] + pub fn drain(&mut self, range: R) -> Drain + where R: RangeBounds + { + // Memory safety + // + // When the Drain is first created, the source deque is shortened to + // make sure no uninitialized or moved-from elements are accessible at + // all if the Drain's destructor never gets to run. + // + // Drain will ptr::read out the values to remove. + // When finished, the remaining data will be copied back to cover the hole, + // and the head/tail values will be restored correctly. + // + let len = self.len(); + let start = match range.start_bound() { + Included(&n) => n, + Excluded(&n) => n + 1, + Unbounded => 0, + }; + let end = match range.end_bound() { + Included(&n) => n + 1, + Excluded(&n) => n, + Unbounded => len, + }; + assert!(start <= end, "drain lower bound was too large"); + assert!(end <= len, "drain upper bound was too large"); + + // The deque's elements are parted into three segments: + // * self.tail -> drain_tail + // * drain_tail -> drain_head + // * drain_head -> self.head + // + // T = self.tail; H = self.head; t = drain_tail; h = drain_head + // + // We store drain_tail as self.head, and drain_head and self.head as + // after_tail and after_head respectively on the Drain. This also + // truncates the effective array such that if the Drain is leaked, we + // have forgotten about the potentially moved values after the start of + // the drain. + // + // T t h H + // [. . . o o x x o o . . .] + // + let drain_tail = self.wrap_add(self.tail, start); + let drain_head = self.wrap_add(self.tail, end); + let head = self.head; + + // "forget" about the values after the start of the drain until after + // the drain is complete and the Drain destructor is run. + self.head = drain_tail; + + Drain { + deque: NonNull::from(&mut *self), + after_tail: drain_head, + after_head: head, + iter: Iter { + tail: drain_tail, + head: drain_head, + ring: unsafe { self.buffer_as_mut_slice() }, + }, + } + } + + /// Clears the `VecDeque`, removing all values. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut v = VecDeque::new(); + /// v.push_back(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn clear(&mut self) { + self.drain(..); + } + + /// Returns `true` if the `VecDeque` contains an element equal to the + /// given value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vector: VecDeque = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// + /// assert_eq!(vector.contains(&1), true); + /// assert_eq!(vector.contains(&10), false); + /// ``` + #[stable(feature = "vec_deque_contains", since = "1.12.0")] + pub fn contains(&self, x: &T) -> bool + where T: PartialEq + { + let (a, b) = self.as_slices(); + a.contains(x) || b.contains(x) + } + + /// Provides a reference to the front element, or `None` if the `VecDeque` is + /// empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut d = VecDeque::new(); + /// assert_eq!(d.front(), None); + /// + /// d.push_back(1); + /// d.push_back(2); + /// assert_eq!(d.front(), Some(&1)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn front(&self) -> Option<&T> { + if !self.is_empty() { + Some(&self[0]) + } else { + None + } + } + + /// Provides a mutable reference to the front element, or `None` if the + /// `VecDeque` is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut d = VecDeque::new(); + /// assert_eq!(d.front_mut(), None); + /// + /// d.push_back(1); + /// d.push_back(2); + /// match d.front_mut() { + /// Some(x) => *x = 9, + /// None => (), + /// } + /// assert_eq!(d.front(), Some(&9)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn front_mut(&mut self) -> Option<&mut T> { + if !self.is_empty() { + Some(&mut self[0]) + } else { + None + } + } + + /// Provides a reference to the back element, or `None` if the `VecDeque` is + /// empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut d = VecDeque::new(); + /// assert_eq!(d.back(), None); + /// + /// d.push_back(1); + /// d.push_back(2); + /// assert_eq!(d.back(), Some(&2)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn back(&self) -> Option<&T> { + if !self.is_empty() { + Some(&self[self.len() - 1]) + } else { + None + } + } + + /// Provides a mutable reference to the back element, or `None` if the + /// `VecDeque` is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut d = VecDeque::new(); + /// assert_eq!(d.back(), None); + /// + /// d.push_back(1); + /// d.push_back(2); + /// match d.back_mut() { + /// Some(x) => *x = 9, + /// None => (), + /// } + /// assert_eq!(d.back(), Some(&9)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn back_mut(&mut self) -> Option<&mut T> { + let len = self.len(); + if !self.is_empty() { + Some(&mut self[len - 1]) + } else { + None + } + } + + /// Removes the first element and returns it, or `None` if the `VecDeque` is + /// empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut d = VecDeque::new(); + /// d.push_back(1); + /// d.push_back(2); + /// + /// assert_eq!(d.pop_front(), Some(1)); + /// assert_eq!(d.pop_front(), Some(2)); + /// assert_eq!(d.pop_front(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_front(&mut self) -> Option { + if self.is_empty() { + None + } else { + let tail = self.tail; + self.tail = self.wrap_add(self.tail, 1); + unsafe { Some(self.buffer_read(tail)) } + } + } + + /// Prepends an element to the `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut d = VecDeque::new(); + /// d.push_front(1); + /// d.push_front(2); + /// assert_eq!(d.front(), Some(&2)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn push_front(&mut self, value: T) { + self.grow_if_necessary(); + + self.tail = self.wrap_sub(self.tail, 1); + let tail = self.tail; + unsafe { + self.buffer_write(tail, value); + } + } + + /// Appends an element to the back of the `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(1); + /// buf.push_back(3); + /// assert_eq!(3, *buf.back().unwrap()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn push_back(&mut self, value: T) { + self.grow_if_necessary(); + + let head = self.head; + self.head = self.wrap_add(self.head, 1); + unsafe { self.buffer_write(head, value) } + } + + /// Removes the last element from the `VecDeque` and returns it, or `None` if + /// it is empty. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// assert_eq!(buf.pop_back(), None); + /// buf.push_back(1); + /// buf.push_back(3); + /// assert_eq!(buf.pop_back(), Some(3)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_back(&mut self) -> Option { + if self.is_empty() { + None + } else { + self.head = self.wrap_sub(self.head, 1); + let head = self.head; + unsafe { Some(self.buffer_read(head)) } + } + } + + #[inline] + fn is_contiguous(&self) -> bool { + self.tail <= self.head + } + + /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the + /// last element. + /// + /// This does not preserve ordering, but is O(1). + /// + /// Returns `None` if `index` is out of bounds. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// assert_eq!(buf.swap_remove_back(0), None); + /// buf.push_back(1); + /// buf.push_back(2); + /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); + /// + /// assert_eq!(buf.swap_remove_back(0), Some(1)); + /// assert_eq!(buf, [3, 2]); + /// ``` + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn swap_remove_back(&mut self, index: usize) -> Option { + let length = self.len(); + if length > 0 && index < length - 1 { + self.swap(index, length - 1); + } else if index >= length { + return None; + } + self.pop_back() + } + + /// Removes an element from anywhere in the `VecDeque` and returns it, + /// replacing it with the first element. + /// + /// This does not preserve ordering, but is O(1). + /// + /// Returns `None` if `index` is out of bounds. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// assert_eq!(buf.swap_remove_front(0), None); + /// buf.push_back(1); + /// buf.push_back(2); + /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); + /// + /// assert_eq!(buf.swap_remove_front(2), Some(3)); + /// assert_eq!(buf, [2, 1]); + /// ``` + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn swap_remove_front(&mut self, index: usize) -> Option { + let length = self.len(); + if length > 0 && index < length && index != 0 { + self.swap(index, 0); + } else if index >= length { + return None; + } + self.pop_front() + } + + /// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices + /// greater than or equal to `index` towards the back. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Panics + /// + /// Panics if `index` is greater than `VecDeque`'s length + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vec_deque = VecDeque::new(); + /// vec_deque.push_back('a'); + /// vec_deque.push_back('b'); + /// vec_deque.push_back('c'); + /// assert_eq!(vec_deque, &['a', 'b', 'c']); + /// + /// vec_deque.insert(1, 'd'); + /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']); + /// ``` + #[stable(feature = "deque_extras_15", since = "1.5.0")] + pub fn insert(&mut self, index: usize, value: T) { + assert!(index <= self.len(), "index out of bounds"); + self.grow_if_necessary(); + + // Move the least number of elements in the ring buffer and insert + // the given object + // + // At most len/2 - 1 elements will be moved. O(min(n, n-i)) + // + // There are three main cases: + // Elements are contiguous + // - special case when tail is 0 + // Elements are discontiguous and the insert is in the tail section + // Elements are discontiguous and the insert is in the head section + // + // For each of those there are two more cases: + // Insert is closer to tail + // Insert is closer to head + // + // Key: H - self.head + // T - self.tail + // o - Valid element + // I - Insertion element + // A - The element that should be after the insertion point + // M - Indicates element was moved + + let idx = self.wrap_add(self.tail, index); + + let distance_to_tail = index; + let distance_to_head = self.len() - index; + + let contiguous = self.is_contiguous(); + + match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { + (true, true, _) if index == 0 => { + // push_front + // + // T + // I H + // [A o o o o o o . . . . . . . . .] + // + // H T + // [A o o o o o o o . . . . . I] + // + + self.tail = self.wrap_sub(self.tail, 1); + } + (true, true, _) => { + unsafe { + // contiguous, insert closer to tail: + // + // T I H + // [. . . o o A o o o o . . . . . .] + // + // T H + // [. . o o I A o o o o . . . . . .] + // M M + // + // contiguous, insert closer to tail and tail is 0: + // + // + // T I H + // [o o A o o o o . . . . . . . . .] + // + // H T + // [o I A o o o o o . . . . . . . o] + // M M + + let new_tail = self.wrap_sub(self.tail, 1); + + self.copy(new_tail, self.tail, 1); + // Already moved the tail, so we only copy `index - 1` elements. + self.copy(self.tail, self.tail + 1, index - 1); + + self.tail = new_tail; + } + } + (true, false, _) => { + unsafe { + // contiguous, insert closer to head: + // + // T I H + // [. . . o o o o A o o . . . . . .] + // + // T H + // [. . . o o o o I A o o . . . . .] + // M M M + + self.copy(idx + 1, idx, self.head - idx); + self.head = self.wrap_add(self.head, 1); + } + } + (false, true, true) => { + unsafe { + // discontiguous, insert closer to tail, tail section: + // + // H T I + // [o o o o o o . . . . . o o A o o] + // + // H T + // [o o o o o o . . . . o o I A o o] + // M M + + self.copy(self.tail - 1, self.tail, index); + self.tail -= 1; + } + } + (false, false, true) => { + unsafe { + // discontiguous, insert closer to head, tail section: + // + // H T I + // [o o . . . . . . . o o o o o A o] + // + // H T + // [o o o . . . . . . o o o o o I A] + // M M M M + + // copy elements up to new head + self.copy(1, 0, self.head); + + // copy last element into empty spot at bottom of buffer + self.copy(0, self.cap() - 1, 1); + + // move elements from idx to end forward not including ^ element + self.copy(idx + 1, idx, self.cap() - 1 - idx); + + self.head += 1; + } + } + (false, true, false) if idx == 0 => { + unsafe { + // discontiguous, insert is closer to tail, head section, + // and is at index zero in the internal buffer: + // + // I H T + // [A o o o o o o o o o . . . o o o] + // + // H T + // [A o o o o o o o o o . . o o o I] + // M M M + + // copy elements up to new tail + self.copy(self.tail - 1, self.tail, self.cap() - self.tail); + + // copy last element into empty spot at bottom of buffer + self.copy(self.cap() - 1, 0, 1); + + self.tail -= 1; + } + } + (false, true, false) => { + unsafe { + // discontiguous, insert closer to tail, head section: + // + // I H T + // [o o o A o o o o o o . . . o o o] + // + // H T + // [o o I A o o o o o o . . o o o o] + // M M M M M M + + // copy elements up to new tail + self.copy(self.tail - 1, self.tail, self.cap() - self.tail); + + // copy last element into empty spot at bottom of buffer + self.copy(self.cap() - 1, 0, 1); + + // move elements from idx-1 to end forward not including ^ element + self.copy(0, 1, idx - 1); + + self.tail -= 1; + } + } + (false, false, false) => { + unsafe { + // discontiguous, insert closer to head, head section: + // + // I H T + // [o o o o A o o . . . . . . o o o] + // + // H T + // [o o o o I A o o . . . . . o o o] + // M M M + + self.copy(idx + 1, idx, self.head - idx); + self.head += 1; + } + } + } + + // tail might've been changed so we need to recalculate + let new_idx = self.wrap_add(self.tail, index); + unsafe { + self.buffer_write(new_idx, value); + } + } + + /// Removes and returns the element at `index` from the `VecDeque`. + /// Whichever end is closer to the removal point will be moved to make + /// room, and all the affected elements will be moved to new positions. + /// Returns `None` if `index` is out of bounds. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(1); + /// buf.push_back(2); + /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); + /// + /// assert_eq!(buf.remove(1), Some(2)); + /// assert_eq!(buf, [1, 3]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(&mut self, index: usize) -> Option { + if self.is_empty() || self.len() <= index { + return None; + } + + // There are three main cases: + // Elements are contiguous + // Elements are discontiguous and the removal is in the tail section + // Elements are discontiguous and the removal is in the head section + // - special case when elements are technically contiguous, + // but self.head = 0 + // + // For each of those there are two more cases: + // Insert is closer to tail + // Insert is closer to head + // + // Key: H - self.head + // T - self.tail + // o - Valid element + // x - Element marked for removal + // R - Indicates element that is being removed + // M - Indicates element was moved + + let idx = self.wrap_add(self.tail, index); + + let elem = unsafe { Some(self.buffer_read(idx)) }; + + let distance_to_tail = index; + let distance_to_head = self.len() - index; + + let contiguous = self.is_contiguous(); + + match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { + (true, true, _) => { + unsafe { + // contiguous, remove closer to tail: + // + // T R H + // [. . . o o x o o o o . . . . . .] + // + // T H + // [. . . . o o o o o o . . . . . .] + // M M + + self.copy(self.tail + 1, self.tail, index); + self.tail += 1; + } + } + (true, false, _) => { + unsafe { + // contiguous, remove closer to head: + // + // T R H + // [. . . o o o o x o o . . . . . .] + // + // T H + // [. . . o o o o o o . . . . . . .] + // M M + + self.copy(idx, idx + 1, self.head - idx - 1); + self.head -= 1; + } + } + (false, true, true) => { + unsafe { + // discontiguous, remove closer to tail, tail section: + // + // H T R + // [o o o o o o . . . . . o o x o o] + // + // H T + // [o o o o o o . . . . . . o o o o] + // M M + + self.copy(self.tail + 1, self.tail, index); + self.tail = self.wrap_add(self.tail, 1); + } + } + (false, false, false) => { + unsafe { + // discontiguous, remove closer to head, head section: + // + // R H T + // [o o o o x o o . . . . . . o o o] + // + // H T + // [o o o o o o . . . . . . . o o o] + // M M + + self.copy(idx, idx + 1, self.head - idx - 1); + self.head -= 1; + } + } + (false, false, true) => { + unsafe { + // discontiguous, remove closer to head, tail section: + // + // H T R + // [o o o . . . . . . o o o o o x o] + // + // H T + // [o o . . . . . . . o o o o o o o] + // M M M M + // + // or quasi-discontiguous, remove next to head, tail section: + // + // H T R + // [. . . . . . . . . o o o o o x o] + // + // T H + // [. . . . . . . . . o o o o o o .] + // M + + // draw in elements in the tail section + self.copy(idx, idx + 1, self.cap() - idx - 1); + + // Prevents underflow. + if self.head != 0 { + // copy first element into empty spot + self.copy(self.cap() - 1, 0, 1); + + // move elements in the head section backwards + self.copy(0, 1, self.head - 1); + } + + self.head = self.wrap_sub(self.head, 1); + } + } + (false, true, false) => { + unsafe { + // discontiguous, remove closer to tail, head section: + // + // R H T + // [o o x o o o o o o o . . . o o o] + // + // H T + // [o o o o o o o o o o . . . . o o] + // M M M M M + + // draw in elements up to idx + self.copy(1, 0, idx); + + // copy last element into empty spot + self.copy(0, self.cap() - 1, 1); + + // move elements from tail to end forward, excluding the last one + self.copy(self.tail + 1, self.tail, self.cap() - self.tail - 1); + + self.tail = self.wrap_add(self.tail, 1); + } + } + } + + return elem; + } + + /// Splits the `VecDeque` into two at the given index. + /// + /// Returns a newly allocated `VecDeque`. `self` contains elements `[0, at)`, + /// and the returned `VecDeque` contains elements `[at, len)`. + /// + /// Note that the capacity of `self` does not change. + /// + /// Element at index 0 is the front of the queue. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); + /// let buf2 = buf.split_off(1); + /// assert_eq!(buf, [1]); + /// assert_eq!(buf2, [2, 3]); + /// ``` + #[inline] + #[stable(feature = "split_off", since = "1.4.0")] + pub fn split_off(&mut self, at: usize) -> Self { + let len = self.len(); + assert!(at <= len, "`at` out of bounds"); + + let other_len = len - at; + let mut other = VecDeque::with_capacity(other_len); + + unsafe { + let (first_half, second_half) = self.as_slices(); + + let first_len = first_half.len(); + let second_len = second_half.len(); + if at < first_len { + // `at` lies in the first half. + let amount_in_first = first_len - at; + + ptr::copy_nonoverlapping(first_half.as_ptr().offset(at as isize), + other.ptr(), + amount_in_first); + + // just take all of the second half. + ptr::copy_nonoverlapping(second_half.as_ptr(), + other.ptr().offset(amount_in_first as isize), + second_len); + } else { + // `at` lies in the second half, need to factor in the elements we skipped + // in the first half. + let offset = at - first_len; + let amount_in_second = second_len - offset; + ptr::copy_nonoverlapping(second_half.as_ptr().offset(offset as isize), + other.ptr(), + amount_in_second); + } + } + + // Cleanup where the ends of the buffers are + self.head = self.wrap_sub(self.head, other_len); + other.head = other.wrap_index(other_len); + + other + } + + /// Moves all the elements of `other` into `Self`, leaving `other` empty. + /// + /// # Panics + /// + /// Panics if the new number of elements in self overflows a `usize`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf: VecDeque<_> = vec![1, 2].into_iter().collect(); + /// let mut buf2: VecDeque<_> = vec![3, 4].into_iter().collect(); + /// buf.append(&mut buf2); + /// assert_eq!(buf, [1, 2, 3, 4]); + /// assert_eq!(buf2, []); + /// ``` + #[inline] + #[stable(feature = "append", since = "1.4.0")] + pub fn append(&mut self, other: &mut Self) { + // naive impl + self.extend(other.drain(..)); + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns false. + /// This method operates in place and preserves the order of the retained + /// elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.extend(1..5); + /// buf.retain(|&x| x%2 == 0); + /// assert_eq!(buf, [2, 4]); + /// ``` + #[stable(feature = "vec_deque_retain", since = "1.4.0")] + pub fn retain(&mut self, mut f: F) + where F: FnMut(&T) -> bool + { + let len = self.len(); + let mut del = 0; + for i in 0..len { + if !f(&self[i]) { + del += 1; + } else if del > 0 { + self.swap(i - del, i); + } + } + if del > 0 { + self.truncate(len - del); + } + } + + // This may panic or abort + #[inline] + fn grow_if_necessary(&mut self) { + if self.is_full() { + let old_cap = self.cap(); + self.buf.double(); + unsafe { + self.handle_cap_increase(old_cap); + } + debug_assert!(!self.is_full()); + } + } +} + +impl VecDeque { + /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len, + /// either by removing excess elements from the back or by appending clones of `value` + /// to the back. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_back(5); + /// buf.push_back(10); + /// buf.push_back(15); + /// assert_eq!(buf, [5, 10, 15]); + /// + /// buf.resize(2, 0); + /// assert_eq!(buf, [5, 10]); + /// + /// buf.resize(5, 20); + /// assert_eq!(buf, [5, 10, 20, 20, 20]); + /// ``` + #[stable(feature = "deque_extras", since = "1.16.0")] + pub fn resize(&mut self, new_len: usize, value: T) { + let len = self.len(); + + if new_len > len { + self.extend(repeat(value).take(new_len - len)) + } else { + self.truncate(new_len); + } + } +} + +/// Returns the index in the underlying buffer for a given logical element index. +#[inline] +fn wrap_index(index: usize, size: usize) -> usize { + // size is always a power of 2 + debug_assert!(size.is_power_of_two()); + index & (size - 1) +} + +/// Returns the two slices that cover the `VecDeque`'s valid range +trait RingSlices: Sized { + fn slice(self, from: usize, to: usize) -> Self; + fn split_at(self, i: usize) -> (Self, Self); + + fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) { + let contiguous = tail <= head; + if contiguous { + let (empty, buf) = buf.split_at(0); + (buf.slice(tail, head), empty) + } else { + let (mid, right) = buf.split_at(tail); + let (left, _) = mid.split_at(head); + (right, left) + } + } +} + +impl<'a, T> RingSlices for &'a [T] { + fn slice(self, from: usize, to: usize) -> Self { + &self[from..to] + } + fn split_at(self, i: usize) -> (Self, Self) { + (*self).split_at(i) + } +} + +impl<'a, T> RingSlices for &'a mut [T] { + fn slice(self, from: usize, to: usize) -> Self { + &mut self[from..to] + } + fn split_at(self, i: usize) -> (Self, Self) { + (*self).split_at_mut(i) + } +} + +/// Calculate the number of elements left to be read in the buffer +#[inline] +fn count(tail: usize, head: usize, size: usize) -> usize { + // size is always a power of 2 + (head.wrapping_sub(tail)) & (size - 1) +} + +/// An iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.VecDeque.html#method.iter +/// [`VecDeque`]: struct.VecDeque.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + ring: &'a [T], + tail: usize, + head: usize, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Iter") + .field(&self.ring) + .field(&self.tail) + .field(&self.head) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Clone for Iter<'a, T> { + fn clone(&self) -> Iter<'a, T> { + Iter { + ring: self.ring, + tail: self.tail, + head: self.head, + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + if self.tail == self.head { + return None; + } + let tail = self.tail; + self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); + unsafe { Some(self.ring.get_unchecked(tail)) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = count(self.tail, self.head, self.ring.len()); + (len, Some(len)) + } + + fn fold(self, mut accum: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = front.iter().fold(accum, &mut f); + back.iter().fold(accum, &mut f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a T> { + if self.tail == self.head { + return None; + } + self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); + unsafe { Some(self.ring.get_unchecked(self.head)) } + } + + fn rfold(self, mut accum: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = back.iter().rfold(accum, &mut f); + front.iter().rfold(accum, &mut f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn is_empty(&self) -> bool { + self.head == self.tail + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T> FusedIterator for Iter<'a, T> {} + + +/// A mutable iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut +/// [`VecDeque`]: struct.VecDeque.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + ring: &'a mut [T], + tail: usize, + head: usize, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IterMut") + .field(&self.ring) + .field(&self.tail) + .field(&self.head) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + #[inline] + fn next(&mut self) -> Option<&'a mut T> { + if self.tail == self.head { + return None; + } + let tail = self.tail; + self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); + + unsafe { + let elem = self.ring.get_unchecked_mut(tail); + Some(&mut *(elem as *mut _)) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = count(self.tail, self.head, self.ring.len()); + (len, Some(len)) + } + + fn fold(self, mut accum: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = front.iter_mut().fold(accum, &mut f); + back.iter_mut().fold(accum, &mut f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut T> { + if self.tail == self.head { + return None; + } + self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); + + unsafe { + let elem = self.ring.get_unchecked_mut(self.head); + Some(&mut *(elem as *mut _)) + } + } + + fn rfold(self, mut accum: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = back.iter_mut().rfold(accum, &mut f); + front.iter_mut().rfold(accum, &mut f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> ExactSizeIterator for IterMut<'a, T> { + fn is_empty(&self) -> bool { + self.head == self.tail + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T> FusedIterator for IterMut<'a, T> {} + +/// An owning iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.VecDeque.html#method.into_iter +/// [`VecDeque`]: struct.VecDeque.html +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter { + inner: VecDeque, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IntoIter") + .field(&self.inner) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.inner.pop_front() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.inner.len(); + (len, Some(len)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.inner.pop_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter { + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +/// A draining iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.VecDeque.html#method.drain +/// [`VecDeque`]: struct.VecDeque.html +#[stable(feature = "drain", since = "1.6.0")] +pub struct Drain<'a, T: 'a> { + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: NonNull>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Drain") + .field(&self.after_tail) + .field(&self.after_head) + .field(&self.iter) + .finish() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} +#[stable(feature = "drain", since = "1.6.0")] +unsafe impl<'a, T: Send> Send for Drain<'a, T> {} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, T: 'a> Drop for Drain<'a, T> { + fn drop(&mut self) { + self.for_each(drop); + + let source_deque = unsafe { self.deque.as_mut() }; + + // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head + // + // T t h H + // [. . . o o x x o o . . .] + // + let orig_tail = source_deque.tail; + let drain_tail = source_deque.head; + let drain_head = self.after_tail; + let orig_head = self.after_head; + + let tail_len = count(orig_tail, drain_tail, source_deque.cap()); + let head_len = count(drain_head, orig_head, source_deque.cap()); + + // Restore the original head value + source_deque.head = orig_head; + + match (tail_len, head_len) { + (0, 0) => { + source_deque.head = 0; + source_deque.tail = 0; + } + (0, _) => { + source_deque.tail = drain_head; + } + (_, 0) => { + source_deque.head = drain_tail; + } + _ => unsafe { + if tail_len <= head_len { + source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); + source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); + } else { + source_deque.head = source_deque.wrap_add(drain_tail, head_len); + source_deque.wrap_copy(drain_tail, drain_head, head_len); + } + }, + } + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, T: 'a> Iterator for Drain<'a, T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(|elt| unsafe { ptr::read(elt) }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(|elt| unsafe { ptr::read(elt) }) + } +} + +#[stable(feature = "drain", since = "1.6.0")] +impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for VecDeque { + fn eq(&self, other: &VecDeque) -> bool { + if self.len() != other.len() { + return false; + } + let (sa, sb) = self.as_slices(); + let (oa, ob) = other.as_slices(); + if sa.len() == oa.len() { + sa == oa && sb == ob + } else if sa.len() < oa.len() { + // Always divisible in three sections, for example: + // self: [a b c|d e f] + // other: [0 1 2 3|4 5] + // front = 3, mid = 1, + // [a b c] == [0 1 2] && [d] == [3] && [e f] == [4 5] + let front = sa.len(); + let mid = oa.len() - front; + + let (oa_front, oa_mid) = oa.split_at(front); + let (sb_mid, sb_back) = sb.split_at(mid); + debug_assert_eq!(sa.len(), oa_front.len()); + debug_assert_eq!(sb_mid.len(), oa_mid.len()); + debug_assert_eq!(sb_back.len(), ob.len()); + sa == oa_front && sb_mid == oa_mid && sb_back == ob + } else { + let front = oa.len(); + let mid = sa.len() - front; + + let (sa_front, sa_mid) = sa.split_at(front); + let (ob_mid, ob_back) = ob.split_at(mid); + debug_assert_eq!(sa_front.len(), oa.len()); + debug_assert_eq!(sa_mid.len(), ob_mid.len()); + debug_assert_eq!(sb.len(), ob_back.len()); + sa_front == oa && sa_mid == ob_mid && sb == ob_back + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for VecDeque {} + +macro_rules! __impl_slice_eq1 { + ($Lhs: ty, $Rhs: ty) => { + __impl_slice_eq1! { $Lhs, $Rhs, Sized } + }; + ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + #[stable(feature = "vec-deque-partial-eq-slice", since = "1.17.0")] + impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + fn eq(&self, other: &$Rhs) -> bool { + if self.len() != other.len() { + return false; + } + let (sa, sb) = self.as_slices(); + let (oa, ob) = other[..].split_at(sa.len()); + sa == oa && sb == ob + } + } + } +} + +__impl_slice_eq1! { VecDeque, Vec } +__impl_slice_eq1! { VecDeque, &'b [B] } +__impl_slice_eq1! { VecDeque, &'b mut [B] } + +macro_rules! array_impls { + ($($N: expr)+) => { + $( + __impl_slice_eq1! { VecDeque, [B; $N] } + __impl_slice_eq1! { VecDeque, &'b [B; $N] } + __impl_slice_eq1! { VecDeque, &'b mut [B; $N] } + )+ + } +} + +array_impls! { + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for VecDeque { + fn partial_cmp(&self, other: &VecDeque) -> Option { + self.iter().partial_cmp(other.iter()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for VecDeque { + #[inline] + fn cmp(&self, other: &VecDeque) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for VecDeque { + fn hash(&self, state: &mut H) { + self.len().hash(state); + let (a, b) = self.as_slices(); + Hash::hash_slice(a, state); + Hash::hash_slice(b, state); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Index for VecDeque { + type Output = A; + + #[inline] + fn index(&self, index: usize) -> &A { + self.get(index).expect("Out of bounds access") + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IndexMut for VecDeque { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut A { + self.get_mut(index).expect("Out of bounds access") + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator for VecDeque { + fn from_iter>(iter: T) -> VecDeque { + let iterator = iter.into_iter(); + let (lower, _) = iterator.size_hint(); + let mut deq = VecDeque::with_capacity(lower); + deq.extend(iterator); + deq + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for VecDeque { + type Item = T; + type IntoIter = IntoIter; + + /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by + /// value. + fn into_iter(self) -> IntoIter { + IntoIter { inner: self } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a VecDeque { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a mut VecDeque { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend for VecDeque { + fn extend>(&mut self, iter: T) { + for elt in iter { + self.push_back(elt); + } + } +} + +#[stable(feature = "extend_ref", since = "1.2.0")] +impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for VecDeque { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +#[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] +impl From> for VecDeque { + fn from(mut other: Vec) -> Self { + unsafe { + let other_buf = other.as_mut_ptr(); + let mut buf = RawVec::from_raw_parts(other_buf, other.capacity()); + let len = other.len(); + mem::forget(other); + + // We need to extend the buf if it's not a power of two, too small + // or doesn't have at least one free space + if !buf.cap().is_power_of_two() || (buf.cap() < (MINIMUM_CAPACITY + 1)) || + (buf.cap() == len) { + let cap = cmp::max(buf.cap() + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); + buf.reserve_exact(len, cap - len); + } + + VecDeque { + tail: 0, + head: len, + buf, + } + } + } +} + +#[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] +impl From> for Vec { + fn from(other: VecDeque) -> Self { + unsafe { + let buf = other.buf.ptr(); + let len = other.len(); + let tail = other.tail; + let head = other.head; + let cap = other.cap(); + + // Need to move the ring to the front of the buffer, as vec will expect this. + if other.is_contiguous() { + ptr::copy(buf.offset(tail as isize), buf, len); + } else { + if (tail - head) >= cmp::min(cap - tail, head) { + // There is enough free space in the centre for the shortest block so we can + // do this in at most three copy moves. + if (cap - tail) > head { + // right hand block is the long one; move that enough for the left + ptr::copy(buf.offset(tail as isize), + buf.offset((tail - head) as isize), + cap - tail); + // copy left in the end + ptr::copy(buf, buf.offset((cap - head) as isize), head); + // shift the new thing to the start + ptr::copy(buf.offset((tail - head) as isize), buf, len); + } else { + // left hand block is the long one, we can do it in two! + ptr::copy(buf, buf.offset((cap - tail) as isize), head); + ptr::copy(buf.offset(tail as isize), buf, cap - tail); + } + } else { + // Need to use N swaps to move the ring + // We can use the space at the end of the ring as a temp store + + let mut left_edge: usize = 0; + let mut right_edge: usize = tail; + + // The general problem looks like this + // GHIJKLM...ABCDEF - before any swaps + // ABCDEFM...GHIJKL - after 1 pass of swaps + // ABCDEFGHIJM...KL - swap until the left edge reaches the temp store + // - then restart the algorithm with a new (smaller) store + // Sometimes the temp store is reached when the right edge is at the end + // of the buffer - this means we've hit the right order with fewer swaps! + // E.g + // EF..ABCD + // ABCDEF.. - after four only swaps we've finished + + while left_edge < len && right_edge != cap { + let mut right_offset = 0; + for i in left_edge..right_edge { + right_offset = (i - left_edge) % (cap - right_edge); + let src: isize = (right_edge + right_offset) as isize; + ptr::swap(buf.offset(i as isize), buf.offset(src)); + } + let n_ops = right_edge - left_edge; + left_edge += n_ops; + right_edge += right_offset + 1; + + } + } + + } + let out = Vec::from_raw_parts(buf, len, cap); + mem::forget(other); + out + } + } +} + +#[cfg(test)] +mod tests { + use test; + + use super::VecDeque; + + #[bench] + fn bench_push_back_100(b: &mut test::Bencher) { + let mut deq = VecDeque::with_capacity(101); + b.iter(|| { + for i in 0..100 { + deq.push_back(i); + } + deq.head = 0; + deq.tail = 0; + }) + } + + #[bench] + fn bench_push_front_100(b: &mut test::Bencher) { + let mut deq = VecDeque::with_capacity(101); + b.iter(|| { + for i in 0..100 { + deq.push_front(i); + } + deq.head = 0; + deq.tail = 0; + }) + } + + #[bench] + fn bench_pop_back_100(b: &mut test::Bencher) { + let mut deq = VecDeque::::with_capacity(101); + + b.iter(|| { + deq.head = 100; + deq.tail = 0; + while !deq.is_empty() { + test::black_box(deq.pop_back()); + } + }) + } + + #[bench] + fn bench_pop_front_100(b: &mut test::Bencher) { + let mut deq = VecDeque::::with_capacity(101); + + b.iter(|| { + deq.head = 100; + deq.tail = 0; + while !deq.is_empty() { + test::black_box(deq.pop_front()); + } + }) + } + + #[test] + fn test_swap_front_back_remove() { + fn test(back: bool) { + // This test checks that every single combination of tail position and length is tested. + // Capacity 15 should be large enough to cover every case. + let mut tester = VecDeque::with_capacity(15); + let usable_cap = tester.capacity(); + let final_len = usable_cap / 2; + + for len in 0..final_len { + let expected: VecDeque<_> = if back { + (0..len).collect() + } else { + (0..len).rev().collect() + }; + for tail_pos in 0..usable_cap { + tester.tail = tail_pos; + tester.head = tail_pos; + if back { + for i in 0..len * 2 { + tester.push_front(i); + } + for i in 0..len { + assert_eq!(tester.swap_remove_back(i), Some(len * 2 - 1 - i)); + } + } else { + for i in 0..len * 2 { + tester.push_back(i); + } + for i in 0..len { + let idx = tester.len() - 1 - i; + assert_eq!(tester.swap_remove_front(idx), Some(len * 2 - 1 - i)); + } + } + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + assert_eq!(tester, expected); + } + } + } + test(true); + test(false); + } + + #[test] + fn test_insert() { + // This test checks that every single combination of tail position, length, and + // insertion position is tested. Capacity 15 should be large enough to cover every case. + + let mut tester = VecDeque::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else + // this test isn't covering what it wants to + let cap = tester.capacity(); + + + // len is the length *after* insertion + for len in 1..cap { + // 0, 1, 2, .., len - 1 + let expected = (0..).take(len).collect::>(); + for tail_pos in 0..cap { + for to_insert in 0..len { + tester.tail = tail_pos; + tester.head = tail_pos; + for i in 0..len { + if i != to_insert { + tester.push_back(i); + } + } + tester.insert(to_insert, to_insert); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + assert_eq!(tester, expected); + } + } + } + } + + #[test] + fn test_remove() { + // This test checks that every single combination of tail position, length, and + // removal position is tested. Capacity 15 should be large enough to cover every case. + + let mut tester = VecDeque::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else + // this test isn't covering what it wants to + let cap = tester.capacity(); + + // len is the length *after* removal + for len in 0..cap - 1 { + // 0, 1, 2, .., len - 1 + let expected = (0..).take(len).collect::>(); + for tail_pos in 0..cap { + for to_remove in 0..len + 1 { + tester.tail = tail_pos; + tester.head = tail_pos; + for i in 0..len { + if i == to_remove { + tester.push_back(1234); + } + tester.push_back(i); + } + if to_remove == len { + tester.push_back(1234); + } + tester.remove(to_remove); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + assert_eq!(tester, expected); + } + } + } + } + + #[test] + fn test_drain() { + let mut tester: VecDeque = VecDeque::with_capacity(7); + + let cap = tester.capacity(); + for len in 0..cap + 1 { + for tail in 0..cap + 1 { + for drain_start in 0..len + 1 { + for drain_end in drain_start..len + 1 { + tester.tail = tail; + tester.head = tail; + for i in 0..len { + tester.push_back(i); + } + + // Check that we drain the correct values + let drained: VecDeque<_> = tester.drain(drain_start..drain_end).collect(); + let drained_expected: VecDeque<_> = (drain_start..drain_end).collect(); + assert_eq!(drained, drained_expected); + + // We shouldn't have changed the capacity or made the + // head or tail out of bounds + assert_eq!(tester.capacity(), cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + + // We should see the correct values in the VecDeque + let expected: VecDeque<_> = (0..drain_start) + .chain(drain_end..len) + .collect(); + assert_eq!(expected, tester); + } + } + } + } + } + + #[test] + fn test_shrink_to_fit() { + // This test checks that every single combination of head and tail position, + // is tested. Capacity 15 should be large enough to cover every case. + + let mut tester = VecDeque::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else + // this test isn't covering what it wants to + let cap = tester.capacity(); + tester.reserve(63); + let max_cap = tester.capacity(); + + for len in 0..cap + 1 { + // 0, 1, 2, .., len - 1 + let expected = (0..).take(len).collect::>(); + for tail_pos in 0..max_cap + 1 { + tester.tail = tail_pos; + tester.head = tail_pos; + tester.reserve(63); + for i in 0..len { + tester.push_back(i); + } + tester.shrink_to_fit(); + assert!(tester.capacity() <= cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + assert_eq!(tester, expected); + } + } + } + + #[test] + fn test_split_off() { + // This test checks that every single combination of tail position, length, and + // split position is tested. Capacity 15 should be large enough to cover every case. + + let mut tester = VecDeque::with_capacity(15); + // can't guarantee we got 15, so have to get what we got. + // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else + // this test isn't covering what it wants to + let cap = tester.capacity(); + + // len is the length *before* splitting + for len in 0..cap { + // index to split at + for at in 0..len + 1 { + // 0, 1, 2, .., at - 1 (may be empty) + let expected_self = (0..).take(at).collect::>(); + // at, at + 1, .., len - 1 (may be empty) + let expected_other = (at..).take(len - at).collect::>(); + + for tail_pos in 0..cap { + tester.tail = tail_pos; + tester.head = tail_pos; + for i in 0..len { + tester.push_back(i); + } + let result = tester.split_off(at); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + assert!(result.tail < result.cap()); + assert!(result.head < result.cap()); + assert_eq!(tester, expected_self); + assert_eq!(result, expected_other); + } + } + } + } + + #[test] + fn test_from_vec() { + use vec::Vec; + for cap in 0..35 { + for len in 0..cap + 1 { + let mut vec = Vec::with_capacity(cap); + vec.extend(0..len); + + let vd = VecDeque::from(vec.clone()); + assert!(vd.cap().is_power_of_two()); + assert_eq!(vd.len(), vec.len()); + assert!(vd.into_iter().eq(vec)); + } + } + } + + #[test] + fn test_vec_from_vecdeque() { + use vec::Vec; + + fn create_vec_and_test_convert(cap: usize, offset: usize, len: usize) { + let mut vd = VecDeque::with_capacity(cap); + for _ in 0..offset { + vd.push_back(0); + vd.pop_front(); + } + vd.extend(0..len); + + let vec: Vec<_> = Vec::from(vd.clone()); + assert_eq!(vec.len(), vd.len()); + assert!(vec.into_iter().eq(vd)); + } + + for cap_pwr in 0..7 { + // Make capacity as a (2^x)-1, so that the ring size is 2^x + let cap = (2i32.pow(cap_pwr) - 1) as usize; + + // In these cases there is enough free space to solve it with copies + for len in 0..((cap + 1) / 2) { + // Test contiguous cases + for offset in 0..(cap - len) { + create_vec_and_test_convert(cap, offset, len) + } + + // Test cases where block at end of buffer is bigger than block at start + for offset in (cap - len)..(cap - (len / 2)) { + create_vec_and_test_convert(cap, offset, len) + } + + // Test cases where block at start of buffer is bigger than block at end + for offset in (cap - (len / 2))..cap { + create_vec_and_test_convert(cap, offset, len) + } + } + + // Now there's not (necessarily) space to straighten the ring with simple copies, + // the ring will use swapping when: + // (cap + 1 - offset) > (cap + 1 - len) && (len - (cap + 1 - offset)) > (cap + 1 - len)) + // right block size > free space && left block size > free space + for len in ((cap + 1) / 2)..cap { + // Test contiguous cases + for offset in 0..(cap - len) { + create_vec_and_test_convert(cap, offset, len) + } + + // Test cases where block at end of buffer is bigger than block at start + for offset in (cap - len)..(cap - (len / 2)) { + create_vec_and_test_convert(cap, offset, len) + } + + // Test cases where block at start of buffer is bigger than block at end + for offset in (cap - (len / 2))..cap { + create_vec_and_test_convert(cap, offset, len) + } + } + } + } + +} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 585e34f5851..e8be9ecfa36 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -162,59 +162,24 @@ mod boxed { } #[cfg(test)] mod boxed_test; +pub mod collections; #[cfg(target_has_atomic = "ptr")] pub mod arc; pub mod rc; pub mod raw_vec; -// collections modules -pub mod binary_heap; -mod btree; pub mod borrow; pub mod fmt; -pub mod linked_list; pub mod slice; pub mod str; pub mod string; pub mod vec; -pub mod vec_deque; - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod btree_map { - //! A map based on a B-Tree. - #[stable(feature = "rust1", since = "1.0.0")] - pub use btree::map::*; -} - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod btree_set { - //! A set based on a B-Tree. - #[stable(feature = "rust1", since = "1.0.0")] - pub use btree::set::*; -} #[cfg(not(test))] mod std { pub use core::ops; // RangeFull } -/// An intermediate trait for specialization of `Extend`. -#[doc(hidden)] -trait SpecExtend { - /// Extends `self` with the contents of the given iterator. - fn spec_extend(&mut self, iter: I); -} - -#[doc(no_inline)] -pub use binary_heap::BinaryHeap; -#[doc(no_inline)] -pub use btree_map::BTreeMap; -#[doc(no_inline)] -pub use btree_set::BTreeSet; -#[doc(no_inline)] -pub use linked_list::LinkedList; -#[doc(no_inline)] -pub use vec_deque::VecDeque; #[doc(no_inline)] pub use string::String; #[doc(no_inline)] diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs deleted file mode 100644 index 9844de9a57d..00000000000 --- a/src/liballoc/linked_list.rs +++ /dev/null @@ -1,1486 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A doubly-linked list with owned nodes. -//! -//! The `LinkedList` allows pushing and popping elements at either end -//! in constant time. -//! -//! Almost always it is better to use `Vec` or [`VecDeque`] instead of -//! [`LinkedList`]. In general, array-based containers are faster, -//! more memory efficient and make better use of CPU cache. -//! -//! [`LinkedList`]: ../linked_list/struct.LinkedList.html -//! [`VecDeque`]: ../vec_deque/struct.VecDeque.html - -#![stable(feature = "rust1", since = "1.0.0")] - -use core::cmp::Ordering; -use core::fmt; -use core::hash::{Hasher, Hash}; -use core::iter::{FromIterator, FusedIterator}; -use core::marker::PhantomData; -use core::mem; -use core::ptr::NonNull; - -use boxed::Box; -use super::SpecExtend; - -/// A doubly-linked list with owned nodes. -/// -/// The `LinkedList` allows pushing and popping elements at either end -/// in constant time. -/// -/// Almost always it is better to use `Vec` or `VecDeque` instead of -/// `LinkedList`. In general, array-based containers are faster, -/// more memory efficient and make better use of CPU cache. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct LinkedList { - head: Option>>, - tail: Option>>, - len: usize, - marker: PhantomData>>, -} - -struct Node { - next: Option>>, - prev: Option>>, - element: T, -} - -/// An iterator over the elements of a `LinkedList`. -/// -/// This `struct` is created by the [`iter`] method on [`LinkedList`]. See its -/// documentation for more. -/// -/// [`iter`]: struct.LinkedList.html#method.iter -/// [`LinkedList`]: struct.LinkedList.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - head: Option>>, - tail: Option>>, - len: usize, - marker: PhantomData<&'a Node>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.len) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Self { - Iter { ..*self } - } -} - -/// A mutable iterator over the elements of a `LinkedList`. -/// -/// This `struct` is created by the [`iter_mut`] method on [`LinkedList`]. See its -/// documentation for more. -/// -/// [`iter_mut`]: struct.LinkedList.html#method.iter_mut -/// [`LinkedList`]: struct.LinkedList.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IterMut<'a, T: 'a> { - list: &'a mut LinkedList, - head: Option>>, - tail: Option>>, - len: usize, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("IterMut") - .field(&self.list) - .field(&self.len) - .finish() - } -} - -/// An owning iterator over the elements of a `LinkedList`. -/// -/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`into_iter`]: struct.LinkedList.html#method.into_iter -/// [`LinkedList`]: struct.LinkedList.html -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - list: LinkedList, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("IntoIter") - .field(&self.list) - .finish() - } -} - -impl Node { - fn new(element: T) -> Self { - Node { - next: None, - prev: None, - element, - } - } - - fn into_element(self: Box) -> T { - self.element - } -} - -// private methods -impl LinkedList { - /// Adds the given node to the front of the list. - #[inline] - fn push_front_node(&mut self, mut node: Box>) { - unsafe { - node.next = self.head; - node.prev = None; - let node = Some(Box::into_raw_non_null(node)); - - match self.head { - None => self.tail = node, - Some(mut head) => head.as_mut().prev = node, - } - - self.head = node; - self.len += 1; - } - } - - /// Removes and returns the node at the front of the list. - #[inline] - fn pop_front_node(&mut self) -> Option>> { - self.head.map(|node| unsafe { - let node = Box::from_raw(node.as_ptr()); - self.head = node.next; - - match self.head { - None => self.tail = None, - Some(mut head) => head.as_mut().prev = None, - } - - self.len -= 1; - node - }) - } - - /// Adds the given node to the back of the list. - #[inline] - fn push_back_node(&mut self, mut node: Box>) { - unsafe { - node.next = None; - node.prev = self.tail; - let node = Some(Box::into_raw_non_null(node)); - - match self.tail { - None => self.head = node, - Some(mut tail) => tail.as_mut().next = node, - } - - self.tail = node; - self.len += 1; - } - } - - /// Removes and returns the node at the back of the list. - #[inline] - fn pop_back_node(&mut self) -> Option>> { - self.tail.map(|node| unsafe { - let node = Box::from_raw(node.as_ptr()); - self.tail = node.prev; - - match self.tail { - None => self.head = None, - Some(mut tail) => tail.as_mut().next = None, - } - - self.len -= 1; - node - }) - } - - /// Unlinks the specified node from the current list. - /// - /// Warning: this will not check that the provided node belongs to the current list. - #[inline] - unsafe fn unlink_node(&mut self, mut node: NonNull>) { - let node = node.as_mut(); - - match node.prev { - Some(mut prev) => prev.as_mut().next = node.next.clone(), - // this node is the head node - None => self.head = node.next.clone(), - }; - - match node.next { - Some(mut next) => next.as_mut().prev = node.prev.clone(), - // this node is the tail node - None => self.tail = node.prev.clone(), - }; - - self.len -= 1; - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for LinkedList { - /// Creates an empty `LinkedList`. - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl LinkedList { - /// Creates an empty `LinkedList`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let list: LinkedList = LinkedList::new(); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Self { - LinkedList { - head: None, - tail: None, - len: 0, - marker: PhantomData, - } - } - - /// Moves all elements from `other` to the end of the list. - /// - /// This reuses all the nodes from `other` and moves them into `self`. After - /// this operation, `other` becomes empty. - /// - /// This operation should compute in O(1) time and O(1) memory. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut list1 = LinkedList::new(); - /// list1.push_back('a'); - /// - /// let mut list2 = LinkedList::new(); - /// list2.push_back('b'); - /// list2.push_back('c'); - /// - /// list1.append(&mut list2); - /// - /// let mut iter = list1.iter(); - /// assert_eq!(iter.next(), Some(&'a')); - /// assert_eq!(iter.next(), Some(&'b')); - /// assert_eq!(iter.next(), Some(&'c')); - /// assert!(iter.next().is_none()); - /// - /// assert!(list2.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn append(&mut self, other: &mut Self) { - match self.tail { - None => mem::swap(self, other), - Some(mut tail) => { - if let Some(mut other_head) = other.head.take() { - unsafe { - tail.as_mut().next = Some(other_head); - other_head.as_mut().prev = Some(tail); - } - - self.tail = other.tail.take(); - self.len += mem::replace(&mut other.len, 0); - } - } - } - } - - /// Provides a forward iterator. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut list: LinkedList = LinkedList::new(); - /// - /// list.push_back(0); - /// list.push_back(1); - /// list.push_back(2); - /// - /// let mut iter = list.iter(); - /// assert_eq!(iter.next(), Some(&0)); - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { - head: self.head, - tail: self.tail, - len: self.len, - marker: PhantomData, - } - } - - /// Provides a forward iterator with mutable references. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut list: LinkedList = LinkedList::new(); - /// - /// list.push_back(0); - /// list.push_back(1); - /// list.push_back(2); - /// - /// for element in list.iter_mut() { - /// *element += 10; - /// } - /// - /// let mut iter = list.iter(); - /// assert_eq!(iter.next(), Some(&10)); - /// assert_eq!(iter.next(), Some(&11)); - /// assert_eq!(iter.next(), Some(&12)); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { - IterMut { - head: self.head, - tail: self.tail, - len: self.len, - list: self, - } - } - - /// Returns `true` if the `LinkedList` is empty. - /// - /// This operation should compute in O(1) time. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// assert!(dl.is_empty()); - /// - /// dl.push_front("foo"); - /// assert!(!dl.is_empty()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - self.head.is_none() - } - - /// Returns the length of the `LinkedList`. - /// - /// This operation should compute in O(1) time. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// - /// dl.push_front(2); - /// assert_eq!(dl.len(), 1); - /// - /// dl.push_front(1); - /// assert_eq!(dl.len(), 2); - /// - /// dl.push_back(3); - /// assert_eq!(dl.len(), 3); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { - self.len - } - - /// Removes all elements from the `LinkedList`. - /// - /// This operation should compute in O(n) time. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// - /// dl.push_front(2); - /// dl.push_front(1); - /// assert_eq!(dl.len(), 2); - /// assert_eq!(dl.front(), Some(&1)); - /// - /// dl.clear(); - /// assert_eq!(dl.len(), 0); - /// assert_eq!(dl.front(), None); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn clear(&mut self) { - *self = Self::new(); - } - - /// Returns `true` if the `LinkedList` contains an element equal to the - /// given value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut list: LinkedList = LinkedList::new(); - /// - /// list.push_back(0); - /// list.push_back(1); - /// list.push_back(2); - /// - /// assert_eq!(list.contains(&0), true); - /// assert_eq!(list.contains(&10), false); - /// ``` - #[stable(feature = "linked_list_contains", since = "1.12.0")] - pub fn contains(&self, x: &T) -> bool - where T: PartialEq - { - self.iter().any(|e| e == x) - } - - /// Provides a reference to the front element, or `None` if the list is - /// empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// assert_eq!(dl.front(), None); - /// - /// dl.push_front(1); - /// assert_eq!(dl.front(), Some(&1)); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn front(&self) -> Option<&T> { - unsafe { - self.head.as_ref().map(|node| &node.as_ref().element) - } - } - - /// Provides a mutable reference to the front element, or `None` if the list - /// is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// assert_eq!(dl.front(), None); - /// - /// dl.push_front(1); - /// assert_eq!(dl.front(), Some(&1)); - /// - /// match dl.front_mut() { - /// None => {}, - /// Some(x) => *x = 5, - /// } - /// assert_eq!(dl.front(), Some(&5)); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn front_mut(&mut self) -> Option<&mut T> { - unsafe { - self.head.as_mut().map(|node| &mut node.as_mut().element) - } - } - - /// Provides a reference to the back element, or `None` if the list is - /// empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// assert_eq!(dl.back(), None); - /// - /// dl.push_back(1); - /// assert_eq!(dl.back(), Some(&1)); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn back(&self) -> Option<&T> { - unsafe { - self.tail.as_ref().map(|node| &node.as_ref().element) - } - } - - /// Provides a mutable reference to the back element, or `None` if the list - /// is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// assert_eq!(dl.back(), None); - /// - /// dl.push_back(1); - /// assert_eq!(dl.back(), Some(&1)); - /// - /// match dl.back_mut() { - /// None => {}, - /// Some(x) => *x = 5, - /// } - /// assert_eq!(dl.back(), Some(&5)); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn back_mut(&mut self) -> Option<&mut T> { - unsafe { - self.tail.as_mut().map(|node| &mut node.as_mut().element) - } - } - - /// Adds an element first in the list. - /// - /// This operation should compute in O(1) time. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut dl = LinkedList::new(); - /// - /// dl.push_front(2); - /// assert_eq!(dl.front().unwrap(), &2); - /// - /// dl.push_front(1); - /// assert_eq!(dl.front().unwrap(), &1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn push_front(&mut self, elt: T) { - self.push_front_node(box Node::new(elt)); - } - - /// Removes the first element and returns it, or `None` if the list is - /// empty. - /// - /// This operation should compute in O(1) time. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// assert_eq!(d.pop_front(), None); - /// - /// d.push_front(1); - /// d.push_front(3); - /// assert_eq!(d.pop_front(), Some(3)); - /// assert_eq!(d.pop_front(), Some(1)); - /// assert_eq!(d.pop_front(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop_front(&mut self) -> Option { - self.pop_front_node().map(Node::into_element) - } - - /// Appends an element to the back of a list - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// d.push_back(1); - /// d.push_back(3); - /// assert_eq!(3, *d.back().unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn push_back(&mut self, elt: T) { - self.push_back_node(box Node::new(elt)); - } - - /// Removes the last element from a list and returns it, or `None` if - /// it is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// assert_eq!(d.pop_back(), None); - /// d.push_back(1); - /// d.push_back(3); - /// assert_eq!(d.pop_back(), Some(3)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop_back(&mut self) -> Option { - self.pop_back_node().map(Node::into_element) - } - - /// Splits the list into two at the given index. Returns everything after the given index, - /// including the index. - /// - /// This operation should compute in O(n) time. - /// - /// # Panics - /// - /// Panics if `at > len`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::LinkedList; - /// - /// let mut d = LinkedList::new(); - /// - /// d.push_front(1); - /// d.push_front(2); - /// d.push_front(3); - /// - /// let mut splitted = d.split_off(2); - /// - /// assert_eq!(splitted.pop_front(), Some(1)); - /// assert_eq!(splitted.pop_front(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn split_off(&mut self, at: usize) -> LinkedList { - let len = self.len(); - assert!(at <= len, "Cannot split off at a nonexistent index"); - if at == 0 { - return mem::replace(self, Self::new()); - } else if at == len { - return Self::new(); - } - - // Below, we iterate towards the `i-1`th node, either from the start or the end, - // depending on which would be faster. - let split_node = if at - 1 <= len - 1 - (at - 1) { - let mut iter = self.iter_mut(); - // instead of skipping using .skip() (which creates a new struct), - // we skip manually so we can access the head field without - // depending on implementation details of Skip - for _ in 0..at - 1 { - iter.next(); - } - iter.head - } else { - // better off starting from the end - let mut iter = self.iter_mut(); - for _ in 0..len - 1 - (at - 1) { - iter.next_back(); - } - iter.tail - }; - - // The split node is the new tail node of the first part and owns - // the head of the second part. - let second_part_head; - - unsafe { - second_part_head = split_node.unwrap().as_mut().next.take(); - if let Some(mut head) = second_part_head { - head.as_mut().prev = None; - } - } - - let second_part = LinkedList { - head: second_part_head, - tail: self.tail, - len: len - at, - marker: PhantomData, - }; - - // Fix the tail ptr of the first part - self.tail = split_node; - self.len = at; - - second_part - } - - /// Creates an iterator which uses a closure to determine if an element should be removed. - /// - /// If the closure returns true, then the element is removed and yielded. - /// If the closure returns false, the element will remain in the list and will not be yielded - /// by the iterator. - /// - /// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of - /// whether you choose to keep or remove it. - /// - /// # Examples - /// - /// Splitting a list into evens and odds, reusing the original list: - /// - /// ``` - /// #![feature(drain_filter)] - /// use std::collections::LinkedList; - /// - /// let mut numbers: LinkedList = LinkedList::new(); - /// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); - /// - /// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::>(); - /// let odds = numbers; - /// - /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); - /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); - /// ``` - #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter(&mut self, filter: F) -> DrainFilter - where F: FnMut(&mut T) -> bool - { - // avoid borrow issues. - let it = self.head; - let old_len = self.len; - - DrainFilter { - list: self, - it: it, - pred: filter, - idx: 0, - old_len: old_len, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T> Drop for LinkedList { - fn drop(&mut self) { - while let Some(_) = self.pop_front_node() {} - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - if self.len == 0 { - None - } else { - self.head.map(|node| unsafe { - // Need an unbound lifetime to get 'a - let node = &*node.as_ptr(); - self.len -= 1; - self.head = node.next; - &node.element - }) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Iter<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a T> { - if self.len == 0 { - None - } else { - self.tail.map(|node| unsafe { - // Need an unbound lifetime to get 'a - let node = &*node.as_ptr(); - self.len -= 1; - self.tail = node.prev; - &node.element - }) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for IterMut<'a, T> { - type Item = &'a mut T; - - #[inline] - fn next(&mut self) -> Option<&'a mut T> { - if self.len == 0 { - None - } else { - self.head.map(|node| unsafe { - // Need an unbound lifetime to get 'a - let node = &mut *node.as_ptr(); - self.len -= 1; - self.head = node.next; - &mut node.element - }) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut T> { - if self.len == 0 { - None - } else { - self.tail.map(|node| unsafe { - // Need an unbound lifetime to get 'a - let node = &mut *node.as_ptr(); - self.len -= 1; - self.tail = node.prev; - &mut node.element - }) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for IterMut<'a, T> {} - -impl<'a, T> IterMut<'a, T> { - /// Inserts the given element just after the element most recently returned by `.next()`. - /// The inserted element does not appear in the iteration. - /// - /// # Examples - /// - /// ``` - /// #![feature(linked_list_extras)] - /// - /// use std::collections::LinkedList; - /// - /// let mut list: LinkedList<_> = vec![1, 3, 4].into_iter().collect(); - /// - /// { - /// let mut it = list.iter_mut(); - /// assert_eq!(it.next().unwrap(), &1); - /// // insert `2` after `1` - /// it.insert_next(2); - /// } - /// { - /// let vec: Vec<_> = list.into_iter().collect(); - /// assert_eq!(vec, [1, 2, 3, 4]); - /// } - /// ``` - #[inline] - #[unstable(feature = "linked_list_extras", - reason = "this is probably better handled by a cursor type -- we'll see", - issue = "27794")] - pub fn insert_next(&mut self, element: T) { - match self.head { - None => self.list.push_back(element), - Some(mut head) => unsafe { - let mut prev = match head.as_ref().prev { - None => return self.list.push_front(element), - Some(prev) => prev, - }; - - let node = Some(Box::into_raw_non_null(box Node { - next: Some(head), - prev: Some(prev), - element, - })); - - prev.as_mut().next = node; - head.as_mut().prev = node; - - self.list.len += 1; - }, - } - } - - /// Provides a reference to the next element, without changing the iterator. - /// - /// # Examples - /// - /// ``` - /// #![feature(linked_list_extras)] - /// - /// use std::collections::LinkedList; - /// - /// let mut list: LinkedList<_> = vec![1, 2, 3].into_iter().collect(); - /// - /// let mut it = list.iter_mut(); - /// assert_eq!(it.next().unwrap(), &1); - /// assert_eq!(it.peek_next().unwrap(), &2); - /// // We just peeked at 2, so it was not consumed from the iterator. - /// assert_eq!(it.next().unwrap(), &2); - /// ``` - #[inline] - #[unstable(feature = "linked_list_extras", - reason = "this is probably better handled by a cursor type -- we'll see", - issue = "27794")] - pub fn peek_next(&mut self) -> Option<&mut T> { - if self.len == 0 { - None - } else { - unsafe { - self.head.as_mut().map(|node| &mut node.as_mut().element) - } - } - } -} - -/// An iterator produced by calling `drain_filter` on LinkedList. -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -pub struct DrainFilter<'a, T: 'a, F: 'a> - where F: FnMut(&mut T) -> bool, -{ - list: &'a mut LinkedList, - it: Option>>, - pred: F, - idx: usize, - old_len: usize, -} - -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T, F> Iterator for DrainFilter<'a, T, F> - where F: FnMut(&mut T) -> bool, -{ - type Item = T; - - fn next(&mut self) -> Option { - while let Some(mut node) = self.it { - unsafe { - self.it = node.as_ref().next; - self.idx += 1; - - if (self.pred)(&mut node.as_mut().element) { - self.list.unlink_node(node); - return Some(Box::from_raw(node.as_ptr()).element); - } - } - } - - None - } - - fn size_hint(&self) -> (usize, Option) { - (0, Some(self.old_len - self.idx)) - } -} - -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T, F> Drop for DrainFilter<'a, T, F> - where F: FnMut(&mut T) -> bool, -{ - fn drop(&mut self) { - self.for_each(drop); - } -} - -#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T: 'a + fmt::Debug, F> fmt::Debug for DrainFilter<'a, T, F> - where F: FnMut(&mut T) -> bool -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("DrainFilter") - .field(&self.list) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.list.pop_front() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.list.len, Some(self.list.len)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - self.list.pop_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromIterator for LinkedList { - fn from_iter>(iter: I) -> Self { - let mut list = Self::new(); - list.extend(iter); - list - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for LinkedList { - type Item = T; - type IntoIter = IntoIter; - - /// Consumes the list into an iterator yielding elements by value. - #[inline] - fn into_iter(self) -> IntoIter { - IntoIter { list: self } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a LinkedList { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut LinkedList { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Extend for LinkedList { - fn extend>(&mut self, iter: I) { - >::spec_extend(self, iter); - } -} - -impl SpecExtend for LinkedList { - default fn spec_extend(&mut self, iter: I) { - for elt in iter { - self.push_back(elt); - } - } -} - -impl SpecExtend> for LinkedList { - fn spec_extend(&mut self, ref mut other: LinkedList) { - self.append(other); - } -} - -#[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for LinkedList { - fn eq(&self, other: &Self) -> bool { - self.len() == other.len() && self.iter().eq(other) - } - - fn ne(&self, other: &Self) -> bool { - self.len() != other.len() || self.iter().ne(other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for LinkedList {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for LinkedList { - fn partial_cmp(&self, other: &Self) -> Option { - self.iter().partial_cmp(other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for LinkedList { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.iter().cmp(other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for LinkedList { - fn clone(&self) -> Self { - self.iter().cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LinkedList { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for LinkedList { - fn hash(&self, state: &mut H) { - self.len().hash(state); - for elt in self { - elt.hash(state); - } - } -} - -// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters. -#[allow(dead_code)] -fn assert_covariance() { - fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { - x - } - fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { - x - } - fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { - x - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for LinkedList {} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for LinkedList {} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} - -#[cfg(test)] -mod tests { - use std::thread; - use std::vec::Vec; - - use rand::{thread_rng, Rng}; - - use super::{LinkedList, Node}; - - #[cfg(test)] - fn list_from(v: &[T]) -> LinkedList { - v.iter().cloned().collect() - } - - pub fn check_links(list: &LinkedList) { - unsafe { - let mut len = 0; - let mut last_ptr: Option<&Node> = None; - let mut node_ptr: &Node; - match list.head { - None => { - // tail node should also be None. - assert!(list.tail.is_none()); - assert_eq!(0, list.len); - return; - } - Some(node) => node_ptr = &*node.as_ptr(), - } - loop { - match (last_ptr, node_ptr.prev) { - (None, None) => {} - (None, _) => panic!("prev link for head"), - (Some(p), Some(pptr)) => { - assert_eq!(p as *const Node, pptr.as_ptr() as *const Node); - } - _ => panic!("prev link is none, not good"), - } - match node_ptr.next { - Some(next) => { - last_ptr = Some(node_ptr); - node_ptr = &*next.as_ptr(); - len += 1; - } - None => { - len += 1; - break; - } - } - } - - // verify that the tail node points to the last node. - let tail = list.tail.as_ref().expect("some tail node").as_ref(); - assert_eq!(tail as *const Node, node_ptr as *const Node); - // check that len matches interior links. - assert_eq!(len, list.len); - } - } - - #[test] - fn test_append() { - // Empty to empty - { - let mut m = LinkedList::::new(); - let mut n = LinkedList::new(); - m.append(&mut n); - check_links(&m); - assert_eq!(m.len(), 0); - assert_eq!(n.len(), 0); - } - // Non-empty to empty - { - let mut m = LinkedList::new(); - let mut n = LinkedList::new(); - n.push_back(2); - m.append(&mut n); - check_links(&m); - assert_eq!(m.len(), 1); - assert_eq!(m.pop_back(), Some(2)); - assert_eq!(n.len(), 0); - check_links(&m); - } - // Empty to non-empty - { - let mut m = LinkedList::new(); - let mut n = LinkedList::new(); - m.push_back(2); - m.append(&mut n); - check_links(&m); - assert_eq!(m.len(), 1); - assert_eq!(m.pop_back(), Some(2)); - check_links(&m); - } - - // Non-empty to non-empty - let v = vec![1, 2, 3, 4, 5]; - let u = vec![9, 8, 1, 2, 3, 4, 5]; - let mut m = list_from(&v); - let mut n = list_from(&u); - m.append(&mut n); - check_links(&m); - let mut sum = v; - sum.extend_from_slice(&u); - assert_eq!(sum.len(), m.len()); - for elt in sum { - assert_eq!(m.pop_front(), Some(elt)) - } - assert_eq!(n.len(), 0); - // let's make sure it's working properly, since we - // did some direct changes to private members - n.push_back(3); - assert_eq!(n.len(), 1); - assert_eq!(n.pop_front(), Some(3)); - check_links(&n); - } - - #[test] - fn test_insert_prev() { - let mut m = list_from(&[0, 2, 4, 6, 8]); - let len = m.len(); - { - let mut it = m.iter_mut(); - it.insert_next(-2); - loop { - match it.next() { - None => break, - Some(elt) => { - it.insert_next(*elt + 1); - match it.peek_next() { - Some(x) => assert_eq!(*x, *elt + 2), - None => assert_eq!(8, *elt), - } - } - } - } - it.insert_next(0); - it.insert_next(1); - } - check_links(&m); - assert_eq!(m.len(), 3 + len * 2); - assert_eq!(m.into_iter().collect::>(), - [-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_send() { - let n = list_from(&[1, 2, 3]); - thread::spawn(move || { - check_links(&n); - let a: &[_] = &[&1, &2, &3]; - assert_eq!(a, &*n.iter().collect::>()); - }) - .join() - .ok() - .unwrap(); - } - - #[test] - fn test_fuzz() { - for _ in 0..25 { - fuzz_test(3); - fuzz_test(16); - fuzz_test(189); - } - } - - #[test] - fn test_26021() { - // There was a bug in split_off that failed to null out the RHS's head's prev ptr. - // This caused the RHS's dtor to walk up into the LHS at drop and delete all of - // its nodes. - // - // https://github.com/rust-lang/rust/issues/26021 - let mut v1 = LinkedList::new(); - v1.push_front(1); - v1.push_front(1); - v1.push_front(1); - v1.push_front(1); - let _ = v1.split_off(3); // Dropping this now should not cause laundry consumption - assert_eq!(v1.len(), 3); - - assert_eq!(v1.iter().len(), 3); - assert_eq!(v1.iter().collect::>().len(), 3); - } - - #[test] - fn test_split_off() { - let mut v1 = LinkedList::new(); - v1.push_front(1); - v1.push_front(1); - v1.push_front(1); - v1.push_front(1); - - // test all splits - for ix in 0..1 + v1.len() { - let mut a = v1.clone(); - let b = a.split_off(ix); - check_links(&a); - check_links(&b); - a.extend(b); - assert_eq!(v1, a); - } - } - - #[cfg(test)] - fn fuzz_test(sz: i32) { - let mut m: LinkedList<_> = LinkedList::new(); - let mut v = vec![]; - for i in 0..sz { - check_links(&m); - let r: u8 = thread_rng().next_u32() as u8; - match r % 6 { - 0 => { - m.pop_back(); - v.pop(); - } - 1 => { - if !v.is_empty() { - m.pop_front(); - v.remove(0); - } - } - 2 | 4 => { - m.push_front(-i); - v.insert(0, -i); - } - 3 | 5 | _ => { - m.push_back(i); - v.push(i); - } - } - } - - check_links(&m); - - let mut i = 0; - for (a, &b) in m.into_iter().zip(&v) { - i += 1; - assert_eq!(a, b); - } - assert_eq!(i, v.len()); - } - - #[test] - fn drain_filter_test() { - let mut m: LinkedList = LinkedList::new(); - m.extend(&[1, 2, 3, 4, 5, 6]); - let deleted = m.drain_filter(|v| *v < 4).collect::>(); - - check_links(&m); - - assert_eq!(deleted, &[1, 2, 3]); - assert_eq!(m.into_iter().collect::>(), &[4, 5, 6]); - } - - #[test] - fn drain_to_empty_test() { - let mut m: LinkedList = LinkedList::new(); - m.extend(&[1, 2, 3, 4, 5, 6]); - let deleted = m.drain_filter(|_| true).collect::>(); - - check_links(&m); - - assert_eq!(deleted, &[1, 2, 3, 4, 5, 6]); - assert_eq!(m.into_iter().collect::>(), &[]); - } -} diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index ec9c39c916c..bb99d0401d3 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -51,7 +51,6 @@ use boxed::Box; use slice::{SliceConcatExt, SliceIndex}; use string::String; use vec::Vec; -use vec_deque::VecDeque; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{FromStr, Utf8Error}; diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs deleted file mode 100644 index e917a65c9c5..00000000000 --- a/src/liballoc/vec_deque.rs +++ /dev/null @@ -1,2970 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A double-ended queue implemented with a growable ring buffer. -//! -//! This queue has `O(1)` amortized inserts and removals from both ends of the -//! container. It also has `O(1)` indexing like a vector. The contained elements -//! are not required to be copyable, and the queue will be sendable if the -//! contained type is sendable. - -#![stable(feature = "rust1", since = "1.0.0")] - -use core::cmp::Ordering; -use core::fmt; -use core::iter::{repeat, FromIterator, FusedIterator}; -use core::mem; -use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, RangeBounds}; -use core::ptr; -use core::ptr::NonNull; -use core::slice; - -use core::hash::{Hash, Hasher}; -use core::cmp; - -use alloc::CollectionAllocErr; -use raw_vec::RawVec; -use vec::Vec; - -const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 -const MINIMUM_CAPACITY: usize = 1; // 2 - 1 -#[cfg(target_pointer_width = "32")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (32 - 1); // Largest possible power of two -#[cfg(target_pointer_width = "64")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of two - -/// A double-ended queue implemented with a growable ring buffer. -/// -/// The "default" usage of this type as a queue is to use [`push_back`] to add to -/// the queue, and [`pop_front`] to remove from the queue. [`extend`] and [`append`] -/// push onto the back in this manner, and iterating over `VecDeque` goes front -/// to back. -/// -/// [`push_back`]: #method.push_back -/// [`pop_front`]: #method.pop_front -/// [`extend`]: #method.extend -/// [`append`]: #method.append -#[stable(feature = "rust1", since = "1.0.0")] -pub struct VecDeque { - // tail and head are pointers into the buffer. Tail always points - // to the first element that could be read, Head always points - // to where data should be written. - // If tail == head the buffer is empty. The length of the ringbuffer - // is defined as the distance between the two. - tail: usize, - head: usize, - buf: RawVec, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for VecDeque { - fn clone(&self) -> VecDeque { - self.iter().cloned().collect() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T> Drop for VecDeque { - fn drop(&mut self) { - let (front, back) = self.as_mut_slices(); - unsafe { - // use drop for [T] - ptr::drop_in_place(front); - ptr::drop_in_place(back); - } - // RawVec handles deallocation - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for VecDeque { - /// Creates an empty `VecDeque`. - #[inline] - fn default() -> VecDeque { - VecDeque::new() - } -} - -impl VecDeque { - /// Marginally more convenient - #[inline] - fn ptr(&self) -> *mut T { - self.buf.ptr() - } - - /// Marginally more convenient - #[inline] - fn cap(&self) -> usize { - if mem::size_of::() == 0 { - // For zero sized types, we are always at maximum capacity - MAXIMUM_ZST_CAPACITY - } else { - self.buf.cap() - } - } - - /// Turn ptr into a slice - #[inline] - unsafe fn buffer_as_slice(&self) -> &[T] { - slice::from_raw_parts(self.ptr(), self.cap()) - } - - /// Turn ptr into a mut slice - #[inline] - unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] { - slice::from_raw_parts_mut(self.ptr(), self.cap()) - } - - /// Moves an element out of the buffer - #[inline] - unsafe fn buffer_read(&mut self, off: usize) -> T { - ptr::read(self.ptr().offset(off as isize)) - } - - /// Writes an element into the buffer, moving it. - #[inline] - unsafe fn buffer_write(&mut self, off: usize, value: T) { - ptr::write(self.ptr().offset(off as isize), value); - } - - /// Returns `true` if and only if the buffer is at full capacity. - #[inline] - fn is_full(&self) -> bool { - self.cap() - self.len() == 1 - } - - /// Returns the index in the underlying buffer for a given logical element - /// index. - #[inline] - fn wrap_index(&self, idx: usize) -> usize { - wrap_index(idx, self.cap()) - } - - /// Returns the index in the underlying buffer for a given logical element - /// index + addend. - #[inline] - fn wrap_add(&self, idx: usize, addend: usize) -> usize { - wrap_index(idx.wrapping_add(addend), self.cap()) - } - - /// Returns the index in the underlying buffer for a given logical element - /// index - subtrahend. - #[inline] - fn wrap_sub(&self, idx: usize, subtrahend: usize) -> usize { - wrap_index(idx.wrapping_sub(subtrahend), self.cap()) - } - - /// Copies a contiguous block of memory len long from src to dst - #[inline] - unsafe fn copy(&self, dst: usize, src: usize, len: usize) { - debug_assert!(dst + len <= self.cap(), - "cpy dst={} src={} len={} cap={}", - dst, - src, - len, - self.cap()); - debug_assert!(src + len <= self.cap(), - "cpy dst={} src={} len={} cap={}", - dst, - src, - len, - self.cap()); - ptr::copy(self.ptr().offset(src as isize), - self.ptr().offset(dst as isize), - len); - } - - /// Copies a contiguous block of memory len long from src to dst - #[inline] - unsafe fn copy_nonoverlapping(&self, dst: usize, src: usize, len: usize) { - debug_assert!(dst + len <= self.cap(), - "cno dst={} src={} len={} cap={}", - dst, - src, - len, - self.cap()); - debug_assert!(src + len <= self.cap(), - "cno dst={} src={} len={} cap={}", - dst, - src, - len, - self.cap()); - ptr::copy_nonoverlapping(self.ptr().offset(src as isize), - self.ptr().offset(dst as isize), - len); - } - - /// Copies a potentially wrapping block of memory len long from src to dest. - /// (abs(dst - src) + len) must be no larger than cap() (There must be at - /// most one continuous overlapping region between src and dest). - unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) { - #[allow(dead_code)] - fn diff(a: usize, b: usize) -> usize { - if a <= b { b - a } else { a - b } - } - debug_assert!(cmp::min(diff(dst, src), self.cap() - diff(dst, src)) + len <= self.cap(), - "wrc dst={} src={} len={} cap={}", - dst, - src, - len, - self.cap()); - - if src == dst || len == 0 { - return; - } - - let dst_after_src = self.wrap_sub(dst, src) < len; - - let src_pre_wrap_len = self.cap() - src; - let dst_pre_wrap_len = self.cap() - dst; - let src_wraps = src_pre_wrap_len < len; - let dst_wraps = dst_pre_wrap_len < len; - - match (dst_after_src, src_wraps, dst_wraps) { - (_, false, false) => { - // src doesn't wrap, dst doesn't wrap - // - // S . . . - // 1 [_ _ A A B B C C _] - // 2 [_ _ A A A A B B _] - // D . . . - // - self.copy(dst, src, len); - } - (false, false, true) => { - // dst before src, src doesn't wrap, dst wraps - // - // S . . . - // 1 [A A B B _ _ _ C C] - // 2 [A A B B _ _ _ A A] - // 3 [B B B B _ _ _ A A] - // . . D . - // - self.copy(dst, src, dst_pre_wrap_len); - self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); - } - (true, false, true) => { - // src before dst, src doesn't wrap, dst wraps - // - // S . . . - // 1 [C C _ _ _ A A B B] - // 2 [B B _ _ _ A A B B] - // 3 [B B _ _ _ A A A A] - // . . D . - // - self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); - self.copy(dst, src, dst_pre_wrap_len); - } - (false, true, false) => { - // dst before src, src wraps, dst doesn't wrap - // - // . . S . - // 1 [C C _ _ _ A A B B] - // 2 [C C _ _ _ B B B B] - // 3 [C C _ _ _ B B C C] - // D . . . - // - self.copy(dst, src, src_pre_wrap_len); - self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); - } - (true, true, false) => { - // src before dst, src wraps, dst doesn't wrap - // - // . . S . - // 1 [A A B B _ _ _ C C] - // 2 [A A A A _ _ _ C C] - // 3 [C C A A _ _ _ C C] - // D . . . - // - self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); - self.copy(dst, src, src_pre_wrap_len); - } - (false, true, true) => { - // dst before src, src wraps, dst wraps - // - // . . . S . - // 1 [A B C D _ E F G H] - // 2 [A B C D _ E G H H] - // 3 [A B C D _ E G H A] - // 4 [B C C D _ E G H A] - // . . D . . - // - debug_assert!(dst_pre_wrap_len > src_pre_wrap_len); - let delta = dst_pre_wrap_len - src_pre_wrap_len; - self.copy(dst, src, src_pre_wrap_len); - self.copy(dst + src_pre_wrap_len, 0, delta); - self.copy(0, delta, len - dst_pre_wrap_len); - } - (true, true, true) => { - // src before dst, src wraps, dst wraps - // - // . . S . . - // 1 [A B C D _ E F G H] - // 2 [A A B D _ E F G H] - // 3 [H A B D _ E F G H] - // 4 [H A B D _ E F F G] - // . . . D . - // - debug_assert!(src_pre_wrap_len > dst_pre_wrap_len); - let delta = src_pre_wrap_len - dst_pre_wrap_len; - self.copy(delta, 0, len - src_pre_wrap_len); - self.copy(0, self.cap() - delta, delta); - self.copy(dst, src, dst_pre_wrap_len); - } - } - } - - /// Frobs the head and tail sections around to handle the fact that we - /// just reallocated. Unsafe because it trusts old_cap. - #[inline] - unsafe fn handle_cap_increase(&mut self, old_cap: usize) { - let new_cap = self.cap(); - - // Move the shortest contiguous section of the ring buffer - // T H - // [o o o o o o o . ] - // T H - // A [o o o o o o o . . . . . . . . . ] - // H T - // [o o . o o o o o ] - // T H - // B [. . . o o o o o o o . . . . . . ] - // H T - // [o o o o o . o o ] - // H T - // C [o o o o o . . . . . . . . . o o ] - - if self.tail <= self.head { - // A - // Nop - } else if self.head < old_cap - self.tail { - // B - self.copy_nonoverlapping(old_cap, 0, self.head); - self.head += old_cap; - debug_assert!(self.head > self.tail); - } else { - // C - let new_tail = new_cap - (old_cap - self.tail); - self.copy_nonoverlapping(new_tail, self.tail, old_cap - self.tail); - self.tail = new_tail; - debug_assert!(self.head < self.tail); - } - debug_assert!(self.head < self.cap()); - debug_assert!(self.tail < self.cap()); - debug_assert!(self.cap().count_ones() == 1); - } -} - -impl VecDeque { - /// Creates an empty `VecDeque`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let vector: VecDeque = VecDeque::new(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> VecDeque { - VecDeque::with_capacity(INITIAL_CAPACITY) - } - - /// Creates an empty `VecDeque` with space for at least `n` elements. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let vector: VecDeque = VecDeque::with_capacity(10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(n: usize) -> VecDeque { - // +1 since the ringbuffer always leaves one space empty - let cap = cmp::max(n + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); - assert!(cap > n, "capacity overflow"); - - VecDeque { - tail: 0, - head: 0, - buf: RawVec::with_capacity(cap), - } - } - - /// Retrieves an element in the `VecDeque` by index. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(3); - /// buf.push_back(4); - /// buf.push_back(5); - /// assert_eq!(buf.get(1), Some(&4)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self, index: usize) -> Option<&T> { - if index < self.len() { - let idx = self.wrap_add(self.tail, index); - unsafe { Some(&*self.ptr().offset(idx as isize)) } - } else { - None - } - } - - /// Retrieves an element in the `VecDeque` mutably by index. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(3); - /// buf.push_back(4); - /// buf.push_back(5); - /// if let Some(elem) = buf.get_mut(1) { - /// *elem = 7; - /// } - /// - /// assert_eq!(buf[1], 7); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if index < self.len() { - let idx = self.wrap_add(self.tail, index); - unsafe { Some(&mut *self.ptr().offset(idx as isize)) } - } else { - None - } - } - - /// Swaps elements at indices `i` and `j`. - /// - /// `i` and `j` may be equal. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Panics - /// - /// Panics if either index is out of bounds. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(3); - /// buf.push_back(4); - /// buf.push_back(5); - /// assert_eq!(buf, [3, 4, 5]); - /// buf.swap(0, 2); - /// assert_eq!(buf, [5, 4, 3]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn swap(&mut self, i: usize, j: usize) { - assert!(i < self.len()); - assert!(j < self.len()); - let ri = self.wrap_add(self.tail, i); - let rj = self.wrap_add(self.tail, j); - unsafe { - ptr::swap(self.ptr().offset(ri as isize), - self.ptr().offset(rj as isize)) - } - } - - /// Returns the number of elements the `VecDeque` can hold without - /// reallocating. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let buf: VecDeque = VecDeque::with_capacity(10); - /// assert!(buf.capacity() >= 10); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { - self.cap() - 1 - } - - /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the - /// given `VecDeque`. Does nothing if the capacity is already sufficient. - /// - /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future - /// insertions are expected. - /// - /// # Panics - /// - /// Panics if the new capacity overflows `usize`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf: VecDeque = vec![1].into_iter().collect(); - /// buf.reserve_exact(10); - /// assert!(buf.capacity() >= 11); - /// ``` - /// - /// [`reserve`]: #method.reserve - #[stable(feature = "rust1", since = "1.0.0")] - pub fn reserve_exact(&mut self, additional: usize) { - self.reserve(additional); - } - - /// Reserves capacity for at least `additional` more elements to be inserted in the given - /// `VecDeque`. The collection may reserve more space to avoid frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new capacity overflows `usize`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf: VecDeque = vec![1].into_iter().collect(); - /// buf.reserve(10); - /// assert!(buf.capacity() >= 11); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn reserve(&mut self, additional: usize) { - let old_cap = self.cap(); - let used_cap = self.len() + 1; - let new_cap = used_cap.checked_add(additional) - .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) - .expect("capacity overflow"); - - if new_cap > old_cap { - self.buf.reserve_exact(used_cap, new_cap - used_cap); - unsafe { - self.handle_cap_increase(old_cap); - } - } - } - - /// Tries to reserves the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `VecDeque`. After calling `reserve_exact`, - /// capacity will be greater than or equal to `self.len() + additional`. - /// Does nothing if the capacity is already sufficient. - /// - /// Note that the allocator may give the collection more space than it - /// requests. Therefore capacity can not be relied upon to be precisely - /// minimal. Prefer `reserve` if future insertions are expected. - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - /// - /// # Examples - /// - /// ``` - /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; - /// use std::collections::VecDeque; - /// - /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { - /// let mut output = VecDeque::new(); - /// - /// // Pre-reserve the memory, exiting if we can't - /// output.try_reserve_exact(data.len())?; - /// - /// // Now we know this can't OOM in the middle of our complex work - /// output.extend(data.iter().map(|&val| { - /// val * 2 + 5 // very complicated - /// })); - /// - /// Ok(output) - /// } - /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); - /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { - self.try_reserve(additional) - } - - /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `VecDeque`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be - /// greater than or equal to `self.len() + additional`. Does nothing if - /// capacity is already sufficient. - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - /// - /// # Examples - /// - /// ``` - /// #![feature(try_reserve)] - /// use std::collections::CollectionAllocErr; - /// use std::collections::VecDeque; - /// - /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { - /// let mut output = VecDeque::new(); - /// - /// // Pre-reserve the memory, exiting if we can't - /// output.try_reserve(data.len())?; - /// - /// // Now we know this can't OOM in the middle of our complex work - /// output.extend(data.iter().map(|&val| { - /// val * 2 + 5 // very complicated - /// })); - /// - /// Ok(output) - /// } - /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); - /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { - let old_cap = self.cap(); - let used_cap = self.len() + 1; - let new_cap = used_cap.checked_add(additional) - .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) - .ok_or(CollectionAllocErr::CapacityOverflow)?; - - if new_cap > old_cap { - self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?; - unsafe { - self.handle_cap_increase(old_cap); - } - } - Ok(()) - } - - /// Shrinks the capacity of the `VecDeque` as much as possible. - /// - /// It will drop down as close as possible to the length but the allocator may still inform the - /// `VecDeque` that there is space for a few more elements. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::with_capacity(15); - /// buf.extend(0..4); - /// assert_eq!(buf.capacity(), 15); - /// buf.shrink_to_fit(); - /// assert!(buf.capacity() >= 4); - /// ``` - #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn shrink_to_fit(&mut self) { - self.shrink_to(0); - } - - /// Shrinks the capacity of the `VecDeque` with a lower bound. - /// - /// The capacity will remain at least as large as both the length - /// and the supplied value. - /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. - /// - /// # Examples - /// - /// ``` - /// #![feature(shrink_to)] - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::with_capacity(15); - /// buf.extend(0..4); - /// assert_eq!(buf.capacity(), 15); - /// buf.shrink_to(6); - /// assert!(buf.capacity() >= 6); - /// buf.shrink_to(0); - /// assert!(buf.capacity() >= 4); - /// ``` - #[unstable(feature = "shrink_to", reason = "new API", issue="0")] - pub fn shrink_to(&mut self, min_capacity: usize) { - assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity"); - - // +1 since the ringbuffer always leaves one space empty - // len + 1 can't overflow for an existing, well-formed ringbuffer. - let target_cap = cmp::max( - cmp::max(min_capacity, self.len()) + 1, - MINIMUM_CAPACITY + 1 - ).next_power_of_two(); - - if target_cap < self.cap() { - // There are three cases of interest: - // All elements are out of desired bounds - // Elements are contiguous, and head is out of desired bounds - // Elements are discontiguous, and tail is out of desired bounds - // - // At all other times, element positions are unaffected. - // - // Indicates that elements at the head should be moved. - let head_outside = self.head == 0 || self.head >= target_cap; - // Move elements from out of desired bounds (positions after target_cap) - if self.tail >= target_cap && head_outside { - // T H - // [. . . . . . . . o o o o o o o . ] - // T H - // [o o o o o o o . ] - unsafe { - self.copy_nonoverlapping(0, self.tail, self.len()); - } - self.head = self.len(); - self.tail = 0; - } else if self.tail != 0 && self.tail < target_cap && head_outside { - // T H - // [. . . o o o o o o o . . . . . . ] - // H T - // [o o . o o o o o ] - let len = self.wrap_sub(self.head, target_cap); - unsafe { - self.copy_nonoverlapping(0, target_cap, len); - } - self.head = len; - debug_assert!(self.head < self.tail); - } else if self.tail >= target_cap { - // H T - // [o o o o o . . . . . . . . . o o ] - // H T - // [o o o o o . o o ] - debug_assert!(self.wrap_sub(self.head, 1) < target_cap); - let len = self.cap() - self.tail; - let new_tail = target_cap - len; - unsafe { - self.copy_nonoverlapping(new_tail, self.tail, len); - } - self.tail = new_tail; - debug_assert!(self.head < self.tail); - } - - self.buf.shrink_to_fit(target_cap); - - debug_assert!(self.head < self.cap()); - debug_assert!(self.tail < self.cap()); - debug_assert!(self.cap().count_ones() == 1); - } - } - - /// Shortens the `VecDeque`, dropping excess elements from the back. - /// - /// If `len` is greater than the `VecDeque`'s current length, this has no - /// effect. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(5); - /// buf.push_back(10); - /// buf.push_back(15); - /// assert_eq!(buf, [5, 10, 15]); - /// buf.truncate(1); - /// assert_eq!(buf, [5]); - /// ``` - #[stable(feature = "deque_extras", since = "1.16.0")] - pub fn truncate(&mut self, len: usize) { - for _ in len..self.len() { - self.pop_back(); - } - } - - /// Returns a front-to-back iterator. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(5); - /// buf.push_back(3); - /// buf.push_back(4); - /// let b: &[_] = &[&5, &3, &4]; - /// let c: Vec<&i32> = buf.iter().collect(); - /// assert_eq!(&c[..], b); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { - Iter { - tail: self.tail, - head: self.head, - ring: unsafe { self.buffer_as_slice() }, - } - } - - /// Returns a front-to-back iterator that returns mutable references. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(5); - /// buf.push_back(3); - /// buf.push_back(4); - /// for num in buf.iter_mut() { - /// *num = *num - 2; - /// } - /// let b: &[_] = &[&mut 3, &mut 1, &mut 2]; - /// assert_eq!(&buf.iter_mut().collect::>()[..], b); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { - IterMut { - tail: self.tail, - head: self.head, - ring: unsafe { self.buffer_as_mut_slice() }, - } - } - - /// Returns a pair of slices which contain, in order, the contents of the - /// `VecDeque`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut vector = VecDeque::new(); - /// - /// vector.push_back(0); - /// vector.push_back(1); - /// vector.push_back(2); - /// - /// assert_eq!(vector.as_slices(), (&[0, 1, 2][..], &[][..])); - /// - /// vector.push_front(10); - /// vector.push_front(9); - /// - /// assert_eq!(vector.as_slices(), (&[9, 10][..], &[0, 1, 2][..])); - /// ``` - #[inline] - #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn as_slices(&self) -> (&[T], &[T]) { - unsafe { - let buf = self.buffer_as_slice(); - RingSlices::ring_slices(buf, self.head, self.tail) - } - } - - /// Returns a pair of slices which contain, in order, the contents of the - /// `VecDeque`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut vector = VecDeque::new(); - /// - /// vector.push_back(0); - /// vector.push_back(1); - /// - /// vector.push_front(10); - /// vector.push_front(9); - /// - /// vector.as_mut_slices().0[0] = 42; - /// vector.as_mut_slices().1[0] = 24; - /// assert_eq!(vector.as_slices(), (&[42, 10][..], &[24, 1][..])); - /// ``` - #[inline] - #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { - unsafe { - let head = self.head; - let tail = self.tail; - let buf = self.buffer_as_mut_slice(); - RingSlices::ring_slices(buf, head, tail) - } - } - - /// Returns the number of elements in the `VecDeque`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut v = VecDeque::new(); - /// assert_eq!(v.len(), 0); - /// v.push_back(1); - /// assert_eq!(v.len(), 1); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { - count(self.tail, self.head, self.cap()) - } - - /// Returns `true` if the `VecDeque` is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut v = VecDeque::new(); - /// assert!(v.is_empty()); - /// v.push_front(1); - /// assert!(!v.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - self.tail == self.head - } - - /// Create a draining iterator that removes the specified range in the - /// `VecDeque` and yields the removed items. - /// - /// Note 1: The element range is removed even if the iterator is not - /// consumed until the end. - /// - /// Note 2: It is unspecified how many elements are removed from the deque, - /// if the `Drain` value is not dropped, but the borrow it holds expires - /// (eg. due to mem::forget). - /// - /// # Panics - /// - /// Panics if the starting point is greater than the end point or if - /// the end point is greater than the length of the vector. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); - /// let drained = v.drain(2..).collect::>(); - /// assert_eq!(drained, [3]); - /// assert_eq!(v, [1, 2]); - /// - /// // A full range clears all contents - /// v.drain(..); - /// assert!(v.is_empty()); - /// ``` - #[inline] - #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self, range: R) -> Drain - where R: RangeBounds - { - // Memory safety - // - // When the Drain is first created, the source deque is shortened to - // make sure no uninitialized or moved-from elements are accessible at - // all if the Drain's destructor never gets to run. - // - // Drain will ptr::read out the values to remove. - // When finished, the remaining data will be copied back to cover the hole, - // and the head/tail values will be restored correctly. - // - let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; - assert!(start <= end, "drain lower bound was too large"); - assert!(end <= len, "drain upper bound was too large"); - - // The deque's elements are parted into three segments: - // * self.tail -> drain_tail - // * drain_tail -> drain_head - // * drain_head -> self.head - // - // T = self.tail; H = self.head; t = drain_tail; h = drain_head - // - // We store drain_tail as self.head, and drain_head and self.head as - // after_tail and after_head respectively on the Drain. This also - // truncates the effective array such that if the Drain is leaked, we - // have forgotten about the potentially moved values after the start of - // the drain. - // - // T t h H - // [. . . o o x x o o . . .] - // - let drain_tail = self.wrap_add(self.tail, start); - let drain_head = self.wrap_add(self.tail, end); - let head = self.head; - - // "forget" about the values after the start of the drain until after - // the drain is complete and the Drain destructor is run. - self.head = drain_tail; - - Drain { - deque: NonNull::from(&mut *self), - after_tail: drain_head, - after_head: head, - iter: Iter { - tail: drain_tail, - head: drain_head, - ring: unsafe { self.buffer_as_mut_slice() }, - }, - } - } - - /// Clears the `VecDeque`, removing all values. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut v = VecDeque::new(); - /// v.push_back(1); - /// v.clear(); - /// assert!(v.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn clear(&mut self) { - self.drain(..); - } - - /// Returns `true` if the `VecDeque` contains an element equal to the - /// given value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut vector: VecDeque = VecDeque::new(); - /// - /// vector.push_back(0); - /// vector.push_back(1); - /// - /// assert_eq!(vector.contains(&1), true); - /// assert_eq!(vector.contains(&10), false); - /// ``` - #[stable(feature = "vec_deque_contains", since = "1.12.0")] - pub fn contains(&self, x: &T) -> bool - where T: PartialEq - { - let (a, b) = self.as_slices(); - a.contains(x) || b.contains(x) - } - - /// Provides a reference to the front element, or `None` if the `VecDeque` is - /// empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut d = VecDeque::new(); - /// assert_eq!(d.front(), None); - /// - /// d.push_back(1); - /// d.push_back(2); - /// assert_eq!(d.front(), Some(&1)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn front(&self) -> Option<&T> { - if !self.is_empty() { - Some(&self[0]) - } else { - None - } - } - - /// Provides a mutable reference to the front element, or `None` if the - /// `VecDeque` is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut d = VecDeque::new(); - /// assert_eq!(d.front_mut(), None); - /// - /// d.push_back(1); - /// d.push_back(2); - /// match d.front_mut() { - /// Some(x) => *x = 9, - /// None => (), - /// } - /// assert_eq!(d.front(), Some(&9)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn front_mut(&mut self) -> Option<&mut T> { - if !self.is_empty() { - Some(&mut self[0]) - } else { - None - } - } - - /// Provides a reference to the back element, or `None` if the `VecDeque` is - /// empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut d = VecDeque::new(); - /// assert_eq!(d.back(), None); - /// - /// d.push_back(1); - /// d.push_back(2); - /// assert_eq!(d.back(), Some(&2)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn back(&self) -> Option<&T> { - if !self.is_empty() { - Some(&self[self.len() - 1]) - } else { - None - } - } - - /// Provides a mutable reference to the back element, or `None` if the - /// `VecDeque` is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut d = VecDeque::new(); - /// assert_eq!(d.back(), None); - /// - /// d.push_back(1); - /// d.push_back(2); - /// match d.back_mut() { - /// Some(x) => *x = 9, - /// None => (), - /// } - /// assert_eq!(d.back(), Some(&9)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn back_mut(&mut self) -> Option<&mut T> { - let len = self.len(); - if !self.is_empty() { - Some(&mut self[len - 1]) - } else { - None - } - } - - /// Removes the first element and returns it, or `None` if the `VecDeque` is - /// empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut d = VecDeque::new(); - /// d.push_back(1); - /// d.push_back(2); - /// - /// assert_eq!(d.pop_front(), Some(1)); - /// assert_eq!(d.pop_front(), Some(2)); - /// assert_eq!(d.pop_front(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop_front(&mut self) -> Option { - if self.is_empty() { - None - } else { - let tail = self.tail; - self.tail = self.wrap_add(self.tail, 1); - unsafe { Some(self.buffer_read(tail)) } - } - } - - /// Prepends an element to the `VecDeque`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut d = VecDeque::new(); - /// d.push_front(1); - /// d.push_front(2); - /// assert_eq!(d.front(), Some(&2)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn push_front(&mut self, value: T) { - self.grow_if_necessary(); - - self.tail = self.wrap_sub(self.tail, 1); - let tail = self.tail; - unsafe { - self.buffer_write(tail, value); - } - } - - /// Appends an element to the back of the `VecDeque`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(1); - /// buf.push_back(3); - /// assert_eq!(3, *buf.back().unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn push_back(&mut self, value: T) { - self.grow_if_necessary(); - - let head = self.head; - self.head = self.wrap_add(self.head, 1); - unsafe { self.buffer_write(head, value) } - } - - /// Removes the last element from the `VecDeque` and returns it, or `None` if - /// it is empty. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.pop_back(), None); - /// buf.push_back(1); - /// buf.push_back(3); - /// assert_eq!(buf.pop_back(), Some(3)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn pop_back(&mut self) -> Option { - if self.is_empty() { - None - } else { - self.head = self.wrap_sub(self.head, 1); - let head = self.head; - unsafe { Some(self.buffer_read(head)) } - } - } - - #[inline] - fn is_contiguous(&self) -> bool { - self.tail <= self.head - } - - /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the - /// last element. - /// - /// This does not preserve ordering, but is O(1). - /// - /// Returns `None` if `index` is out of bounds. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.swap_remove_back(0), None); - /// buf.push_back(1); - /// buf.push_back(2); - /// buf.push_back(3); - /// assert_eq!(buf, [1, 2, 3]); - /// - /// assert_eq!(buf.swap_remove_back(0), Some(1)); - /// assert_eq!(buf, [3, 2]); - /// ``` - #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn swap_remove_back(&mut self, index: usize) -> Option { - let length = self.len(); - if length > 0 && index < length - 1 { - self.swap(index, length - 1); - } else if index >= length { - return None; - } - self.pop_back() - } - - /// Removes an element from anywhere in the `VecDeque` and returns it, - /// replacing it with the first element. - /// - /// This does not preserve ordering, but is O(1). - /// - /// Returns `None` if `index` is out of bounds. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// assert_eq!(buf.swap_remove_front(0), None); - /// buf.push_back(1); - /// buf.push_back(2); - /// buf.push_back(3); - /// assert_eq!(buf, [1, 2, 3]); - /// - /// assert_eq!(buf.swap_remove_front(2), Some(3)); - /// assert_eq!(buf, [2, 1]); - /// ``` - #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn swap_remove_front(&mut self, index: usize) -> Option { - let length = self.len(); - if length > 0 && index < length && index != 0 { - self.swap(index, 0); - } else if index >= length { - return None; - } - self.pop_front() - } - - /// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices - /// greater than or equal to `index` towards the back. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Panics - /// - /// Panics if `index` is greater than `VecDeque`'s length - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut vec_deque = VecDeque::new(); - /// vec_deque.push_back('a'); - /// vec_deque.push_back('b'); - /// vec_deque.push_back('c'); - /// assert_eq!(vec_deque, &['a', 'b', 'c']); - /// - /// vec_deque.insert(1, 'd'); - /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']); - /// ``` - #[stable(feature = "deque_extras_15", since = "1.5.0")] - pub fn insert(&mut self, index: usize, value: T) { - assert!(index <= self.len(), "index out of bounds"); - self.grow_if_necessary(); - - // Move the least number of elements in the ring buffer and insert - // the given object - // - // At most len/2 - 1 elements will be moved. O(min(n, n-i)) - // - // There are three main cases: - // Elements are contiguous - // - special case when tail is 0 - // Elements are discontiguous and the insert is in the tail section - // Elements are discontiguous and the insert is in the head section - // - // For each of those there are two more cases: - // Insert is closer to tail - // Insert is closer to head - // - // Key: H - self.head - // T - self.tail - // o - Valid element - // I - Insertion element - // A - The element that should be after the insertion point - // M - Indicates element was moved - - let idx = self.wrap_add(self.tail, index); - - let distance_to_tail = index; - let distance_to_head = self.len() - index; - - let contiguous = self.is_contiguous(); - - match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { - (true, true, _) if index == 0 => { - // push_front - // - // T - // I H - // [A o o o o o o . . . . . . . . .] - // - // H T - // [A o o o o o o o . . . . . I] - // - - self.tail = self.wrap_sub(self.tail, 1); - } - (true, true, _) => { - unsafe { - // contiguous, insert closer to tail: - // - // T I H - // [. . . o o A o o o o . . . . . .] - // - // T H - // [. . o o I A o o o o . . . . . .] - // M M - // - // contiguous, insert closer to tail and tail is 0: - // - // - // T I H - // [o o A o o o o . . . . . . . . .] - // - // H T - // [o I A o o o o o . . . . . . . o] - // M M - - let new_tail = self.wrap_sub(self.tail, 1); - - self.copy(new_tail, self.tail, 1); - // Already moved the tail, so we only copy `index - 1` elements. - self.copy(self.tail, self.tail + 1, index - 1); - - self.tail = new_tail; - } - } - (true, false, _) => { - unsafe { - // contiguous, insert closer to head: - // - // T I H - // [. . . o o o o A o o . . . . . .] - // - // T H - // [. . . o o o o I A o o . . . . .] - // M M M - - self.copy(idx + 1, idx, self.head - idx); - self.head = self.wrap_add(self.head, 1); - } - } - (false, true, true) => { - unsafe { - // discontiguous, insert closer to tail, tail section: - // - // H T I - // [o o o o o o . . . . . o o A o o] - // - // H T - // [o o o o o o . . . . o o I A o o] - // M M - - self.copy(self.tail - 1, self.tail, index); - self.tail -= 1; - } - } - (false, false, true) => { - unsafe { - // discontiguous, insert closer to head, tail section: - // - // H T I - // [o o . . . . . . . o o o o o A o] - // - // H T - // [o o o . . . . . . o o o o o I A] - // M M M M - - // copy elements up to new head - self.copy(1, 0, self.head); - - // copy last element into empty spot at bottom of buffer - self.copy(0, self.cap() - 1, 1); - - // move elements from idx to end forward not including ^ element - self.copy(idx + 1, idx, self.cap() - 1 - idx); - - self.head += 1; - } - } - (false, true, false) if idx == 0 => { - unsafe { - // discontiguous, insert is closer to tail, head section, - // and is at index zero in the internal buffer: - // - // I H T - // [A o o o o o o o o o . . . o o o] - // - // H T - // [A o o o o o o o o o . . o o o I] - // M M M - - // copy elements up to new tail - self.copy(self.tail - 1, self.tail, self.cap() - self.tail); - - // copy last element into empty spot at bottom of buffer - self.copy(self.cap() - 1, 0, 1); - - self.tail -= 1; - } - } - (false, true, false) => { - unsafe { - // discontiguous, insert closer to tail, head section: - // - // I H T - // [o o o A o o o o o o . . . o o o] - // - // H T - // [o o I A o o o o o o . . o o o o] - // M M M M M M - - // copy elements up to new tail - self.copy(self.tail - 1, self.tail, self.cap() - self.tail); - - // copy last element into empty spot at bottom of buffer - self.copy(self.cap() - 1, 0, 1); - - // move elements from idx-1 to end forward not including ^ element - self.copy(0, 1, idx - 1); - - self.tail -= 1; - } - } - (false, false, false) => { - unsafe { - // discontiguous, insert closer to head, head section: - // - // I H T - // [o o o o A o o . . . . . . o o o] - // - // H T - // [o o o o I A o o . . . . . o o o] - // M M M - - self.copy(idx + 1, idx, self.head - idx); - self.head += 1; - } - } - } - - // tail might've been changed so we need to recalculate - let new_idx = self.wrap_add(self.tail, index); - unsafe { - self.buffer_write(new_idx, value); - } - } - - /// Removes and returns the element at `index` from the `VecDeque`. - /// Whichever end is closer to the removal point will be moved to make - /// room, and all the affected elements will be moved to new positions. - /// Returns `None` if `index` is out of bounds. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(1); - /// buf.push_back(2); - /// buf.push_back(3); - /// assert_eq!(buf, [1, 2, 3]); - /// - /// assert_eq!(buf.remove(1), Some(2)); - /// assert_eq!(buf, [1, 3]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, index: usize) -> Option { - if self.is_empty() || self.len() <= index { - return None; - } - - // There are three main cases: - // Elements are contiguous - // Elements are discontiguous and the removal is in the tail section - // Elements are discontiguous and the removal is in the head section - // - special case when elements are technically contiguous, - // but self.head = 0 - // - // For each of those there are two more cases: - // Insert is closer to tail - // Insert is closer to head - // - // Key: H - self.head - // T - self.tail - // o - Valid element - // x - Element marked for removal - // R - Indicates element that is being removed - // M - Indicates element was moved - - let idx = self.wrap_add(self.tail, index); - - let elem = unsafe { Some(self.buffer_read(idx)) }; - - let distance_to_tail = index; - let distance_to_head = self.len() - index; - - let contiguous = self.is_contiguous(); - - match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { - (true, true, _) => { - unsafe { - // contiguous, remove closer to tail: - // - // T R H - // [. . . o o x o o o o . . . . . .] - // - // T H - // [. . . . o o o o o o . . . . . .] - // M M - - self.copy(self.tail + 1, self.tail, index); - self.tail += 1; - } - } - (true, false, _) => { - unsafe { - // contiguous, remove closer to head: - // - // T R H - // [. . . o o o o x o o . . . . . .] - // - // T H - // [. . . o o o o o o . . . . . . .] - // M M - - self.copy(idx, idx + 1, self.head - idx - 1); - self.head -= 1; - } - } - (false, true, true) => { - unsafe { - // discontiguous, remove closer to tail, tail section: - // - // H T R - // [o o o o o o . . . . . o o x o o] - // - // H T - // [o o o o o o . . . . . . o o o o] - // M M - - self.copy(self.tail + 1, self.tail, index); - self.tail = self.wrap_add(self.tail, 1); - } - } - (false, false, false) => { - unsafe { - // discontiguous, remove closer to head, head section: - // - // R H T - // [o o o o x o o . . . . . . o o o] - // - // H T - // [o o o o o o . . . . . . . o o o] - // M M - - self.copy(idx, idx + 1, self.head - idx - 1); - self.head -= 1; - } - } - (false, false, true) => { - unsafe { - // discontiguous, remove closer to head, tail section: - // - // H T R - // [o o o . . . . . . o o o o o x o] - // - // H T - // [o o . . . . . . . o o o o o o o] - // M M M M - // - // or quasi-discontiguous, remove next to head, tail section: - // - // H T R - // [. . . . . . . . . o o o o o x o] - // - // T H - // [. . . . . . . . . o o o o o o .] - // M - - // draw in elements in the tail section - self.copy(idx, idx + 1, self.cap() - idx - 1); - - // Prevents underflow. - if self.head != 0 { - // copy first element into empty spot - self.copy(self.cap() - 1, 0, 1); - - // move elements in the head section backwards - self.copy(0, 1, self.head - 1); - } - - self.head = self.wrap_sub(self.head, 1); - } - } - (false, true, false) => { - unsafe { - // discontiguous, remove closer to tail, head section: - // - // R H T - // [o o x o o o o o o o . . . o o o] - // - // H T - // [o o o o o o o o o o . . . . o o] - // M M M M M - - // draw in elements up to idx - self.copy(1, 0, idx); - - // copy last element into empty spot - self.copy(0, self.cap() - 1, 1); - - // move elements from tail to end forward, excluding the last one - self.copy(self.tail + 1, self.tail, self.cap() - self.tail - 1); - - self.tail = self.wrap_add(self.tail, 1); - } - } - } - - return elem; - } - - /// Splits the `VecDeque` into two at the given index. - /// - /// Returns a newly allocated `VecDeque`. `self` contains elements `[0, at)`, - /// and the returned `VecDeque` contains elements `[at, len)`. - /// - /// Note that the capacity of `self` does not change. - /// - /// Element at index 0 is the front of the queue. - /// - /// # Panics - /// - /// Panics if `at > len`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); - /// let buf2 = buf.split_off(1); - /// assert_eq!(buf, [1]); - /// assert_eq!(buf2, [2, 3]); - /// ``` - #[inline] - #[stable(feature = "split_off", since = "1.4.0")] - pub fn split_off(&mut self, at: usize) -> Self { - let len = self.len(); - assert!(at <= len, "`at` out of bounds"); - - let other_len = len - at; - let mut other = VecDeque::with_capacity(other_len); - - unsafe { - let (first_half, second_half) = self.as_slices(); - - let first_len = first_half.len(); - let second_len = second_half.len(); - if at < first_len { - // `at` lies in the first half. - let amount_in_first = first_len - at; - - ptr::copy_nonoverlapping(first_half.as_ptr().offset(at as isize), - other.ptr(), - amount_in_first); - - // just take all of the second half. - ptr::copy_nonoverlapping(second_half.as_ptr(), - other.ptr().offset(amount_in_first as isize), - second_len); - } else { - // `at` lies in the second half, need to factor in the elements we skipped - // in the first half. - let offset = at - first_len; - let amount_in_second = second_len - offset; - ptr::copy_nonoverlapping(second_half.as_ptr().offset(offset as isize), - other.ptr(), - amount_in_second); - } - } - - // Cleanup where the ends of the buffers are - self.head = self.wrap_sub(self.head, other_len); - other.head = other.wrap_index(other_len); - - other - } - - /// Moves all the elements of `other` into `Self`, leaving `other` empty. - /// - /// # Panics - /// - /// Panics if the new number of elements in self overflows a `usize`. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf: VecDeque<_> = vec![1, 2].into_iter().collect(); - /// let mut buf2: VecDeque<_> = vec![3, 4].into_iter().collect(); - /// buf.append(&mut buf2); - /// assert_eq!(buf, [1, 2, 3, 4]); - /// assert_eq!(buf2, []); - /// ``` - #[inline] - #[stable(feature = "append", since = "1.4.0")] - pub fn append(&mut self, other: &mut Self) { - // naive impl - self.extend(other.drain(..)); - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` such that `f(&e)` returns false. - /// This method operates in place and preserves the order of the retained - /// elements. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.extend(1..5); - /// buf.retain(|&x| x%2 == 0); - /// assert_eq!(buf, [2, 4]); - /// ``` - #[stable(feature = "vec_deque_retain", since = "1.4.0")] - pub fn retain(&mut self, mut f: F) - where F: FnMut(&T) -> bool - { - let len = self.len(); - let mut del = 0; - for i in 0..len { - if !f(&self[i]) { - del += 1; - } else if del > 0 { - self.swap(i - del, i); - } - } - if del > 0 { - self.truncate(len - del); - } - } - - // This may panic or abort - #[inline] - fn grow_if_necessary(&mut self) { - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } - } -} - -impl VecDeque { - /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len, - /// either by removing excess elements from the back or by appending clones of `value` - /// to the back. - /// - /// # Examples - /// - /// ``` - /// use std::collections::VecDeque; - /// - /// let mut buf = VecDeque::new(); - /// buf.push_back(5); - /// buf.push_back(10); - /// buf.push_back(15); - /// assert_eq!(buf, [5, 10, 15]); - /// - /// buf.resize(2, 0); - /// assert_eq!(buf, [5, 10]); - /// - /// buf.resize(5, 20); - /// assert_eq!(buf, [5, 10, 20, 20, 20]); - /// ``` - #[stable(feature = "deque_extras", since = "1.16.0")] - pub fn resize(&mut self, new_len: usize, value: T) { - let len = self.len(); - - if new_len > len { - self.extend(repeat(value).take(new_len - len)) - } else { - self.truncate(new_len); - } - } -} - -/// Returns the index in the underlying buffer for a given logical element index. -#[inline] -fn wrap_index(index: usize, size: usize) -> usize { - // size is always a power of 2 - debug_assert!(size.is_power_of_two()); - index & (size - 1) -} - -/// Returns the two slices that cover the `VecDeque`'s valid range -trait RingSlices: Sized { - fn slice(self, from: usize, to: usize) -> Self; - fn split_at(self, i: usize) -> (Self, Self); - - fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) { - let contiguous = tail <= head; - if contiguous { - let (empty, buf) = buf.split_at(0); - (buf.slice(tail, head), empty) - } else { - let (mid, right) = buf.split_at(tail); - let (left, _) = mid.split_at(head); - (right, left) - } - } -} - -impl<'a, T> RingSlices for &'a [T] { - fn slice(self, from: usize, to: usize) -> Self { - &self[from..to] - } - fn split_at(self, i: usize) -> (Self, Self) { - (*self).split_at(i) - } -} - -impl<'a, T> RingSlices for &'a mut [T] { - fn slice(self, from: usize, to: usize) -> Self { - &mut self[from..to] - } - fn split_at(self, i: usize) -> (Self, Self) { - (*self).split_at_mut(i) - } -} - -/// Calculate the number of elements left to be read in the buffer -#[inline] -fn count(tail: usize, head: usize, size: usize) -> usize { - // size is always a power of 2 - (head.wrapping_sub(tail)) & (size - 1) -} - -/// An iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its -/// documentation for more. -/// -/// [`iter`]: struct.VecDeque.html#method.iter -/// [`VecDeque`]: struct.VecDeque.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - ring: &'a [T], - tail: usize, - head: usize, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.ring) - .field(&self.tail) - .field(&self.head) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Iter<'a, T> { - Iter { - ring: self.ring, - tail: self.tail, - head: self.head, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - if self.tail == self.head { - return None; - } - let tail = self.tail; - self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); - unsafe { Some(self.ring.get_unchecked(tail)) } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = count(self.tail, self.head, self.ring.len()); - (len, Some(len)) - } - - fn fold(self, mut accum: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = front.iter().fold(accum, &mut f); - back.iter().fold(accum, &mut f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Iter<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a T> { - if self.tail == self.head { - return None; - } - self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); - unsafe { Some(self.ring.get_unchecked(self.head)) } - } - - fn rfold(self, mut accum: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = back.iter().rfold(accum, &mut f); - front.iter().rfold(accum, &mut f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> { - fn is_empty(&self) -> bool { - self.head == self.tail - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} - - -/// A mutable iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its -/// documentation for more. -/// -/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut -/// [`VecDeque`]: struct.VecDeque.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IterMut<'a, T: 'a> { - ring: &'a mut [T], - tail: usize, - head: usize, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("IterMut") - .field(&self.ring) - .field(&self.tail) - .field(&self.head) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for IterMut<'a, T> { - type Item = &'a mut T; - - #[inline] - fn next(&mut self) -> Option<&'a mut T> { - if self.tail == self.head { - return None; - } - let tail = self.tail; - self.tail = wrap_index(self.tail.wrapping_add(1), self.ring.len()); - - unsafe { - let elem = self.ring.get_unchecked_mut(tail); - Some(&mut *(elem as *mut _)) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = count(self.tail, self.head, self.ring.len()); - (len, Some(len)) - } - - fn fold(self, mut accum: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = front.iter_mut().fold(accum, &mut f); - back.iter_mut().fold(accum, &mut f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut T> { - if self.tail == self.head { - return None; - } - self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len()); - - unsafe { - let elem = self.ring.get_unchecked_mut(self.head); - Some(&mut *(elem as *mut _)) - } - } - - fn rfold(self, mut accum: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc - { - let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); - accum = back.iter_mut().rfold(accum, &mut f); - front.iter_mut().rfold(accum, &mut f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for IterMut<'a, T> { - fn is_empty(&self) -> bool { - self.head == self.tail - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for IterMut<'a, T> {} - -/// An owning iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`] -/// (provided by the `IntoIterator` trait). See its documentation for more. -/// -/// [`into_iter`]: struct.VecDeque.html#method.into_iter -/// [`VecDeque`]: struct.VecDeque.html -#[derive(Clone)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter { - inner: VecDeque, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("IntoIter") - .field(&self.inner) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.inner.pop_front() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.inner.len(); - (len, Some(len)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.pop_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for IntoIter { - fn is_empty(&self) -> bool { - self.inner.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for IntoIter {} - -/// A draining iterator over the elements of a `VecDeque`. -/// -/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its -/// documentation for more. -/// -/// [`drain`]: struct.VecDeque.html#method.drain -/// [`VecDeque`]: struct.VecDeque.html -#[stable(feature = "drain", since = "1.6.0")] -pub struct Drain<'a, T: 'a> { - after_tail: usize, - after_head: usize, - iter: Iter<'a, T>, - deque: NonNull>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Drain") - .field(&self.after_tail) - .field(&self.after_head) - .field(&self.iter) - .finish() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} -#[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Send> Send for Drain<'a, T> {} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> Drop for Drain<'a, T> { - fn drop(&mut self) { - self.for_each(drop); - - let source_deque = unsafe { self.deque.as_mut() }; - - // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head - // - // T t h H - // [. . . o o x x o o . . .] - // - let orig_tail = source_deque.tail; - let drain_tail = source_deque.head; - let drain_head = self.after_tail; - let orig_head = self.after_head; - - let tail_len = count(orig_tail, drain_tail, source_deque.cap()); - let head_len = count(drain_head, orig_head, source_deque.cap()); - - // Restore the original head value - source_deque.head = orig_head; - - match (tail_len, head_len) { - (0, 0) => { - source_deque.head = 0; - source_deque.tail = 0; - } - (0, _) => { - source_deque.tail = drain_head; - } - (_, 0) => { - source_deque.head = drain_tail; - } - _ => unsafe { - if tail_len <= head_len { - source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); - source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); - } else { - source_deque.head = source_deque.wrap_add(drain_tail, head_len); - source_deque.wrap_copy(drain_tail, drain_head, head_len); - } - }, - } - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> Iterator for Drain<'a, T> { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt) }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(|elt| unsafe { ptr::read(elt) }) - } -} - -#[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for VecDeque { - fn eq(&self, other: &VecDeque) -> bool { - if self.len() != other.len() { - return false; - } - let (sa, sb) = self.as_slices(); - let (oa, ob) = other.as_slices(); - if sa.len() == oa.len() { - sa == oa && sb == ob - } else if sa.len() < oa.len() { - // Always divisible in three sections, for example: - // self: [a b c|d e f] - // other: [0 1 2 3|4 5] - // front = 3, mid = 1, - // [a b c] == [0 1 2] && [d] == [3] && [e f] == [4 5] - let front = sa.len(); - let mid = oa.len() - front; - - let (oa_front, oa_mid) = oa.split_at(front); - let (sb_mid, sb_back) = sb.split_at(mid); - debug_assert_eq!(sa.len(), oa_front.len()); - debug_assert_eq!(sb_mid.len(), oa_mid.len()); - debug_assert_eq!(sb_back.len(), ob.len()); - sa == oa_front && sb_mid == oa_mid && sb_back == ob - } else { - let front = oa.len(); - let mid = sa.len() - front; - - let (sa_front, sa_mid) = sa.split_at(front); - let (ob_mid, ob_back) = ob.split_at(mid); - debug_assert_eq!(sa_front.len(), oa.len()); - debug_assert_eq!(sa_mid.len(), ob_mid.len()); - debug_assert_eq!(sb.len(), ob_back.len()); - sa_front == oa && sa_mid == ob_mid && sb == ob_back - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for VecDeque {} - -macro_rules! __impl_slice_eq1 { - ($Lhs: ty, $Rhs: ty) => { - __impl_slice_eq1! { $Lhs, $Rhs, Sized } - }; - ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - #[stable(feature = "vec-deque-partial-eq-slice", since = "1.17.0")] - impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { - fn eq(&self, other: &$Rhs) -> bool { - if self.len() != other.len() { - return false; - } - let (sa, sb) = self.as_slices(); - let (oa, ob) = other[..].split_at(sa.len()); - sa == oa && sb == ob - } - } - } -} - -__impl_slice_eq1! { VecDeque, Vec } -__impl_slice_eq1! { VecDeque, &'b [B] } -__impl_slice_eq1! { VecDeque, &'b mut [B] } - -macro_rules! array_impls { - ($($N: expr)+) => { - $( - __impl_slice_eq1! { VecDeque, [B; $N] } - __impl_slice_eq1! { VecDeque, &'b [B; $N] } - __impl_slice_eq1! { VecDeque, &'b mut [B; $N] } - )+ - } -} - -array_impls! { - 0 1 2 3 4 5 6 7 8 9 - 10 11 12 13 14 15 16 17 18 19 - 20 21 22 23 24 25 26 27 28 29 - 30 31 32 -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for VecDeque { - fn partial_cmp(&self, other: &VecDeque) -> Option { - self.iter().partial_cmp(other.iter()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for VecDeque { - #[inline] - fn cmp(&self, other: &VecDeque) -> Ordering { - self.iter().cmp(other.iter()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for VecDeque { - fn hash(&self, state: &mut H) { - self.len().hash(state); - let (a, b) = self.as_slices(); - Hash::hash_slice(a, state); - Hash::hash_slice(b, state); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Index for VecDeque { - type Output = A; - - #[inline] - fn index(&self, index: usize) -> &A { - self.get(index).expect("Out of bounds access") - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IndexMut for VecDeque { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut A { - self.get_mut(index).expect("Out of bounds access") - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromIterator for VecDeque { - fn from_iter>(iter: T) -> VecDeque { - let iterator = iter.into_iter(); - let (lower, _) = iterator.size_hint(); - let mut deq = VecDeque::with_capacity(lower); - deq.extend(iterator); - deq - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for VecDeque { - type Item = T; - type IntoIter = IntoIter; - - /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by - /// value. - fn into_iter(self) -> IntoIter { - IntoIter { inner: self } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a VecDeque { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut VecDeque { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Extend for VecDeque { - fn extend>(&mut self, iter: T) { - for elt in iter { - self.push_back(elt); - } - } -} - -#[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for VecDeque { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self).finish() - } -} - -#[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] -impl From> for VecDeque { - fn from(mut other: Vec) -> Self { - unsafe { - let other_buf = other.as_mut_ptr(); - let mut buf = RawVec::from_raw_parts(other_buf, other.capacity()); - let len = other.len(); - mem::forget(other); - - // We need to extend the buf if it's not a power of two, too small - // or doesn't have at least one free space - if !buf.cap().is_power_of_two() || (buf.cap() < (MINIMUM_CAPACITY + 1)) || - (buf.cap() == len) { - let cap = cmp::max(buf.cap() + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); - buf.reserve_exact(len, cap - len); - } - - VecDeque { - tail: 0, - head: len, - buf, - } - } - } -} - -#[stable(feature = "vecdeque_vec_conversions", since = "1.10.0")] -impl From> for Vec { - fn from(other: VecDeque) -> Self { - unsafe { - let buf = other.buf.ptr(); - let len = other.len(); - let tail = other.tail; - let head = other.head; - let cap = other.cap(); - - // Need to move the ring to the front of the buffer, as vec will expect this. - if other.is_contiguous() { - ptr::copy(buf.offset(tail as isize), buf, len); - } else { - if (tail - head) >= cmp::min(cap - tail, head) { - // There is enough free space in the centre for the shortest block so we can - // do this in at most three copy moves. - if (cap - tail) > head { - // right hand block is the long one; move that enough for the left - ptr::copy(buf.offset(tail as isize), - buf.offset((tail - head) as isize), - cap - tail); - // copy left in the end - ptr::copy(buf, buf.offset((cap - head) as isize), head); - // shift the new thing to the start - ptr::copy(buf.offset((tail - head) as isize), buf, len); - } else { - // left hand block is the long one, we can do it in two! - ptr::copy(buf, buf.offset((cap - tail) as isize), head); - ptr::copy(buf.offset(tail as isize), buf, cap - tail); - } - } else { - // Need to use N swaps to move the ring - // We can use the space at the end of the ring as a temp store - - let mut left_edge: usize = 0; - let mut right_edge: usize = tail; - - // The general problem looks like this - // GHIJKLM...ABCDEF - before any swaps - // ABCDEFM...GHIJKL - after 1 pass of swaps - // ABCDEFGHIJM...KL - swap until the left edge reaches the temp store - // - then restart the algorithm with a new (smaller) store - // Sometimes the temp store is reached when the right edge is at the end - // of the buffer - this means we've hit the right order with fewer swaps! - // E.g - // EF..ABCD - // ABCDEF.. - after four only swaps we've finished - - while left_edge < len && right_edge != cap { - let mut right_offset = 0; - for i in left_edge..right_edge { - right_offset = (i - left_edge) % (cap - right_edge); - let src: isize = (right_edge + right_offset) as isize; - ptr::swap(buf.offset(i as isize), buf.offset(src)); - } - let n_ops = right_edge - left_edge; - left_edge += n_ops; - right_edge += right_offset + 1; - - } - } - - } - let out = Vec::from_raw_parts(buf, len, cap); - mem::forget(other); - out - } - } -} - -#[cfg(test)] -mod tests { - use test; - - use super::VecDeque; - - #[bench] - fn bench_push_back_100(b: &mut test::Bencher) { - let mut deq = VecDeque::with_capacity(101); - b.iter(|| { - for i in 0..100 { - deq.push_back(i); - } - deq.head = 0; - deq.tail = 0; - }) - } - - #[bench] - fn bench_push_front_100(b: &mut test::Bencher) { - let mut deq = VecDeque::with_capacity(101); - b.iter(|| { - for i in 0..100 { - deq.push_front(i); - } - deq.head = 0; - deq.tail = 0; - }) - } - - #[bench] - fn bench_pop_back_100(b: &mut test::Bencher) { - let mut deq = VecDeque::::with_capacity(101); - - b.iter(|| { - deq.head = 100; - deq.tail = 0; - while !deq.is_empty() { - test::black_box(deq.pop_back()); - } - }) - } - - #[bench] - fn bench_pop_front_100(b: &mut test::Bencher) { - let mut deq = VecDeque::::with_capacity(101); - - b.iter(|| { - deq.head = 100; - deq.tail = 0; - while !deq.is_empty() { - test::black_box(deq.pop_front()); - } - }) - } - - #[test] - fn test_swap_front_back_remove() { - fn test(back: bool) { - // This test checks that every single combination of tail position and length is tested. - // Capacity 15 should be large enough to cover every case. - let mut tester = VecDeque::with_capacity(15); - let usable_cap = tester.capacity(); - let final_len = usable_cap / 2; - - for len in 0..final_len { - let expected: VecDeque<_> = if back { - (0..len).collect() - } else { - (0..len).rev().collect() - }; - for tail_pos in 0..usable_cap { - tester.tail = tail_pos; - tester.head = tail_pos; - if back { - for i in 0..len * 2 { - tester.push_front(i); - } - for i in 0..len { - assert_eq!(tester.swap_remove_back(i), Some(len * 2 - 1 - i)); - } - } else { - for i in 0..len * 2 { - tester.push_back(i); - } - for i in 0..len { - let idx = tester.len() - 1 - i; - assert_eq!(tester.swap_remove_front(idx), Some(len * 2 - 1 - i)); - } - } - assert!(tester.tail < tester.cap()); - assert!(tester.head < tester.cap()); - assert_eq!(tester, expected); - } - } - } - test(true); - test(false); - } - - #[test] - fn test_insert() { - // This test checks that every single combination of tail position, length, and - // insertion position is tested. Capacity 15 should be large enough to cover every case. - - let mut tester = VecDeque::with_capacity(15); - // can't guarantee we got 15, so have to get what we got. - // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else - // this test isn't covering what it wants to - let cap = tester.capacity(); - - - // len is the length *after* insertion - for len in 1..cap { - // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect::>(); - for tail_pos in 0..cap { - for to_insert in 0..len { - tester.tail = tail_pos; - tester.head = tail_pos; - for i in 0..len { - if i != to_insert { - tester.push_back(i); - } - } - tester.insert(to_insert, to_insert); - assert!(tester.tail < tester.cap()); - assert!(tester.head < tester.cap()); - assert_eq!(tester, expected); - } - } - } - } - - #[test] - fn test_remove() { - // This test checks that every single combination of tail position, length, and - // removal position is tested. Capacity 15 should be large enough to cover every case. - - let mut tester = VecDeque::with_capacity(15); - // can't guarantee we got 15, so have to get what we got. - // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else - // this test isn't covering what it wants to - let cap = tester.capacity(); - - // len is the length *after* removal - for len in 0..cap - 1 { - // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect::>(); - for tail_pos in 0..cap { - for to_remove in 0..len + 1 { - tester.tail = tail_pos; - tester.head = tail_pos; - for i in 0..len { - if i == to_remove { - tester.push_back(1234); - } - tester.push_back(i); - } - if to_remove == len { - tester.push_back(1234); - } - tester.remove(to_remove); - assert!(tester.tail < tester.cap()); - assert!(tester.head < tester.cap()); - assert_eq!(tester, expected); - } - } - } - } - - #[test] - fn test_drain() { - let mut tester: VecDeque = VecDeque::with_capacity(7); - - let cap = tester.capacity(); - for len in 0..cap + 1 { - for tail in 0..cap + 1 { - for drain_start in 0..len + 1 { - for drain_end in drain_start..len + 1 { - tester.tail = tail; - tester.head = tail; - for i in 0..len { - tester.push_back(i); - } - - // Check that we drain the correct values - let drained: VecDeque<_> = tester.drain(drain_start..drain_end).collect(); - let drained_expected: VecDeque<_> = (drain_start..drain_end).collect(); - assert_eq!(drained, drained_expected); - - // We shouldn't have changed the capacity or made the - // head or tail out of bounds - assert_eq!(tester.capacity(), cap); - assert!(tester.tail < tester.cap()); - assert!(tester.head < tester.cap()); - - // We should see the correct values in the VecDeque - let expected: VecDeque<_> = (0..drain_start) - .chain(drain_end..len) - .collect(); - assert_eq!(expected, tester); - } - } - } - } - } - - #[test] - fn test_shrink_to_fit() { - // This test checks that every single combination of head and tail position, - // is tested. Capacity 15 should be large enough to cover every case. - - let mut tester = VecDeque::with_capacity(15); - // can't guarantee we got 15, so have to get what we got. - // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else - // this test isn't covering what it wants to - let cap = tester.capacity(); - tester.reserve(63); - let max_cap = tester.capacity(); - - for len in 0..cap + 1 { - // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect::>(); - for tail_pos in 0..max_cap + 1 { - tester.tail = tail_pos; - tester.head = tail_pos; - tester.reserve(63); - for i in 0..len { - tester.push_back(i); - } - tester.shrink_to_fit(); - assert!(tester.capacity() <= cap); - assert!(tester.tail < tester.cap()); - assert!(tester.head < tester.cap()); - assert_eq!(tester, expected); - } - } - } - - #[test] - fn test_split_off() { - // This test checks that every single combination of tail position, length, and - // split position is tested. Capacity 15 should be large enough to cover every case. - - let mut tester = VecDeque::with_capacity(15); - // can't guarantee we got 15, so have to get what we got. - // 15 would be great, but we will definitely get 2^k - 1, for k >= 4, or else - // this test isn't covering what it wants to - let cap = tester.capacity(); - - // len is the length *before* splitting - for len in 0..cap { - // index to split at - for at in 0..len + 1 { - // 0, 1, 2, .., at - 1 (may be empty) - let expected_self = (0..).take(at).collect::>(); - // at, at + 1, .., len - 1 (may be empty) - let expected_other = (at..).take(len - at).collect::>(); - - for tail_pos in 0..cap { - tester.tail = tail_pos; - tester.head = tail_pos; - for i in 0..len { - tester.push_back(i); - } - let result = tester.split_off(at); - assert!(tester.tail < tester.cap()); - assert!(tester.head < tester.cap()); - assert!(result.tail < result.cap()); - assert!(result.head < result.cap()); - assert_eq!(tester, expected_self); - assert_eq!(result, expected_other); - } - } - } - } - - #[test] - fn test_from_vec() { - use super::super::vec::Vec; - for cap in 0..35 { - for len in 0..cap + 1 { - let mut vec = Vec::with_capacity(cap); - vec.extend(0..len); - - let vd = VecDeque::from(vec.clone()); - assert!(vd.cap().is_power_of_two()); - assert_eq!(vd.len(), vec.len()); - assert!(vd.into_iter().eq(vec)); - } - } - } - - #[test] - fn test_vec_from_vecdeque() { - use super::super::vec::Vec; - - fn create_vec_and_test_convert(cap: usize, offset: usize, len: usize) { - let mut vd = VecDeque::with_capacity(cap); - for _ in 0..offset { - vd.push_back(0); - vd.pop_front(); - } - vd.extend(0..len); - - let vec: Vec<_> = Vec::from(vd.clone()); - assert_eq!(vec.len(), vd.len()); - assert!(vec.into_iter().eq(vd)); - } - - for cap_pwr in 0..7 { - // Make capacity as a (2^x)-1, so that the ring size is 2^x - let cap = (2i32.pow(cap_pwr) - 1) as usize; - - // In these cases there is enough free space to solve it with copies - for len in 0..((cap + 1) / 2) { - // Test contiguous cases - for offset in 0..(cap - len) { - create_vec_and_test_convert(cap, offset, len) - } - - // Test cases where block at end of buffer is bigger than block at start - for offset in (cap - len)..(cap - (len / 2)) { - create_vec_and_test_convert(cap, offset, len) - } - - // Test cases where block at start of buffer is bigger than block at end - for offset in (cap - (len / 2))..cap { - create_vec_and_test_convert(cap, offset, len) - } - } - - // Now there's not (necessarily) space to straighten the ring with simple copies, - // the ring will use swapping when: - // (cap + 1 - offset) > (cap + 1 - len) && (len - (cap + 1 - offset)) > (cap + 1 - len)) - // right block size > free space && left block size > free space - for len in ((cap + 1) / 2)..cap { - // Test contiguous cases - for offset in 0..(cap - len) { - create_vec_and_test_convert(cap, offset, len) - } - - // Test cases where block at end of buffer is bigger than block at start - for offset in (cap - len)..(cap - (len / 2)) { - create_vec_and_test_convert(cap, offset, len) - } - - // Test cases where block at start of buffer is bigger than block at end - for offset in (cap - (len / 2))..cap { - create_vec_and_test_convert(cap, offset, len) - } - } - } - } - -} diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 42113414183..643426c377b 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -424,13 +424,13 @@ #[doc(hidden)] pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{BinaryHeap, BTreeMap, BTreeSet}; +pub use alloc_crate::collections::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{LinkedList, VecDeque}; +pub use alloc_crate::collections::{LinkedList, VecDeque}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{binary_heap, btree_map, btree_set}; +pub use alloc_crate::collections::{binary_heap, btree_map, btree_set}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::{linked_list, vec_deque}; +pub use alloc_crate::collections::{linked_list, vec_deque}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_map::HashMap; -- cgit 1.4.1-3-g733a5 From b0547cea0ae50f49619ded26f43d0d55a1674b14 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 15 Jun 2018 03:56:35 +0200 Subject: Move core::alloc::CollectionAllocErr to alloc::collections --- src/liballoc/collections/mod.rs | 29 +++++++++++++++++++++++++++++ src/liballoc/collections/vec_deque.rs | 2 +- src/liballoc/raw_vec.rs | 4 ++-- src/liballoc/string.rs | 2 +- src/liballoc/vec.rs | 2 +- src/libcore/alloc.rs | 28 ---------------------------- src/libstd/collections/hash/map.rs | 2 +- src/libstd/collections/hash/table.rs | 3 ++- src/libstd/collections/mod.rs | 2 +- 9 files changed, 38 insertions(+), 36 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/collections/mod.rs b/src/liballoc/collections/mod.rs index 35c816a1ceb..96e0eb633b2 100644 --- a/src/liballoc/collections/mod.rs +++ b/src/liballoc/collections/mod.rs @@ -51,6 +51,35 @@ pub use self::linked_list::LinkedList; #[doc(no_inline)] pub use self::vec_deque::VecDeque; +use alloc::{AllocErr, LayoutErr}; + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr, +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(AllocErr: AllocErr) -> Self { + CollectionAllocErr::AllocErr + } +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(_: LayoutErr) -> Self { + CollectionAllocErr::CapacityOverflow + } +} + /// An intermediate trait for specialization of `Extend`. #[doc(hidden)] trait SpecExtend { diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 4753d36415c..ba92b886138 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -30,7 +30,7 @@ use core::slice; use core::hash::{Hash, Hasher}; use core::cmp; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use raw_vec::RawVec; use vec::Vec; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 5095bbe96cc..4f2686abf45 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -18,8 +18,8 @@ use core::ptr::{self, NonNull, Unique}; use core::slice; use alloc::{Alloc, Layout, Global, handle_alloc_error}; -use alloc::CollectionAllocErr; -use alloc::CollectionAllocErr::*; +use collections::CollectionAllocErr; +use collections::CollectionAllocErr::*; use boxed::Box; /// A low-level utility for more ergonomically allocating, reallocating, and deallocating diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a988b6a26d9..6b28687a060 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -66,7 +66,7 @@ use core::ptr; use core::str::pattern::Pattern; use core::str::lossy; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use borrow::{Cow, ToOwned}; use boxed::Box; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 752a6c966d5..fbbaced540e 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -80,7 +80,7 @@ use core::ptr; use core::ptr::NonNull; use core::slice; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use borrow::ToOwned; use borrow::Cow; use boxed::Box; diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 91447e01ad4..01221aecb62 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -385,34 +385,6 @@ impl fmt::Display for CannotReallocInPlace { } } -/// Augments `AllocErr` with a CapacityOverflow variant. -// FIXME: should this be in libcore or liballoc? -#[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr, -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - #[inline] - fn from(AllocErr: AllocErr) -> Self { - CollectionAllocErr::AllocErr - } -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - #[inline] - fn from(_: LayoutErr) -> Self { - CollectionAllocErr::CapacityOverflow - } -} - /// A memory allocator that can be registered as the standard library’s default /// though the `#[global_allocator]` attributes. /// diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ee8c1dc81ad..91912e5f241 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,7 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use cell::Cell; use borrow::Borrow; use cmp::max; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index d14b754ddb6..2b319186a8d 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, handle_alloc_error}; +use alloc::{Global, Alloc, Layout, LayoutErr, handle_alloc_error}; +use collections::CollectionAllocErr; use hash::{BuildHasher, Hash, Hasher}; use marker; use mem::{size_of, needs_drop}; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 643426c377b..8d2c82bc0aa 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -438,7 +438,7 @@ pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use alloc::CollectionAllocErr; +pub use alloc_crate::collections::CollectionAllocErr; mod hash; -- cgit 1.4.1-3-g733a5 From c7638edf5293dd471d951e64671d60febd0b628c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 15 Jun 2018 04:07:09 +0200 Subject: Rename alloc::arc to alloc::sync, to match std::sync --- src/liballoc/arc.rs | 1936 ------------------------------------------------ src/liballoc/lib.rs | 4 +- src/liballoc/sync.rs | 1936 ++++++++++++++++++++++++++++++++++++++++++++++++ src/liballoc/task.rs | 2 +- src/libstd/sync/mod.rs | 2 +- 5 files changed, 1940 insertions(+), 1940 deletions(-) delete mode 100644 src/liballoc/arc.rs create mode 100644 src/liballoc/sync.rs (limited to 'src/libstd') diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs deleted file mode 100644 index 2abd9c85c57..00000000000 --- a/src/liballoc/arc.rs +++ /dev/null @@ -1,1936 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "rust1", since = "1.0.0")] - -//! Thread-safe reference-counting pointers. -//! -//! See the [`Arc`][arc] documentation for more details. -//! -//! [arc]: struct.Arc.html - -use core::any::Any; -use core::sync::atomic; -use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use core::borrow; -use core::fmt; -use core::cmp::Ordering; -use core::intrinsics::abort; -use core::mem::{self, align_of_val, size_of_val}; -use core::ops::Deref; -use core::ops::CoerceUnsized; -use core::ptr::{self, NonNull}; -use core::marker::{Unsize, PhantomData}; -use core::hash::{Hash, Hasher}; -use core::{isize, usize}; -use core::convert::From; - -use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; -use boxed::Box; -use string::String; -use vec::Vec; - -/// A soft limit on the amount of references that may be made to an `Arc`. -/// -/// Going above this limit will abort your program (although not -/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. -const MAX_REFCOUNT: usize = (isize::MAX) as usize; - -/// A sentinel value that is used for the pointer of `Weak::new()`. -const WEAK_EMPTY: usize = 1; - -/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically -/// Reference Counted'. -/// -/// The type `Arc` provides shared ownership of a value of type `T`, -/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces -/// a new pointer to the same value in the heap. When the last `Arc` -/// pointer to a given value is destroyed, the pointed-to value is -/// also destroyed. -/// -/// Shared references in Rust disallow mutation by default, and `Arc` is no -/// exception: you cannot generally obtain a mutable reference to something -/// inside an `Arc`. If you need to mutate through an `Arc`, use -/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] -/// types. -/// -/// ## Thread Safety -/// -/// Unlike [`Rc`], `Arc` uses atomic operations for its reference -/// counting. This means that it is thread-safe. The disadvantage is that -/// atomic operations are more expensive than ordinary memory accesses. If you -/// are not sharing reference-counted values between threads, consider using -/// [`Rc`] for lower overhead. [`Rc`] is a safe default, because the -/// compiler will catch any attempt to send an [`Rc`] between threads. -/// However, a library might choose `Arc` in order to give library consumers -/// more flexibility. -/// -/// `Arc` will implement [`Send`] and [`Sync`] as long as the `T` implements -/// [`Send`] and [`Sync`]. Why can't you put a non-thread-safe type `T` in an -/// `Arc` to make it thread-safe? This may be a bit counter-intuitive at -/// first: after all, isn't the point of `Arc` thread safety? The key is -/// this: `Arc` makes it thread safe to have multiple ownership of the same -/// data, but it doesn't add thread safety to its data. Consider -/// `Arc<`[`RefCell`]`>`. [`RefCell`] isn't [`Sync`], and if `Arc` was always -/// [`Send`], `Arc<`[`RefCell`]`>` would be as well. But then we'd have a problem: -/// [`RefCell`] is not thread safe; it keeps track of the borrowing count using -/// non-atomic operations. -/// -/// In the end, this means that you may need to pair `Arc` with some sort of -/// [`std::sync`] type, usually [`Mutex`][mutex]. -/// -/// ## Breaking cycles with `Weak` -/// -/// The [`downgrade`][downgrade] method can be used to create a non-owning -/// [`Weak`][weak] pointer. A [`Weak`][weak] pointer can be [`upgrade`][upgrade]d -/// to an `Arc`, but this will return [`None`] if the value has already been -/// dropped. -/// -/// A cycle between `Arc` pointers will never be deallocated. For this reason, -/// [`Weak`][weak] is used to break cycles. For example, a tree could have -/// strong `Arc` pointers from parent nodes to children, and [`Weak`][weak] -/// pointers from children back to their parents. -/// -/// # Cloning references -/// -/// Creating a new reference from an existing reference counted pointer is done using the -/// `Clone` trait implemented for [`Arc`][arc] and [`Weak`][weak]. -/// -/// ``` -/// use std::sync::Arc; -/// let foo = Arc::new(vec![1.0, 2.0, 3.0]); -/// // The two syntaxes below are equivalent. -/// let a = foo.clone(); -/// let b = Arc::clone(&foo); -/// // a and b both point to the same memory location as foo. -/// ``` -/// -/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly -/// the meaning of the code. In the example above, this syntax makes it easier to see that -/// this code is creating a new reference rather than copying the whole content of foo. -/// -/// ## `Deref` behavior -/// -/// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), -/// so you can call `T`'s methods on a value of type `Arc`. To avoid name -/// clashes with `T`'s methods, the methods of `Arc` itself are [associated -/// functions][assoc], called using function-like syntax: -/// -/// ``` -/// use std::sync::Arc; -/// let my_arc = Arc::new(()); -/// -/// Arc::downgrade(&my_arc); -/// ``` -/// -/// [`Weak`][weak] does not auto-dereference to `T`, because the value may have -/// already been destroyed. -/// -/// [arc]: struct.Arc.html -/// [weak]: struct.Weak.html -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone -/// [mutex]: ../../std/sync/struct.Mutex.html -/// [rwlock]: ../../std/sync/struct.RwLock.html -/// [atomic]: ../../std/sync/atomic/index.html -/// [`Send`]: ../../std/marker/trait.Send.html -/// [`Sync`]: ../../std/marker/trait.Sync.html -/// [deref]: ../../std/ops/trait.Deref.html -/// [downgrade]: struct.Arc.html#method.downgrade -/// [upgrade]: struct.Weak.html#method.upgrade -/// [`None`]: ../../std/option/enum.Option.html#variant.None -/// [assoc]: ../../book/first-edition/method-syntax.html#associated-functions -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`std::sync`]: ../../std/sync/index.html -/// [`Arc::clone(&from)`]: #method.clone -/// -/// # Examples -/// -/// Sharing some immutable data between threads: -/// -// Note that we **do not** run these tests here. The windows builders get super -// unhappy if a thread outlives the main thread and then exits at the same time -// (something deadlocks) so we just avoid this entirely by not running these -// tests. -/// ```no_run -/// use std::sync::Arc; -/// use std::thread; -/// -/// let five = Arc::new(5); -/// -/// for _ in 0..10 { -/// let five = Arc::clone(&five); -/// -/// thread::spawn(move || { -/// println!("{:?}", five); -/// }); -/// } -/// ``` -/// -/// Sharing a mutable [`AtomicUsize`]: -/// -/// [`AtomicUsize`]: ../../std/sync/atomic/struct.AtomicUsize.html -/// -/// ```no_run -/// use std::sync::Arc; -/// use std::sync::atomic::{AtomicUsize, Ordering}; -/// use std::thread; -/// -/// let val = Arc::new(AtomicUsize::new(5)); -/// -/// for _ in 0..10 { -/// let val = Arc::clone(&val); -/// -/// thread::spawn(move || { -/// let v = val.fetch_add(1, Ordering::SeqCst); -/// println!("{:?}", v); -/// }); -/// } -/// ``` -/// -/// See the [`rc` documentation][rc_examples] for more examples of reference -/// counting in general. -/// -/// [rc_examples]: ../../std/rc/index.html#examples -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Arc { - ptr: NonNull>, - phantom: PhantomData, -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Arc {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for Arc {} - -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized> CoerceUnsized> for Arc {} - -/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the -/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. -/// -/// Since a `Weak` reference does not count towards ownership, it will not -/// prevent the inner value from being dropped, and `Weak` itself makes no -/// guarantees about the value still being present and may return [`None`] -/// when [`upgrade`]d. -/// -/// A `Weak` pointer is useful for keeping a temporary reference to the value -/// within [`Arc`] without extending its lifetime. It is also used to prevent -/// circular references between [`Arc`] pointers, since mutual owning references -/// would never allow either [`Arc`] to be dropped. For example, a tree could -/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` -/// pointers from children back to their parents. -/// -/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. -/// -/// [`Arc`]: struct.Arc.html -/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade -/// [`upgrade`]: struct.Weak.html#method.upgrade -/// [`Option`]: ../../std/option/enum.Option.html -/// [`None`]: ../../std/option/enum.Option.html#variant.None -#[stable(feature = "arc_weak", since = "1.4.0")] -pub struct Weak { - // This is a `NonNull` to allow optimizing the size of this type in enums, - // but it is actually not truly "non-null". A `Weak::new()` will set this - // to a sentinel value, instead of needing to allocate some space in the - // heap. - ptr: NonNull>, -} - -#[stable(feature = "arc_weak", since = "1.4.0")] -unsafe impl Send for Weak {} -#[stable(feature = "arc_weak", since = "1.4.0")] -unsafe impl Sync for Weak {} - -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized> CoerceUnsized> for Weak {} - -#[stable(feature = "arc_weak", since = "1.4.0")] -impl fmt::Debug for Weak { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(Weak)") - } -} - -struct ArcInner { - strong: atomic::AtomicUsize, - - // the value usize::MAX acts as a sentinel for temporarily "locking" the - // ability to upgrade weak pointers or downgrade strong ones; this is used - // to avoid races in `make_mut` and `get_mut`. - weak: atomic::AtomicUsize, - - data: T, -} - -unsafe impl Send for ArcInner {} -unsafe impl Sync for ArcInner {} - -impl Arc { - /// Constructs a new `Arc`. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(data: T) -> Arc { - // Start the weak pointer count as 1 which is the weak pointer that's - // held by all the strong pointers (kinda), see std/rc.rs for more info - let x: Box<_> = box ArcInner { - strong: atomic::AtomicUsize::new(1), - weak: atomic::AtomicUsize::new(1), - data, - }; - Arc { ptr: Box::into_raw_non_null(x), phantom: PhantomData } - } - - /// Returns the contained value, if the `Arc` has exactly one strong reference. - /// - /// Otherwise, an [`Err`][result] is returned with the same `Arc` that was - /// passed in. - /// - /// This will succeed even if there are outstanding weak references. - /// - /// [result]: ../../std/result/enum.Result.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new(3); - /// assert_eq!(Arc::try_unwrap(x), Ok(3)); - /// - /// let x = Arc::new(4); - /// let _y = Arc::clone(&x); - /// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4); - /// ``` - #[inline] - #[stable(feature = "arc_unique", since = "1.4.0")] - pub fn try_unwrap(this: Self) -> Result { - // See `drop` for why all these atomics are like this - if this.inner().strong.compare_exchange(1, 0, Release, Relaxed).is_err() { - return Err(this); - } - - atomic::fence(Acquire); - - unsafe { - let elem = ptr::read(&this.ptr.as_ref().data); - - // Make a weak pointer to clean up the implicit strong-weak reference - let _weak = Weak { ptr: this.ptr }; - mem::forget(this); - - Ok(elem) - } - } -} - -impl Arc { - /// Consumes the `Arc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Arc` using - /// [`Arc::from_raw`][from_raw]. - /// - /// [from_raw]: struct.Arc.html#method.from_raw - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new(10); - /// let x_ptr = Arc::into_raw(x); - /// assert_eq!(unsafe { *x_ptr }, 10); - /// ``` - #[stable(feature = "rc_raw", since = "1.17.0")] - pub fn into_raw(this: Self) -> *const T { - let ptr: *const T = &*this; - mem::forget(this); - ptr - } - - /// Constructs an `Arc` from a raw pointer. - /// - /// The raw pointer must have been previously returned by a call to a - /// [`Arc::into_raw`][into_raw]. - /// - /// This function is unsafe because improper use may lead to memory problems. For example, a - /// double-free may occur if the function is called twice on the same raw pointer. - /// - /// [into_raw]: struct.Arc.html#method.into_raw - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new(10); - /// let x_ptr = Arc::into_raw(x); - /// - /// unsafe { - /// // Convert back to an `Arc` to prevent leak. - /// let x = Arc::from_raw(x_ptr); - /// assert_eq!(*x, 10); - /// - /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. - /// } - /// - /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! - /// ``` - #[stable(feature = "rc_raw", since = "1.17.0")] - pub unsafe fn from_raw(ptr: *const T) -> Self { - // Align the unsized value to the end of the ArcInner. - // Because it is ?Sized, it will always be the last field in memory. - let align = align_of_val(&*ptr); - let layout = Layout::new::>(); - let offset = (layout.size() + layout.padding_needed_for(align)) as isize; - - // Reverse the offset to find the original ArcInner. - let fake_ptr = ptr as *mut ArcInner; - let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - - Arc { - ptr: NonNull::new_unchecked(arc_ptr), - phantom: PhantomData, - } - } - - /// Creates a new [`Weak`][weak] pointer to this value. - /// - /// [weak]: struct.Weak.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// let weak_five = Arc::downgrade(&five); - /// ``` - #[stable(feature = "arc_weak", since = "1.4.0")] - pub fn downgrade(this: &Self) -> Weak { - // This Relaxed is OK because we're checking the value in the CAS - // below. - let mut cur = this.inner().weak.load(Relaxed); - - loop { - // check if the weak counter is currently "locked"; if so, spin. - if cur == usize::MAX { - cur = this.inner().weak.load(Relaxed); - continue; - } - - // NOTE: this code currently ignores the possibility of overflow - // into usize::MAX; in general both Rc and Arc need to be adjusted - // to deal with overflow. - - // Unlike with Clone(), we need this to be an Acquire read to - // synchronize with the write coming from `is_unique`, so that the - // events prior to that write happen before this read. - match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) { - Ok(_) => return Weak { ptr: this.ptr }, - Err(old) => cur = old, - } - } - } - - /// Gets the number of [`Weak`][weak] pointers to this value. - /// - /// [weak]: struct.Weak.html - /// - /// # Safety - /// - /// This method by itself is safe, but using it correctly requires extra care. - /// Another thread can change the weak count at any time, - /// including potentially between calling this method and acting on the result. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// let _weak_five = Arc::downgrade(&five); - /// - /// // This assertion is deterministic because we haven't shared - /// // the `Arc` or `Weak` between threads. - /// assert_eq!(1, Arc::weak_count(&five)); - /// ``` - #[inline] - #[stable(feature = "arc_counts", since = "1.15.0")] - pub fn weak_count(this: &Self) -> usize { - let cnt = this.inner().weak.load(SeqCst); - // If the weak count is currently locked, the value of the - // count was 0 just before taking the lock. - if cnt == usize::MAX { 0 } else { cnt - 1 } - } - - /// Gets the number of strong (`Arc`) pointers to this value. - /// - /// # Safety - /// - /// This method by itself is safe, but using it correctly requires extra care. - /// Another thread can change the strong count at any time, - /// including potentially between calling this method and acting on the result. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// let _also_five = Arc::clone(&five); - /// - /// // This assertion is deterministic because we haven't shared - /// // the `Arc` between threads. - /// assert_eq!(2, Arc::strong_count(&five)); - /// ``` - #[inline] - #[stable(feature = "arc_counts", since = "1.15.0")] - pub fn strong_count(this: &Self) -> usize { - this.inner().strong.load(SeqCst) - } - - #[inline] - fn inner(&self) -> &ArcInner { - // This unsafety is ok because while this arc is alive we're guaranteed - // that the inner pointer is valid. Furthermore, we know that the - // `ArcInner` structure itself is `Sync` because the inner data is - // `Sync` as well, so we're ok loaning out an immutable pointer to these - // contents. - unsafe { self.ptr.as_ref() } - } - - // Non-inlined part of `drop`. - #[inline(never)] - unsafe fn drop_slow(&mut self) { - // Destroy the data at this time, even though we may not free the box - // allocation itself (there may still be weak pointers lying around). - ptr::drop_in_place(&mut self.ptr.as_mut().data); - - if self.inner().weak.fetch_sub(1, Release) == 1 { - atomic::fence(Acquire); - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) - } - } - - #[inline] - #[stable(feature = "ptr_eq", since = "1.17.0")] - /// Returns true if the two `Arc`s point to the same value (not - /// just values that compare as equal). - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// let same_five = Arc::clone(&five); - /// let other_five = Arc::new(5); - /// - /// assert!(Arc::ptr_eq(&five, &same_five)); - /// assert!(!Arc::ptr_eq(&five, &other_five)); - /// ``` - pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() - } -} - -impl Arc { - // Allocates an `ArcInner` with sufficient space for an unsized value - unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { - // Create a fake ArcInner to find allocation size and alignment - let fake_ptr = ptr as *mut ArcInner; - - let layout = Layout::for_value(&*fake_ptr); - - let mem = Global.alloc(layout) - .unwrap_or_else(|_| handle_alloc_error(layout)); - - // Initialize the real ArcInner - let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; - - ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); - ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); - - inner - } - - fn from_box(v: Box) -> Arc { - unsafe { - let box_unique = Box::into_unique(v); - let bptr = box_unique.as_ptr(); - - let value_size = size_of_val(&*bptr); - let ptr = Self::allocate_for_ptr(bptr); - - // Copy value as bytes - ptr::copy_nonoverlapping( - bptr as *const T as *const u8, - &mut (*ptr).data as *mut _ as *mut u8, - value_size); - - // Free the allocation without dropping its contents - box_free(box_unique); - - Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } - } - } -} - -// Sets the data pointer of a `?Sized` raw pointer. -// -// For a slice/trait object, this sets the `data` field and leaves the rest -// unchanged. For a sized raw pointer, this simply sets the pointer. -unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); - ptr -} - -impl Arc<[T]> { - // Copy elements from slice into newly allocated Arc<[T]> - // - // Unsafe because the caller must either take ownership or bind `T: Copy` - unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { - let v_ptr = v as *const [T]; - let ptr = Self::allocate_for_ptr(v_ptr); - - ptr::copy_nonoverlapping( - v.as_ptr(), - &mut (*ptr).data as *mut [T] as *mut T, - v.len()); - - Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } - } -} - -// Specialization trait used for From<&[T]> -trait ArcFromSlice { - fn from_slice(slice: &[T]) -> Self; -} - -impl ArcFromSlice for Arc<[T]> { - #[inline] - default fn from_slice(v: &[T]) -> Self { - // Panic guard while cloning T elements. - // In the event of a panic, elements that have been written - // into the new ArcInner will be dropped, then the memory freed. - struct Guard { - mem: NonNull, - elems: *mut T, - layout: Layout, - n_elems: usize, - } - - impl Drop for Guard { - fn drop(&mut self) { - use core::slice::from_raw_parts_mut; - - unsafe { - let slice = from_raw_parts_mut(self.elems, self.n_elems); - ptr::drop_in_place(slice); - - Global.dealloc(self.mem.cast(), self.layout.clone()); - } - } - } - - unsafe { - let v_ptr = v as *const [T]; - let ptr = Self::allocate_for_ptr(v_ptr); - - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); - - // Pointer to first element - let elems = &mut (*ptr).data as *mut [T] as *mut T; - - let mut guard = Guard{ - mem: NonNull::new_unchecked(mem), - elems: elems, - layout: layout, - n_elems: 0, - }; - - for (i, item) in v.iter().enumerate() { - ptr::write(elems.offset(i as isize), item.clone()); - guard.n_elems += 1; - } - - // All clear. Forget the guard so it doesn't free the new ArcInner. - mem::forget(guard); - - Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } - } - } -} - -impl ArcFromSlice for Arc<[T]> { - #[inline] - fn from_slice(v: &[T]) -> Self { - unsafe { Arc::copy_from_slice(v) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Arc { - /// Makes a clone of the `Arc` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// strong reference count. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// Arc::clone(&five); - /// ``` - #[inline] - fn clone(&self) -> Arc { - // Using a relaxed ordering is alright here, as knowledge of the - // original reference prevents other threads from erroneously deleting - // the object. - // - // As explained in the [Boost documentation][1], Increasing the - // reference counter can always be done with memory_order_relaxed: New - // references to an object can only be formed from an existing - // reference, and passing an existing reference from one thread to - // another must already provide any required synchronization. - // - // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) - let old_size = self.inner().strong.fetch_add(1, Relaxed); - - // However we need to guard against massive refcounts in case someone - // is `mem::forget`ing Arcs. If we don't do this the count can overflow - // and users will use-after free. We racily saturate to `isize::MAX` on - // the assumption that there aren't ~2 billion threads incrementing - // the reference count at once. This branch will never be taken in - // any realistic program. - // - // We abort because such a program is incredibly degenerate, and we - // don't care to support it. - if old_size > MAX_REFCOUNT { - unsafe { - abort(); - } - } - - Arc { ptr: self.ptr, phantom: PhantomData } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Arc { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - &self.inner().data - } -} - -impl Arc { - /// Makes a mutable reference into the given `Arc`. - /// - /// If there are other `Arc` or [`Weak`][weak] pointers to the same value, - /// then `make_mut` will invoke [`clone`][clone] on the inner value to - /// ensure unique ownership. This is also referred to as clone-on-write. - /// - /// See also [`get_mut`][get_mut], which will fail rather than cloning. - /// - /// [weak]: struct.Weak.html - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone - /// [get_mut]: struct.Arc.html#method.get_mut - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let mut data = Arc::new(5); - /// - /// *Arc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = Arc::clone(&data); // Won't clone inner data - /// *Arc::make_mut(&mut data) += 1; // Clones inner data - /// *Arc::make_mut(&mut data) += 1; // Won't clone anything - /// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything - /// - /// // Now `data` and `other_data` point to different values. - /// assert_eq!(*data, 8); - /// assert_eq!(*other_data, 12); - /// ``` - #[inline] - #[stable(feature = "arc_unique", since = "1.4.0")] - pub fn make_mut(this: &mut Self) -> &mut T { - // Note that we hold both a strong reference and a weak reference. - // Thus, releasing our strong reference only will not, by itself, cause - // the memory to be deallocated. - // - // Use Acquire to ensure that we see any writes to `weak` that happen - // before release writes (i.e., decrements) to `strong`. Since we hold a - // weak count, there's no chance the ArcInner itself could be - // deallocated. - if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() { - // Another strong pointer exists; clone - *this = Arc::new((**this).clone()); - } else if this.inner().weak.load(Relaxed) != 1 { - // Relaxed suffices in the above because this is fundamentally an - // optimization: we are always racing with weak pointers being - // dropped. Worst case, we end up allocated a new Arc unnecessarily. - - // We removed the last strong ref, but there are additional weak - // refs remaining. We'll move the contents to a new Arc, and - // invalidate the other weak refs. - - // Note that it is not possible for the read of `weak` to yield - // usize::MAX (i.e., locked), since the weak count can only be - // locked by a thread with a strong reference. - - // Materialize our own implicit weak pointer, so that it can clean - // up the ArcInner as needed. - let weak = Weak { ptr: this.ptr }; - - // mark the data itself as already deallocated - unsafe { - // there is no data race in the implicit write caused by `read` - // here (due to zeroing) because data is no longer accessed by - // other threads (due to there being no more strong refs at this - // point). - let mut swap = Arc::new(ptr::read(&weak.ptr.as_ref().data)); - mem::swap(this, &mut swap); - mem::forget(swap); - } - } else { - // We were the sole reference of either kind; bump back up the - // strong ref count. - this.inner().strong.store(1, Release); - } - - // As with `get_mut()`, the unsafety is ok because our reference was - // either unique to begin with, or became one upon cloning the contents. - unsafe { - &mut this.ptr.as_mut().data - } - } -} - -impl Arc { - /// Returns a mutable reference to the inner value, if there are - /// no other `Arc` or [`Weak`][weak] pointers to the same value. - /// - /// Returns [`None`][option] otherwise, because it is not safe to - /// mutate a shared value. - /// - /// See also [`make_mut`][make_mut], which will [`clone`][clone] - /// the inner value when it's shared. - /// - /// [weak]: struct.Weak.html - /// [option]: ../../std/option/enum.Option.html - /// [make_mut]: struct.Arc.html#method.make_mut - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let mut x = Arc::new(3); - /// *Arc::get_mut(&mut x).unwrap() = 4; - /// assert_eq!(*x, 4); - /// - /// let _y = Arc::clone(&x); - /// assert!(Arc::get_mut(&mut x).is_none()); - /// ``` - #[inline] - #[stable(feature = "arc_unique", since = "1.4.0")] - pub fn get_mut(this: &mut Self) -> Option<&mut T> { - if this.is_unique() { - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the Arc itself to be `mut`, so we're returning the only possible - // reference to the inner data. - unsafe { - Some(&mut this.ptr.as_mut().data) - } - } else { - None - } - } - - /// Determine whether this is the unique reference (including weak refs) to - /// the underlying data. - /// - /// Note that this requires locking the weak ref count. - fn is_unique(&mut self) -> bool { - // lock the weak pointer count if we appear to be the sole weak pointer - // holder. - // - // The acquire label here ensures a happens-before relationship with any - // writes to `strong` prior to decrements of the `weak` count (via drop, - // which uses Release). - if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() { - // Due to the previous acquire read, this will observe any writes to - // `strong` that were due to upgrading weak pointers; only strong - // clones remain, which require that the strong count is > 1 anyway. - let unique = self.inner().strong.load(Relaxed) == 1; - - // The release write here synchronizes with a read in `downgrade`, - // effectively preventing the above read of `strong` from happening - // after the write. - self.inner().weak.store(1, Release); // release the lock - unique - } else { - false - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { - /// Drops the `Arc`. - /// - /// This will decrement the strong reference count. If the strong reference - /// count reaches zero then the only other references (if any) are - /// [`Weak`][weak], so we `drop` the inner value. - /// - /// [weak]: struct.Weak.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Arc::new(Foo); - /// let foo2 = Arc::clone(&foo); - /// - /// drop(foo); // Doesn't print anything - /// drop(foo2); // Prints "dropped!" - /// ``` - #[inline] - fn drop(&mut self) { - // Because `fetch_sub` is already atomic, we do not need to synchronize - // with other threads unless we are going to delete the object. This - // same logic applies to the below `fetch_sub` to the `weak` count. - if self.inner().strong.fetch_sub(1, Release) != 1 { - return; - } - - // This fence is needed to prevent reordering of use of the data and - // deletion of the data. Because it is marked `Release`, the decreasing - // of the reference count synchronizes with this `Acquire` fence. This - // means that use of the data happens before decreasing the reference - // count, which happens before this fence, which happens before the - // deletion of the data. - // - // As explained in the [Boost documentation][1], - // - // > It is important to enforce any possible access to the object in one - // > thread (through an existing reference) to *happen before* deleting - // > the object in a different thread. This is achieved by a "release" - // > operation after dropping a reference (any access to the object - // > through this reference must obviously happened before), and an - // > "acquire" operation before deleting the object. - // - // In particular, while the contents of an Arc are usually immutable, it's - // possible to have interior writes to something like a Mutex. Since a - // Mutex is not acquired when it is deleted, we can't rely on its - // synchronization logic to make writes in thread A visible to a destructor - // running in thread B. - // - // Also note that the Acquire fence here could probably be replaced with an - // Acquire load, which could improve performance in highly-contended - // situations. See [2]. - // - // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) - // [2]: (https://github.com/rust-lang/rust/pull/41714) - atomic::fence(Acquire); - - unsafe { - self.drop_slow(); - } - } -} - -impl Arc { - #[inline] - #[unstable(feature = "rc_downcast", issue = "44608")] - /// Attempt to downcast the `Arc` to a concrete type. - /// - /// # Examples - /// - /// ``` - /// #![feature(rc_downcast)] - /// use std::any::Any; - /// use std::sync::Arc; - /// - /// fn print_if_string(value: Arc) { - /// if let Ok(string) = value.downcast::() { - /// println!("String ({}): {}", string.len(), string); - /// } - /// } - /// - /// fn main() { - /// let my_string = "Hello World".to_string(); - /// print_if_string(Arc::new(my_string)); - /// print_if_string(Arc::new(0i8)); - /// } - /// ``` - pub fn downcast(self) -> Result, Self> - where - T: Any + Send + Sync + 'static, - { - if (*self).is::() { - let ptr = self.ptr.cast::>(); - mem::forget(self); - Ok(Arc { ptr, phantom: PhantomData }) - } else { - Err(self) - } - } -} - -impl Weak { - /// Constructs a new `Weak`, without allocating any memory. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: struct.Weak.html#method.upgrade - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::sync::Weak; - /// - /// let empty: Weak = Weak::new(); - /// assert!(empty.upgrade().is_none()); - /// ``` - #[stable(feature = "downgraded_weak", since = "1.10.0")] - pub fn new() -> Weak { - unsafe { - Weak { - ptr: NonNull::new_unchecked(WEAK_EMPTY as *mut _), - } - } - } -} - -impl Weak { - /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending - /// the lifetime of the value if successful. - /// - /// Returns [`None`] if the value has since been dropped. - /// - /// [`Arc`]: struct.Arc.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// let weak_five = Arc::downgrade(&five); - /// - /// let strong_five: Option> = weak_five.upgrade(); - /// assert!(strong_five.is_some()); - /// - /// // Destroy all strong pointers. - /// drop(strong_five); - /// drop(five); - /// - /// assert!(weak_five.upgrade().is_none()); - /// ``` - #[stable(feature = "arc_weak", since = "1.4.0")] - pub fn upgrade(&self) -> Option> { - // We use a CAS loop to increment the strong count instead of a - // fetch_add because once the count hits 0 it must never be above 0. - let inner = if self.ptr.as_ptr() as *const u8 as usize == WEAK_EMPTY { - return None; - } else { - unsafe { self.ptr.as_ref() } - }; - - // Relaxed load because any write of 0 that we can observe - // leaves the field in a permanently zero state (so a - // "stale" read of 0 is fine), and any other value is - // confirmed via the CAS below. - let mut n = inner.strong.load(Relaxed); - - loop { - if n == 0 { - return None; - } - - // See comments in `Arc::clone` for why we do this (for `mem::forget`). - if n > MAX_REFCOUNT { - unsafe { - abort(); - } - } - - // Relaxed is valid for the same reason it is on Arc's Clone impl - match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) { - Ok(_) => return Some(Arc { - // null checked above - ptr: self.ptr, - phantom: PhantomData, - }), - Err(old) => n = old, - } - } - } -} - -#[stable(feature = "arc_weak", since = "1.4.0")] -impl Clone for Weak { - /// Makes a clone of the `Weak` pointer that points to the same value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Weak}; - /// - /// let weak_five = Arc::downgrade(&Arc::new(5)); - /// - /// Weak::clone(&weak_five); - /// ``` - #[inline] - fn clone(&self) -> Weak { - let inner = if self.ptr.as_ptr() as *const u8 as usize == WEAK_EMPTY { - return Weak { ptr: self.ptr }; - } else { - unsafe { self.ptr.as_ref() } - }; - // See comments in Arc::clone() for why this is relaxed. This can use a - // fetch_add (ignoring the lock) because the weak count is only locked - // where are *no other* weak pointers in existence. (So we can't be - // running this code in that case). - let old_size = inner.weak.fetch_add(1, Relaxed); - - // See comments in Arc::clone() for why we do this (for mem::forget). - if old_size > MAX_REFCOUNT { - unsafe { - abort(); - } - } - - return Weak { ptr: self.ptr }; - } -} - -#[stable(feature = "downgraded_weak", since = "1.10.0")] -impl Default for Weak { - /// Constructs a new `Weak`, without allocating memory. - /// Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: struct.Weak.html#method.upgrade - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::sync::Weak; - /// - /// let empty: Weak = Default::default(); - /// assert!(empty.upgrade().is_none()); - /// ``` - fn default() -> Weak { - Weak::new() - } -} - -#[stable(feature = "arc_weak", since = "1.4.0")] -impl Drop for Weak { - /// Drops the `Weak` pointer. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Weak}; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Arc::new(Foo); - /// let weak_foo = Arc::downgrade(&foo); - /// let other_weak_foo = Weak::clone(&weak_foo); - /// - /// drop(weak_foo); // Doesn't print anything - /// drop(foo); // Prints "dropped!" - /// - /// assert!(other_weak_foo.upgrade().is_none()); - /// ``` - fn drop(&mut self) { - // If we find out that we were the last weak pointer, then its time to - // deallocate the data entirely. See the discussion in Arc::drop() about - // the memory orderings - // - // It's not necessary to check for the locked state here, because the - // weak count can only be locked if there was precisely one weak ref, - // meaning that drop could only subsequently run ON that remaining weak - // ref, which can only happen after the lock is released. - let inner = if self.ptr.as_ptr() as *const u8 as usize == WEAK_EMPTY { - return; - } else { - unsafe { self.ptr.as_ref() } - }; - - if inner.weak.fetch_sub(1, Release) == 1 { - atomic::fence(Acquire); - unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Arc { - /// Equality for two `Arc`s. - /// - /// Two `Arc`s are equal if their inner values are equal. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five == Arc::new(5)); - /// ``` - fn eq(&self, other: &Arc) -> bool { - *(*self) == *(*other) - } - - /// Inequality for two `Arc`s. - /// - /// Two `Arc`s are unequal if their inner values are unequal. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five != Arc::new(6)); - /// ``` - fn ne(&self, other: &Arc) -> bool { - *(*self) != *(*other) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Arc { - /// Partial comparison for two `Arc`s. - /// - /// The two are compared by calling `partial_cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// use std::cmp::Ordering; - /// - /// let five = Arc::new(5); - /// - /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::new(6))); - /// ``` - fn partial_cmp(&self, other: &Arc) -> Option { - (**self).partial_cmp(&**other) - } - - /// Less-than comparison for two `Arc`s. - /// - /// The two are compared by calling `<` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five < Arc::new(6)); - /// ``` - fn lt(&self, other: &Arc) -> bool { - *(*self) < *(*other) - } - - /// 'Less than or equal to' comparison for two `Arc`s. - /// - /// The two are compared by calling `<=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five <= Arc::new(5)); - /// ``` - fn le(&self, other: &Arc) -> bool { - *(*self) <= *(*other) - } - - /// Greater-than comparison for two `Arc`s. - /// - /// The two are compared by calling `>` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five > Arc::new(4)); - /// ``` - fn gt(&self, other: &Arc) -> bool { - *(*self) > *(*other) - } - - /// 'Greater than or equal to' comparison for two `Arc`s. - /// - /// The two are compared by calling `>=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five >= Arc::new(5)); - /// ``` - fn ge(&self, other: &Arc) -> bool { - *(*self) >= *(*other) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Arc { - /// Comparison for two `Arc`s. - /// - /// The two are compared by calling `cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// use std::cmp::Ordering; - /// - /// let five = Arc::new(5); - /// - /// assert_eq!(Ordering::Less, five.cmp(&Arc::new(6))); - /// ``` - fn cmp(&self, other: &Arc) -> Ordering { - (**self).cmp(&**other) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Arc {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Pointer for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&(&**self as *const T), f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for Arc { - /// Creates a new `Arc`, with the `Default` value for `T`. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x: Arc = Default::default(); - /// assert_eq!(*x, 0); - /// ``` - fn default() -> Arc { - Arc::new(Default::default()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Arc { - fn hash(&self, state: &mut H) { - (**self).hash(state) - } -} - -#[stable(feature = "from_for_ptrs", since = "1.6.0")] -impl From for Arc { - fn from(t: T) -> Self { - Arc::new(t) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a, T: Clone> From<&'a [T]> for Arc<[T]> { - #[inline] - fn from(v: &[T]) -> Arc<[T]> { - >::from_slice(v) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a> From<&'a str> for Arc { - #[inline] - fn from(v: &str) -> Arc { - let arc = Arc::<[u8]>::from(v.as_bytes()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const str) } - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From for Arc { - #[inline] - fn from(v: String) -> Arc { - Arc::from(&v[..]) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Arc { - #[inline] - fn from(v: Box) -> Arc { - Arc::from_box(v) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Arc<[T]> { - #[inline] - fn from(mut v: Vec) -> Arc<[T]> { - unsafe { - let arc = Arc::copy_from_slice(&v); - - // Allow the Vec to free its memory, but not destroy its contents - v.set_len(0); - - arc - } - } -} - -#[cfg(test)] -mod tests { - use std::boxed::Box; - use std::clone::Clone; - use std::sync::mpsc::channel; - use std::mem::drop; - use std::ops::Drop; - use std::option::Option; - use std::option::Option::{None, Some}; - use std::sync::atomic; - use std::sync::atomic::Ordering::{Acquire, SeqCst}; - use std::thread; - use std::sync::Mutex; - use std::convert::From; - - use super::{Arc, Weak}; - use vec::Vec; - - struct Canary(*mut atomic::AtomicUsize); - - impl Drop for Canary { - fn drop(&mut self) { - unsafe { - match *self { - Canary(c) => { - (*c).fetch_add(1, SeqCst); - } - } - } - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn manually_share_arc() { - let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let arc_v = Arc::new(v); - - let (tx, rx) = channel(); - - let _t = thread::spawn(move || { - let arc_v: Arc> = rx.recv().unwrap(); - assert_eq!((*arc_v)[3], 4); - }); - - tx.send(arc_v.clone()).unwrap(); - - assert_eq!((*arc_v)[2], 3); - assert_eq!((*arc_v)[4], 5); - } - - #[test] - fn test_arc_get_mut() { - let mut x = Arc::new(3); - *Arc::get_mut(&mut x).unwrap() = 4; - assert_eq!(*x, 4); - let y = x.clone(); - assert!(Arc::get_mut(&mut x).is_none()); - drop(y); - assert!(Arc::get_mut(&mut x).is_some()); - let _w = Arc::downgrade(&x); - assert!(Arc::get_mut(&mut x).is_none()); - } - - #[test] - fn try_unwrap() { - let x = Arc::new(3); - assert_eq!(Arc::try_unwrap(x), Ok(3)); - let x = Arc::new(4); - let _y = x.clone(); - assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); - let x = Arc::new(5); - let _w = Arc::downgrade(&x); - assert_eq!(Arc::try_unwrap(x), Ok(5)); - } - - #[test] - fn into_from_raw() { - let x = Arc::new(box "hello"); - let y = x.clone(); - - let x_ptr = Arc::into_raw(x); - drop(y); - unsafe { - assert_eq!(**x_ptr, "hello"); - - let x = Arc::from_raw(x_ptr); - assert_eq!(**x, "hello"); - - assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); - } - } - - #[test] - fn test_into_from_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let arc: Arc = Arc::from("foo"); - - let ptr = Arc::into_raw(arc.clone()); - let arc2 = unsafe { Arc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert_eq!(arc, arc2); - - let arc: Arc = Arc::new(123); - - let ptr = Arc::into_raw(arc.clone()); - let arc2 = unsafe { Arc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert_eq!(arc2.to_string(), "123"); - } - - #[test] - fn test_cowarc_clone_make_mut() { - let mut cow0 = Arc::new(75); - let mut cow1 = cow0.clone(); - let mut cow2 = cow1.clone(); - - assert!(75 == *Arc::make_mut(&mut cow0)); - assert!(75 == *Arc::make_mut(&mut cow1)); - assert!(75 == *Arc::make_mut(&mut cow2)); - - *Arc::make_mut(&mut cow0) += 1; - *Arc::make_mut(&mut cow1) += 2; - *Arc::make_mut(&mut cow2) += 3; - - assert!(76 == *cow0); - assert!(77 == *cow1); - assert!(78 == *cow2); - - // none should point to the same backing memory - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 != *cow2); - } - - #[test] - fn test_cowarc_clone_unique2() { - let mut cow0 = Arc::new(75); - let cow1 = cow0.clone(); - let cow2 = cow1.clone(); - - assert!(75 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - *Arc::make_mut(&mut cow0) += 1; - assert!(76 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - // cow1 and cow2 should share the same contents - // cow0 should have a unique reference - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 == *cow2); - } - - #[test] - fn test_cowarc_clone_weak() { - let mut cow0 = Arc::new(75); - let cow1_weak = Arc::downgrade(&cow0); - - assert!(75 == *cow0); - assert!(75 == *cow1_weak.upgrade().unwrap()); - - *Arc::make_mut(&mut cow0) += 1; - - assert!(76 == *cow0); - assert!(cow1_weak.upgrade().is_none()); - } - - #[test] - fn test_live() { - let x = Arc::new(5); - let y = Arc::downgrade(&x); - assert!(y.upgrade().is_some()); - } - - #[test] - fn test_dead() { - let x = Arc::new(5); - let y = Arc::downgrade(&x); - drop(x); - assert!(y.upgrade().is_none()); - } - - #[test] - fn weak_self_cyclic() { - struct Cycle { - x: Mutex>>, - } - - let a = Arc::new(Cycle { x: Mutex::new(None) }); - let b = Arc::downgrade(&a.clone()); - *a.x.lock().unwrap() = Some(b); - - // hopefully we don't double-free (or leak)... - } - - #[test] - fn drop_arc() { - let mut canary = atomic::AtomicUsize::new(0); - let x = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); - drop(x); - assert!(canary.load(Acquire) == 1); - } - - #[test] - fn drop_arc_weak() { - let mut canary = atomic::AtomicUsize::new(0); - let arc = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); - let arc_weak = Arc::downgrade(&arc); - assert!(canary.load(Acquire) == 0); - drop(arc); - assert!(canary.load(Acquire) == 1); - drop(arc_weak); - } - - #[test] - fn test_strong_count() { - let a = Arc::new(0); - assert!(Arc::strong_count(&a) == 1); - let w = Arc::downgrade(&a); - assert!(Arc::strong_count(&a) == 1); - let b = w.upgrade().expect(""); - assert!(Arc::strong_count(&b) == 2); - assert!(Arc::strong_count(&a) == 2); - drop(w); - drop(a); - assert!(Arc::strong_count(&b) == 1); - let c = b.clone(); - assert!(Arc::strong_count(&b) == 2); - assert!(Arc::strong_count(&c) == 2); - } - - #[test] - fn test_weak_count() { - let a = Arc::new(0); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 0); - let w = Arc::downgrade(&a); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 1); - let x = w.clone(); - assert!(Arc::weak_count(&a) == 2); - drop(w); - drop(x); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 0); - let c = a.clone(); - assert!(Arc::strong_count(&a) == 2); - assert!(Arc::weak_count(&a) == 0); - let d = Arc::downgrade(&c); - assert!(Arc::weak_count(&c) == 1); - assert!(Arc::strong_count(&c) == 2); - - drop(a); - drop(c); - drop(d); - } - - #[test] - fn show_arc() { - let a = Arc::new(5); - assert_eq!(format!("{:?}", a), "5"); - } - - // Make sure deriving works with Arc - #[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)] - struct Foo { - inner: Arc, - } - - #[test] - fn test_unsized() { - let x: Arc<[i32]> = Arc::new([1, 2, 3]); - assert_eq!(format!("{:?}", x), "[1, 2, 3]"); - let y = Arc::downgrade(&x.clone()); - drop(x); - assert!(y.upgrade().is_none()); - } - - #[test] - fn test_from_owned() { - let foo = 123; - let foo_arc = Arc::from(foo); - assert!(123 == *foo_arc); - } - - #[test] - fn test_new_weak() { - let foo: Weak = Weak::new(); - assert!(foo.upgrade().is_none()); - } - - #[test] - fn test_ptr_eq() { - let five = Arc::new(5); - let same_five = five.clone(); - let other_five = Arc::new(5); - - assert!(Arc::ptr_eq(&five, &same_five)); - assert!(!Arc::ptr_eq(&five, &other_five)); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_weak_count_locked() { - let mut a = Arc::new(atomic::AtomicBool::new(false)); - let a2 = a.clone(); - let t = thread::spawn(move || { - for _i in 0..1000000 { - Arc::get_mut(&mut a); - } - a.store(true, SeqCst); - }); - - while !a2.load(SeqCst) { - let n = Arc::weak_count(&a2); - assert!(n < 2, "bad weak count: {}", n); - } - t.join().unwrap(); - } - - #[test] - fn test_from_str() { - let r: Arc = Arc::from("foo"); - - assert_eq!(&r[..], "foo"); - } - - #[test] - fn test_copy_from_slice() { - let s: &[u32] = &[1, 2, 3]; - let r: Arc<[u32]> = Arc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); - } - - #[test] - fn test_clone_from_slice() { - #[derive(Clone, Debug, Eq, PartialEq)] - struct X(u32); - - let s: &[X] = &[X(1), X(2), X(3)]; - let r: Arc<[X]> = Arc::from(s); - - assert_eq!(&r[..], s); - } - - #[test] - #[should_panic] - fn test_clone_from_slice_panic() { - use std::string::{String, ToString}; - - struct Fail(u32, String); - - impl Clone for Fail { - fn clone(&self) -> Fail { - if self.0 == 2 { - panic!(); - } - Fail(self.0, self.1.clone()) - } - } - - let s: &[Fail] = &[ - Fail(0, "foo".to_string()), - Fail(1, "bar".to_string()), - Fail(2, "baz".to_string()), - ]; - - // Should panic, but not cause memory corruption - let _r: Arc<[Fail]> = Arc::from(s); - } - - #[test] - fn test_from_box() { - let b: Box = box 123; - let r: Arc = Arc::from(b); - - assert_eq!(*r, 123); - } - - #[test] - fn test_from_box_str() { - use std::string::String; - - let s = String::from("foo").into_boxed_str(); - let r: Arc = Arc::from(s); - - assert_eq!(&r[..], "foo"); - } - - #[test] - fn test_from_box_slice() { - let s = vec![1, 2, 3].into_boxed_slice(); - let r: Arc<[u32]> = Arc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); - } - - #[test] - fn test_from_box_trait() { - use std::fmt::Display; - use std::string::ToString; - - let b: Box = box 123; - let r: Arc = Arc::from(b); - - assert_eq!(r.to_string(), "123"); - } - - #[test] - fn test_from_box_trait_zero_sized() { - use std::fmt::Debug; - - let b: Box = box (); - let r: Arc = Arc::from(b); - - assert_eq!(format!("{:?}", r), "()"); - } - - #[test] - fn test_from_vec() { - let v = vec![1, 2, 3]; - let r: Arc<[u32]> = Arc::from(v); - - assert_eq!(&r[..], [1, 2, 3]); - } - - #[test] - fn test_downcast() { - use std::any::Any; - - let r1: Arc = Arc::new(i32::max_value()); - let r2: Arc = Arc::new("abc"); - - assert!(r1.clone().downcast::().is_err()); - - let r1i32 = r1.downcast::(); - assert!(r1i32.is_ok()); - assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value())); - - assert!(r2.clone().downcast::().is_err()); - - let r2str = r2.downcast::<&'static str>(); - assert!(r2str.is_ok()); - assert_eq!(r2str.unwrap(), Arc::new("abc")); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl borrow::Borrow for Arc { - fn borrow(&self) -> &T { - &**self - } -} - -#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsRef for Arc { - fn as_ref(&self) -> &T { - &**self - } -} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 9e1740473fe..8ec5a9ed193 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -40,7 +40,7 @@ //! //! ## Atomically reference counted pointers //! -//! The [`Arc`](arc/index.html) type is the threadsafe equivalent of the `Rc` +//! The [`Arc`](sync/index.html) type is the threadsafe equivalent of the `Rc` //! type. It provides all the same functionality of `Rc`, except it requires //! that the contained type `T` is shareable. Additionally, `Arc` is itself //! sendable while `Rc` is not. @@ -164,7 +164,7 @@ mod boxed { mod boxed_test; pub mod collections; #[cfg(target_has_atomic = "ptr")] -pub mod arc; +pub mod sync; pub mod rc; pub mod raw_vec; diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs new file mode 100644 index 00000000000..2abd9c85c57 --- /dev/null +++ b/src/liballoc/sync.rs @@ -0,0 +1,1936 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "rust1", since = "1.0.0")] + +//! Thread-safe reference-counting pointers. +//! +//! See the [`Arc`][arc] documentation for more details. +//! +//! [arc]: struct.Arc.html + +use core::any::Any; +use core::sync::atomic; +use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; +use core::borrow; +use core::fmt; +use core::cmp::Ordering; +use core::intrinsics::abort; +use core::mem::{self, align_of_val, size_of_val}; +use core::ops::Deref; +use core::ops::CoerceUnsized; +use core::ptr::{self, NonNull}; +use core::marker::{Unsize, PhantomData}; +use core::hash::{Hash, Hasher}; +use core::{isize, usize}; +use core::convert::From; + +use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; +use boxed::Box; +use string::String; +use vec::Vec; + +/// A soft limit on the amount of references that may be made to an `Arc`. +/// +/// Going above this limit will abort your program (although not +/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + +/// A sentinel value that is used for the pointer of `Weak::new()`. +const WEAK_EMPTY: usize = 1; + +/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically +/// Reference Counted'. +/// +/// The type `Arc` provides shared ownership of a value of type `T`, +/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces +/// a new pointer to the same value in the heap. When the last `Arc` +/// pointer to a given value is destroyed, the pointed-to value is +/// also destroyed. +/// +/// Shared references in Rust disallow mutation by default, and `Arc` is no +/// exception: you cannot generally obtain a mutable reference to something +/// inside an `Arc`. If you need to mutate through an `Arc`, use +/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] +/// types. +/// +/// ## Thread Safety +/// +/// Unlike [`Rc`], `Arc` uses atomic operations for its reference +/// counting. This means that it is thread-safe. The disadvantage is that +/// atomic operations are more expensive than ordinary memory accesses. If you +/// are not sharing reference-counted values between threads, consider using +/// [`Rc`] for lower overhead. [`Rc`] is a safe default, because the +/// compiler will catch any attempt to send an [`Rc`] between threads. +/// However, a library might choose `Arc` in order to give library consumers +/// more flexibility. +/// +/// `Arc` will implement [`Send`] and [`Sync`] as long as the `T` implements +/// [`Send`] and [`Sync`]. Why can't you put a non-thread-safe type `T` in an +/// `Arc` to make it thread-safe? This may be a bit counter-intuitive at +/// first: after all, isn't the point of `Arc` thread safety? The key is +/// this: `Arc` makes it thread safe to have multiple ownership of the same +/// data, but it doesn't add thread safety to its data. Consider +/// `Arc<`[`RefCell`]`>`. [`RefCell`] isn't [`Sync`], and if `Arc` was always +/// [`Send`], `Arc<`[`RefCell`]`>` would be as well. But then we'd have a problem: +/// [`RefCell`] is not thread safe; it keeps track of the borrowing count using +/// non-atomic operations. +/// +/// In the end, this means that you may need to pair `Arc` with some sort of +/// [`std::sync`] type, usually [`Mutex`][mutex]. +/// +/// ## Breaking cycles with `Weak` +/// +/// The [`downgrade`][downgrade] method can be used to create a non-owning +/// [`Weak`][weak] pointer. A [`Weak`][weak] pointer can be [`upgrade`][upgrade]d +/// to an `Arc`, but this will return [`None`] if the value has already been +/// dropped. +/// +/// A cycle between `Arc` pointers will never be deallocated. For this reason, +/// [`Weak`][weak] is used to break cycles. For example, a tree could have +/// strong `Arc` pointers from parent nodes to children, and [`Weak`][weak] +/// pointers from children back to their parents. +/// +/// # Cloning references +/// +/// Creating a new reference from an existing reference counted pointer is done using the +/// `Clone` trait implemented for [`Arc`][arc] and [`Weak`][weak]. +/// +/// ``` +/// use std::sync::Arc; +/// let foo = Arc::new(vec![1.0, 2.0, 3.0]); +/// // The two syntaxes below are equivalent. +/// let a = foo.clone(); +/// let b = Arc::clone(&foo); +/// // a and b both point to the same memory location as foo. +/// ``` +/// +/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly +/// the meaning of the code. In the example above, this syntax makes it easier to see that +/// this code is creating a new reference rather than copying the whole content of foo. +/// +/// ## `Deref` behavior +/// +/// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), +/// so you can call `T`'s methods on a value of type `Arc`. To avoid name +/// clashes with `T`'s methods, the methods of `Arc` itself are [associated +/// functions][assoc], called using function-like syntax: +/// +/// ``` +/// use std::sync::Arc; +/// let my_arc = Arc::new(()); +/// +/// Arc::downgrade(&my_arc); +/// ``` +/// +/// [`Weak`][weak] does not auto-dereference to `T`, because the value may have +/// already been destroyed. +/// +/// [arc]: struct.Arc.html +/// [weak]: struct.Weak.html +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone +/// [mutex]: ../../std/sync/struct.Mutex.html +/// [rwlock]: ../../std/sync/struct.RwLock.html +/// [atomic]: ../../std/sync/atomic/index.html +/// [`Send`]: ../../std/marker/trait.Send.html +/// [`Sync`]: ../../std/marker/trait.Sync.html +/// [deref]: ../../std/ops/trait.Deref.html +/// [downgrade]: struct.Arc.html#method.downgrade +/// [upgrade]: struct.Weak.html#method.upgrade +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [assoc]: ../../book/first-edition/method-syntax.html#associated-functions +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`std::sync`]: ../../std/sync/index.html +/// [`Arc::clone(&from)`]: #method.clone +/// +/// # Examples +/// +/// Sharing some immutable data between threads: +/// +// Note that we **do not** run these tests here. The windows builders get super +// unhappy if a thread outlives the main thread and then exits at the same time +// (something deadlocks) so we just avoid this entirely by not running these +// tests. +/// ```no_run +/// use std::sync::Arc; +/// use std::thread; +/// +/// let five = Arc::new(5); +/// +/// for _ in 0..10 { +/// let five = Arc::clone(&five); +/// +/// thread::spawn(move || { +/// println!("{:?}", five); +/// }); +/// } +/// ``` +/// +/// Sharing a mutable [`AtomicUsize`]: +/// +/// [`AtomicUsize`]: ../../std/sync/atomic/struct.AtomicUsize.html +/// +/// ```no_run +/// use std::sync::Arc; +/// use std::sync::atomic::{AtomicUsize, Ordering}; +/// use std::thread; +/// +/// let val = Arc::new(AtomicUsize::new(5)); +/// +/// for _ in 0..10 { +/// let val = Arc::clone(&val); +/// +/// thread::spawn(move || { +/// let v = val.fetch_add(1, Ordering::SeqCst); +/// println!("{:?}", v); +/// }); +/// } +/// ``` +/// +/// See the [`rc` documentation][rc_examples] for more examples of reference +/// counting in general. +/// +/// [rc_examples]: ../../std/rc/index.html#examples +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Arc { + ptr: NonNull>, + phantom: PhantomData, +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for Arc {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for Arc {} + +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U: ?Sized> CoerceUnsized> for Arc {} + +/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. +/// +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. +/// +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Arc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Arc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. +/// +/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. +/// +/// [`Arc`]: struct.Arc.html +/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None +#[stable(feature = "arc_weak", since = "1.4.0")] +pub struct Weak { + // This is a `NonNull` to allow optimizing the size of this type in enums, + // but it is actually not truly "non-null". A `Weak::new()` will set this + // to a sentinel value, instead of needing to allocate some space in the + // heap. + ptr: NonNull>, +} + +#[stable(feature = "arc_weak", since = "1.4.0")] +unsafe impl Send for Weak {} +#[stable(feature = "arc_weak", since = "1.4.0")] +unsafe impl Sync for Weak {} + +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U: ?Sized> CoerceUnsized> for Weak {} + +#[stable(feature = "arc_weak", since = "1.4.0")] +impl fmt::Debug for Weak { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "(Weak)") + } +} + +struct ArcInner { + strong: atomic::AtomicUsize, + + // the value usize::MAX acts as a sentinel for temporarily "locking" the + // ability to upgrade weak pointers or downgrade strong ones; this is used + // to avoid races in `make_mut` and `get_mut`. + weak: atomic::AtomicUsize, + + data: T, +} + +unsafe impl Send for ArcInner {} +unsafe impl Sync for ArcInner {} + +impl Arc { + /// Constructs a new `Arc`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(data: T) -> Arc { + // Start the weak pointer count as 1 which is the weak pointer that's + // held by all the strong pointers (kinda), see std/rc.rs for more info + let x: Box<_> = box ArcInner { + strong: atomic::AtomicUsize::new(1), + weak: atomic::AtomicUsize::new(1), + data, + }; + Arc { ptr: Box::into_raw_non_null(x), phantom: PhantomData } + } + + /// Returns the contained value, if the `Arc` has exactly one strong reference. + /// + /// Otherwise, an [`Err`][result] is returned with the same `Arc` that was + /// passed in. + /// + /// This will succeed even if there are outstanding weak references. + /// + /// [result]: ../../std/result/enum.Result.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new(3); + /// assert_eq!(Arc::try_unwrap(x), Ok(3)); + /// + /// let x = Arc::new(4); + /// let _y = Arc::clone(&x); + /// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4); + /// ``` + #[inline] + #[stable(feature = "arc_unique", since = "1.4.0")] + pub fn try_unwrap(this: Self) -> Result { + // See `drop` for why all these atomics are like this + if this.inner().strong.compare_exchange(1, 0, Release, Relaxed).is_err() { + return Err(this); + } + + atomic::fence(Acquire); + + unsafe { + let elem = ptr::read(&this.ptr.as_ref().data); + + // Make a weak pointer to clean up the implicit strong-weak reference + let _weak = Weak { ptr: this.ptr }; + mem::forget(this); + + Ok(elem) + } + } +} + +impl Arc { + /// Consumes the `Arc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` using + /// [`Arc::from_raw`][from_raw]. + /// + /// [from_raw]: struct.Arc.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// assert_eq!(unsafe { *x_ptr }, 10); + /// ``` + #[stable(feature = "rc_raw", since = "1.17.0")] + pub fn into_raw(this: Self) -> *const T { + let ptr: *const T = &*this; + mem::forget(this); + ptr + } + + /// Constructs an `Arc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to a + /// [`Arc::into_raw`][into_raw]. + /// + /// This function is unsafe because improper use may lead to memory problems. For example, a + /// double-free may occur if the function is called twice on the same raw pointer. + /// + /// [into_raw]: struct.Arc.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Arc` to prevent leak. + /// let x = Arc::from_raw(x_ptr); + /// assert_eq!(*x, 10); + /// + /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + #[stable(feature = "rc_raw", since = "1.17.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + // Align the unsized value to the end of the ArcInner. + // Because it is ?Sized, it will always be the last field in memory. + let align = align_of_val(&*ptr); + let layout = Layout::new::>(); + let offset = (layout.size() + layout.padding_needed_for(align)) as isize; + + // Reverse the offset to find the original ArcInner. + let fake_ptr = ptr as *mut ArcInner; + let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + + Arc { + ptr: NonNull::new_unchecked(arc_ptr), + phantom: PhantomData, + } + } + + /// Creates a new [`Weak`][weak] pointer to this value. + /// + /// [weak]: struct.Weak.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// let weak_five = Arc::downgrade(&five); + /// ``` + #[stable(feature = "arc_weak", since = "1.4.0")] + pub fn downgrade(this: &Self) -> Weak { + // This Relaxed is OK because we're checking the value in the CAS + // below. + let mut cur = this.inner().weak.load(Relaxed); + + loop { + // check if the weak counter is currently "locked"; if so, spin. + if cur == usize::MAX { + cur = this.inner().weak.load(Relaxed); + continue; + } + + // NOTE: this code currently ignores the possibility of overflow + // into usize::MAX; in general both Rc and Arc need to be adjusted + // to deal with overflow. + + // Unlike with Clone(), we need this to be an Acquire read to + // synchronize with the write coming from `is_unique`, so that the + // events prior to that write happen before this read. + match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) { + Ok(_) => return Weak { ptr: this.ptr }, + Err(old) => cur = old, + } + } + } + + /// Gets the number of [`Weak`][weak] pointers to this value. + /// + /// [weak]: struct.Weak.html + /// + /// # Safety + /// + /// This method by itself is safe, but using it correctly requires extra care. + /// Another thread can change the weak count at any time, + /// including potentially between calling this method and acting on the result. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let _weak_five = Arc::downgrade(&five); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` or `Weak` between threads. + /// assert_eq!(1, Arc::weak_count(&five)); + /// ``` + #[inline] + #[stable(feature = "arc_counts", since = "1.15.0")] + pub fn weak_count(this: &Self) -> usize { + let cnt = this.inner().weak.load(SeqCst); + // If the weak count is currently locked, the value of the + // count was 0 just before taking the lock. + if cnt == usize::MAX { 0 } else { cnt - 1 } + } + + /// Gets the number of strong (`Arc`) pointers to this value. + /// + /// # Safety + /// + /// This method by itself is safe, but using it correctly requires extra care. + /// Another thread can change the strong count at any time, + /// including potentially between calling this method and acting on the result. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let _also_five = Arc::clone(&five); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` between threads. + /// assert_eq!(2, Arc::strong_count(&five)); + /// ``` + #[inline] + #[stable(feature = "arc_counts", since = "1.15.0")] + pub fn strong_count(this: &Self) -> usize { + this.inner().strong.load(SeqCst) + } + + #[inline] + fn inner(&self) -> &ArcInner { + // This unsafety is ok because while this arc is alive we're guaranteed + // that the inner pointer is valid. Furthermore, we know that the + // `ArcInner` structure itself is `Sync` because the inner data is + // `Sync` as well, so we're ok loaning out an immutable pointer to these + // contents. + unsafe { self.ptr.as_ref() } + } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + // Destroy the data at this time, even though we may not free the box + // allocation itself (there may still be weak pointers lying around). + ptr::drop_in_place(&mut self.ptr.as_mut().data); + + if self.inner().weak.fetch_sub(1, Release) == 1 { + atomic::fence(Acquire); + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) + } + } + + #[inline] + #[stable(feature = "ptr_eq", since = "1.17.0")] + /// Returns true if the two `Arc`s point to the same value (not + /// just values that compare as equal). + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let same_five = Arc::clone(&five); + /// let other_five = Arc::new(5); + /// + /// assert!(Arc::ptr_eq(&five, &same_five)); + /// assert!(!Arc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + this.ptr.as_ptr() == other.ptr.as_ptr() + } +} + +impl Arc { + // Allocates an `ArcInner` with sufficient space for an unsized value + unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { + // Create a fake ArcInner to find allocation size and alignment + let fake_ptr = ptr as *mut ArcInner; + + let layout = Layout::for_value(&*fake_ptr); + + let mem = Global.alloc(layout) + .unwrap_or_else(|_| handle_alloc_error(layout)); + + // Initialize the real ArcInner + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; + + ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); + ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + + inner + } + + fn from_box(v: Box) -> Arc { + unsafe { + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); + + let value_size = size_of_val(&*bptr); + let ptr = Self::allocate_for_ptr(bptr); + + // Copy value as bytes + ptr::copy_nonoverlapping( + bptr as *const T as *const u8, + &mut (*ptr).data as *mut _ as *mut u8, + value_size); + + // Free the allocation without dropping its contents + box_free(box_unique); + + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } + } + } +} + +// Sets the data pointer of a `?Sized` raw pointer. +// +// For a slice/trait object, this sets the `data` field and leaves the rest +// unchanged. For a sized raw pointer, this simply sets the pointer. +unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { + ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + ptr +} + +impl Arc<[T]> { + // Copy elements from slice into newly allocated Arc<[T]> + // + // Unsafe because the caller must either take ownership or bind `T: Copy` + unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { + let v_ptr = v as *const [T]; + let ptr = Self::allocate_for_ptr(v_ptr); + + ptr::copy_nonoverlapping( + v.as_ptr(), + &mut (*ptr).data as *mut [T] as *mut T, + v.len()); + + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } + } +} + +// Specialization trait used for From<&[T]> +trait ArcFromSlice { + fn from_slice(slice: &[T]) -> Self; +} + +impl ArcFromSlice for Arc<[T]> { + #[inline] + default fn from_slice(v: &[T]) -> Self { + // Panic guard while cloning T elements. + // In the event of a panic, elements that have been written + // into the new ArcInner will be dropped, then the memory freed. + struct Guard { + mem: NonNull, + elems: *mut T, + layout: Layout, + n_elems: usize, + } + + impl Drop for Guard { + fn drop(&mut self) { + use core::slice::from_raw_parts_mut; + + unsafe { + let slice = from_raw_parts_mut(self.elems, self.n_elems); + ptr::drop_in_place(slice); + + Global.dealloc(self.mem.cast(), self.layout.clone()); + } + } + } + + unsafe { + let v_ptr = v as *const [T]; + let ptr = Self::allocate_for_ptr(v_ptr); + + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value(&*ptr); + + // Pointer to first element + let elems = &mut (*ptr).data as *mut [T] as *mut T; + + let mut guard = Guard{ + mem: NonNull::new_unchecked(mem), + elems: elems, + layout: layout, + n_elems: 0, + }; + + for (i, item) in v.iter().enumerate() { + ptr::write(elems.offset(i as isize), item.clone()); + guard.n_elems += 1; + } + + // All clear. Forget the guard so it doesn't free the new ArcInner. + mem::forget(guard); + + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } + } + } +} + +impl ArcFromSlice for Arc<[T]> { + #[inline] + fn from_slice(v: &[T]) -> Self { + unsafe { Arc::copy_from_slice(v) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Arc { + /// Makes a clone of the `Arc` pointer. + /// + /// This creates another pointer to the same inner value, increasing the + /// strong reference count. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// Arc::clone(&five); + /// ``` + #[inline] + fn clone(&self) -> Arc { + // Using a relaxed ordering is alright here, as knowledge of the + // original reference prevents other threads from erroneously deleting + // the object. + // + // As explained in the [Boost documentation][1], Increasing the + // reference counter can always be done with memory_order_relaxed: New + // references to an object can only be formed from an existing + // reference, and passing an existing reference from one thread to + // another must already provide any required synchronization. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + let old_size = self.inner().strong.fetch_add(1, Relaxed); + + // However we need to guard against massive refcounts in case someone + // is `mem::forget`ing Arcs. If we don't do this the count can overflow + // and users will use-after free. We racily saturate to `isize::MAX` on + // the assumption that there aren't ~2 billion threads incrementing + // the reference count at once. This branch will never be taken in + // any realistic program. + // + // We abort because such a program is incredibly degenerate, and we + // don't care to support it. + if old_size > MAX_REFCOUNT { + unsafe { + abort(); + } + } + + Arc { ptr: self.ptr, phantom: PhantomData } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Deref for Arc { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.inner().data + } +} + +impl Arc { + /// Makes a mutable reference into the given `Arc`. + /// + /// If there are other `Arc` or [`Weak`][weak] pointers to the same value, + /// then `make_mut` will invoke [`clone`][clone] on the inner value to + /// ensure unique ownership. This is also referred to as clone-on-write. + /// + /// See also [`get_mut`][get_mut], which will fail rather than cloning. + /// + /// [weak]: struct.Weak.html + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [get_mut]: struct.Arc.html#method.get_mut + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let mut data = Arc::new(5); + /// + /// *Arc::make_mut(&mut data) += 1; // Won't clone anything + /// let mut other_data = Arc::clone(&data); // Won't clone inner data + /// *Arc::make_mut(&mut data) += 1; // Clones inner data + /// *Arc::make_mut(&mut data) += 1; // Won't clone anything + /// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything + /// + /// // Now `data` and `other_data` point to different values. + /// assert_eq!(*data, 8); + /// assert_eq!(*other_data, 12); + /// ``` + #[inline] + #[stable(feature = "arc_unique", since = "1.4.0")] + pub fn make_mut(this: &mut Self) -> &mut T { + // Note that we hold both a strong reference and a weak reference. + // Thus, releasing our strong reference only will not, by itself, cause + // the memory to be deallocated. + // + // Use Acquire to ensure that we see any writes to `weak` that happen + // before release writes (i.e., decrements) to `strong`. Since we hold a + // weak count, there's no chance the ArcInner itself could be + // deallocated. + if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() { + // Another strong pointer exists; clone + *this = Arc::new((**this).clone()); + } else if this.inner().weak.load(Relaxed) != 1 { + // Relaxed suffices in the above because this is fundamentally an + // optimization: we are always racing with weak pointers being + // dropped. Worst case, we end up allocated a new Arc unnecessarily. + + // We removed the last strong ref, but there are additional weak + // refs remaining. We'll move the contents to a new Arc, and + // invalidate the other weak refs. + + // Note that it is not possible for the read of `weak` to yield + // usize::MAX (i.e., locked), since the weak count can only be + // locked by a thread with a strong reference. + + // Materialize our own implicit weak pointer, so that it can clean + // up the ArcInner as needed. + let weak = Weak { ptr: this.ptr }; + + // mark the data itself as already deallocated + unsafe { + // there is no data race in the implicit write caused by `read` + // here (due to zeroing) because data is no longer accessed by + // other threads (due to there being no more strong refs at this + // point). + let mut swap = Arc::new(ptr::read(&weak.ptr.as_ref().data)); + mem::swap(this, &mut swap); + mem::forget(swap); + } + } else { + // We were the sole reference of either kind; bump back up the + // strong ref count. + this.inner().strong.store(1, Release); + } + + // As with `get_mut()`, the unsafety is ok because our reference was + // either unique to begin with, or became one upon cloning the contents. + unsafe { + &mut this.ptr.as_mut().data + } + } +} + +impl Arc { + /// Returns a mutable reference to the inner value, if there are + /// no other `Arc` or [`Weak`][weak] pointers to the same value. + /// + /// Returns [`None`][option] otherwise, because it is not safe to + /// mutate a shared value. + /// + /// See also [`make_mut`][make_mut], which will [`clone`][clone] + /// the inner value when it's shared. + /// + /// [weak]: struct.Weak.html + /// [option]: ../../std/option/enum.Option.html + /// [make_mut]: struct.Arc.html#method.make_mut + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let mut x = Arc::new(3); + /// *Arc::get_mut(&mut x).unwrap() = 4; + /// assert_eq!(*x, 4); + /// + /// let _y = Arc::clone(&x); + /// assert!(Arc::get_mut(&mut x).is_none()); + /// ``` + #[inline] + #[stable(feature = "arc_unique", since = "1.4.0")] + pub fn get_mut(this: &mut Self) -> Option<&mut T> { + if this.is_unique() { + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + unsafe { + Some(&mut this.ptr.as_mut().data) + } + } else { + None + } + } + + /// Determine whether this is the unique reference (including weak refs) to + /// the underlying data. + /// + /// Note that this requires locking the weak ref count. + fn is_unique(&mut self) -> bool { + // lock the weak pointer count if we appear to be the sole weak pointer + // holder. + // + // The acquire label here ensures a happens-before relationship with any + // writes to `strong` prior to decrements of the `weak` count (via drop, + // which uses Release). + if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() { + // Due to the previous acquire read, this will observe any writes to + // `strong` that were due to upgrading weak pointers; only strong + // clones remain, which require that the strong count is > 1 anyway. + let unique = self.inner().strong.load(Relaxed) == 1; + + // The release write here synchronizes with a read in `downgrade`, + // effectively preventing the above read of `strong` from happening + // after the write. + self.inner().weak.store(1, Release); // release the lock + unique + } else { + false + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { + /// Drops the `Arc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count reaches zero then the only other references (if any) are + /// [`Weak`][weak], so we `drop` the inner value. + /// + /// [weak]: struct.Weak.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Arc::new(Foo); + /// let foo2 = Arc::clone(&foo); + /// + /// drop(foo); // Doesn't print anything + /// drop(foo2); // Prints "dropped!" + /// ``` + #[inline] + fn drop(&mut self) { + // Because `fetch_sub` is already atomic, we do not need to synchronize + // with other threads unless we are going to delete the object. This + // same logic applies to the below `fetch_sub` to the `weak` count. + if self.inner().strong.fetch_sub(1, Release) != 1 { + return; + } + + // This fence is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` fence. This + // means that use of the data happens before decreasing the reference + // count, which happens before this fence, which happens before the + // deletion of the data. + // + // As explained in the [Boost documentation][1], + // + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. + // + // In particular, while the contents of an Arc are usually immutable, it's + // possible to have interior writes to something like a Mutex. Since a + // Mutex is not acquired when it is deleted, we can't rely on its + // synchronization logic to make writes in thread A visible to a destructor + // running in thread B. + // + // Also note that the Acquire fence here could probably be replaced with an + // Acquire load, which could improve performance in highly-contended + // situations. See [2]. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + // [2]: (https://github.com/rust-lang/rust/pull/41714) + atomic::fence(Acquire); + + unsafe { + self.drop_slow(); + } + } +} + +impl Arc { + #[inline] + #[unstable(feature = "rc_downcast", issue = "44608")] + /// Attempt to downcast the `Arc` to a concrete type. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_downcast)] + /// use std::any::Any; + /// use std::sync::Arc; + /// + /// fn print_if_string(value: Arc) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// fn main() { + /// let my_string = "Hello World".to_string(); + /// print_if_string(Arc::new(my_string)); + /// print_if_string(Arc::new(0i8)); + /// } + /// ``` + pub fn downcast(self) -> Result, Self> + where + T: Any + Send + Sync + 'static, + { + if (*self).is::() { + let ptr = self.ptr.cast::>(); + mem::forget(self); + Ok(Arc { ptr, phantom: PhantomData }) + } else { + Err(self) + } + } +} + +impl Weak { + /// Constructs a new `Weak`, without allocating any memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::sync::Weak; + /// + /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); + /// ``` + #[stable(feature = "downgraded_weak", since = "1.10.0")] + pub fn new() -> Weak { + unsafe { + Weak { + ptr: NonNull::new_unchecked(WEAK_EMPTY as *mut _), + } + } + } +} + +impl Weak { + /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending + /// the lifetime of the value if successful. + /// + /// Returns [`None`] if the value has since been dropped. + /// + /// [`Arc`]: struct.Arc.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// let weak_five = Arc::downgrade(&five); + /// + /// let strong_five: Option> = weak_five.upgrade(); + /// assert!(strong_five.is_some()); + /// + /// // Destroy all strong pointers. + /// drop(strong_five); + /// drop(five); + /// + /// assert!(weak_five.upgrade().is_none()); + /// ``` + #[stable(feature = "arc_weak", since = "1.4.0")] + pub fn upgrade(&self) -> Option> { + // We use a CAS loop to increment the strong count instead of a + // fetch_add because once the count hits 0 it must never be above 0. + let inner = if self.ptr.as_ptr() as *const u8 as usize == WEAK_EMPTY { + return None; + } else { + unsafe { self.ptr.as_ref() } + }; + + // Relaxed load because any write of 0 that we can observe + // leaves the field in a permanently zero state (so a + // "stale" read of 0 is fine), and any other value is + // confirmed via the CAS below. + let mut n = inner.strong.load(Relaxed); + + loop { + if n == 0 { + return None; + } + + // See comments in `Arc::clone` for why we do this (for `mem::forget`). + if n > MAX_REFCOUNT { + unsafe { + abort(); + } + } + + // Relaxed is valid for the same reason it is on Arc's Clone impl + match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) { + Ok(_) => return Some(Arc { + // null checked above + ptr: self.ptr, + phantom: PhantomData, + }), + Err(old) => n = old, + } + } + } +} + +#[stable(feature = "arc_weak", since = "1.4.0")] +impl Clone for Weak { + /// Makes a clone of the `Weak` pointer that points to the same value. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Weak}; + /// + /// let weak_five = Arc::downgrade(&Arc::new(5)); + /// + /// Weak::clone(&weak_five); + /// ``` + #[inline] + fn clone(&self) -> Weak { + let inner = if self.ptr.as_ptr() as *const u8 as usize == WEAK_EMPTY { + return Weak { ptr: self.ptr }; + } else { + unsafe { self.ptr.as_ref() } + }; + // See comments in Arc::clone() for why this is relaxed. This can use a + // fetch_add (ignoring the lock) because the weak count is only locked + // where are *no other* weak pointers in existence. (So we can't be + // running this code in that case). + let old_size = inner.weak.fetch_add(1, Relaxed); + + // See comments in Arc::clone() for why we do this (for mem::forget). + if old_size > MAX_REFCOUNT { + unsafe { + abort(); + } + } + + return Weak { ptr: self.ptr }; + } +} + +#[stable(feature = "downgraded_weak", since = "1.10.0")] +impl Default for Weak { + /// Constructs a new `Weak`, without allocating memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::sync::Weak; + /// + /// let empty: Weak = Default::default(); + /// assert!(empty.upgrade().is_none()); + /// ``` + fn default() -> Weak { + Weak::new() + } +} + +#[stable(feature = "arc_weak", since = "1.4.0")] +impl Drop for Weak { + /// Drops the `Weak` pointer. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Weak}; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Arc::new(Foo); + /// let weak_foo = Arc::downgrade(&foo); + /// let other_weak_foo = Weak::clone(&weak_foo); + /// + /// drop(weak_foo); // Doesn't print anything + /// drop(foo); // Prints "dropped!" + /// + /// assert!(other_weak_foo.upgrade().is_none()); + /// ``` + fn drop(&mut self) { + // If we find out that we were the last weak pointer, then its time to + // deallocate the data entirely. See the discussion in Arc::drop() about + // the memory orderings + // + // It's not necessary to check for the locked state here, because the + // weak count can only be locked if there was precisely one weak ref, + // meaning that drop could only subsequently run ON that remaining weak + // ref, which can only happen after the lock is released. + let inner = if self.ptr.as_ptr() as *const u8 as usize == WEAK_EMPTY { + return; + } else { + unsafe { self.ptr.as_ref() } + }; + + if inner.weak.fetch_sub(1, Release) == 1 { + atomic::fence(Acquire); + unsafe { + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Arc { + /// Equality for two `Arc`s. + /// + /// Two `Arc`s are equal if their inner values are equal. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five == Arc::new(5)); + /// ``` + fn eq(&self, other: &Arc) -> bool { + *(*self) == *(*other) + } + + /// Inequality for two `Arc`s. + /// + /// Two `Arc`s are unequal if their inner values are unequal. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five != Arc::new(6)); + /// ``` + fn ne(&self, other: &Arc) -> bool { + *(*self) != *(*other) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Arc { + /// Partial comparison for two `Arc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// use std::cmp::Ordering; + /// + /// let five = Arc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::new(6))); + /// ``` + fn partial_cmp(&self, other: &Arc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `Arc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five < Arc::new(6)); + /// ``` + fn lt(&self, other: &Arc) -> bool { + *(*self) < *(*other) + } + + /// 'Less than or equal to' comparison for two `Arc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five <= Arc::new(5)); + /// ``` + fn le(&self, other: &Arc) -> bool { + *(*self) <= *(*other) + } + + /// Greater-than comparison for two `Arc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five > Arc::new(4)); + /// ``` + fn gt(&self, other: &Arc) -> bool { + *(*self) > *(*other) + } + + /// 'Greater than or equal to' comparison for two `Arc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five >= Arc::new(5)); + /// ``` + fn ge(&self, other: &Arc) -> bool { + *(*self) >= *(*other) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Arc { + /// Comparison for two `Arc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// use std::cmp::Ordering; + /// + /// let five = Arc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&Arc::new(6))); + /// ``` + fn cmp(&self, other: &Arc) -> Ordering { + (**self).cmp(&**other) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Arc {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&(&**self as *const T), f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for Arc { + /// Creates a new `Arc`, with the `Default` value for `T`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x: Arc = Default::default(); + /// assert_eq!(*x, 0); + /// ``` + fn default() -> Arc { + Arc::new(Default::default()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for Arc { + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + +#[stable(feature = "from_for_ptrs", since = "1.6.0")] +impl From for Arc { + fn from(t: T) -> Self { + Arc::new(t) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl<'a, T: Clone> From<&'a [T]> for Arc<[T]> { + #[inline] + fn from(v: &[T]) -> Arc<[T]> { + >::from_slice(v) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl<'a> From<&'a str> for Arc { + #[inline] + fn from(v: &str) -> Arc { + let arc = Arc::<[u8]>::from(v.as_bytes()); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const str) } + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From for Arc { + #[inline] + fn from(v: String) -> Arc { + Arc::from(&v[..]) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Arc { + #[inline] + fn from(v: Box) -> Arc { + Arc::from_box(v) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Arc<[T]> { + #[inline] + fn from(mut v: Vec) -> Arc<[T]> { + unsafe { + let arc = Arc::copy_from_slice(&v); + + // Allow the Vec to free its memory, but not destroy its contents + v.set_len(0); + + arc + } + } +} + +#[cfg(test)] +mod tests { + use std::boxed::Box; + use std::clone::Clone; + use std::sync::mpsc::channel; + use std::mem::drop; + use std::ops::Drop; + use std::option::Option; + use std::option::Option::{None, Some}; + use std::sync::atomic; + use std::sync::atomic::Ordering::{Acquire, SeqCst}; + use std::thread; + use std::sync::Mutex; + use std::convert::From; + + use super::{Arc, Weak}; + use vec::Vec; + + struct Canary(*mut atomic::AtomicUsize); + + impl Drop for Canary { + fn drop(&mut self) { + unsafe { + match *self { + Canary(c) => { + (*c).fetch_add(1, SeqCst); + } + } + } + } + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn manually_share_arc() { + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let arc_v = Arc::new(v); + + let (tx, rx) = channel(); + + let _t = thread::spawn(move || { + let arc_v: Arc> = rx.recv().unwrap(); + assert_eq!((*arc_v)[3], 4); + }); + + tx.send(arc_v.clone()).unwrap(); + + assert_eq!((*arc_v)[2], 3); + assert_eq!((*arc_v)[4], 5); + } + + #[test] + fn test_arc_get_mut() { + let mut x = Arc::new(3); + *Arc::get_mut(&mut x).unwrap() = 4; + assert_eq!(*x, 4); + let y = x.clone(); + assert!(Arc::get_mut(&mut x).is_none()); + drop(y); + assert!(Arc::get_mut(&mut x).is_some()); + let _w = Arc::downgrade(&x); + assert!(Arc::get_mut(&mut x).is_none()); + } + + #[test] + fn try_unwrap() { + let x = Arc::new(3); + assert_eq!(Arc::try_unwrap(x), Ok(3)); + let x = Arc::new(4); + let _y = x.clone(); + assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); + let x = Arc::new(5); + let _w = Arc::downgrade(&x); + assert_eq!(Arc::try_unwrap(x), Ok(5)); + } + + #[test] + fn into_from_raw() { + let x = Arc::new(box "hello"); + let y = x.clone(); + + let x_ptr = Arc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Arc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); + } + } + + #[test] + fn test_into_from_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let arc: Arc = Arc::from("foo"); + + let ptr = Arc::into_raw(arc.clone()); + let arc2 = unsafe { Arc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert_eq!(arc, arc2); + + let arc: Arc = Arc::new(123); + + let ptr = Arc::into_raw(arc.clone()); + let arc2 = unsafe { Arc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert_eq!(arc2.to_string(), "123"); + } + + #[test] + fn test_cowarc_clone_make_mut() { + let mut cow0 = Arc::new(75); + let mut cow1 = cow0.clone(); + let mut cow2 = cow1.clone(); + + assert!(75 == *Arc::make_mut(&mut cow0)); + assert!(75 == *Arc::make_mut(&mut cow1)); + assert!(75 == *Arc::make_mut(&mut cow2)); + + *Arc::make_mut(&mut cow0) += 1; + *Arc::make_mut(&mut cow1) += 2; + *Arc::make_mut(&mut cow2) += 3; + + assert!(76 == *cow0); + assert!(77 == *cow1); + assert!(78 == *cow2); + + // none should point to the same backing memory + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 != *cow2); + } + + #[test] + fn test_cowarc_clone_unique2() { + let mut cow0 = Arc::new(75); + let cow1 = cow0.clone(); + let cow2 = cow1.clone(); + + assert!(75 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + *Arc::make_mut(&mut cow0) += 1; + assert!(76 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + // cow1 and cow2 should share the same contents + // cow0 should have a unique reference + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 == *cow2); + } + + #[test] + fn test_cowarc_clone_weak() { + let mut cow0 = Arc::new(75); + let cow1_weak = Arc::downgrade(&cow0); + + assert!(75 == *cow0); + assert!(75 == *cow1_weak.upgrade().unwrap()); + + *Arc::make_mut(&mut cow0) += 1; + + assert!(76 == *cow0); + assert!(cow1_weak.upgrade().is_none()); + } + + #[test] + fn test_live() { + let x = Arc::new(5); + let y = Arc::downgrade(&x); + assert!(y.upgrade().is_some()); + } + + #[test] + fn test_dead() { + let x = Arc::new(5); + let y = Arc::downgrade(&x); + drop(x); + assert!(y.upgrade().is_none()); + } + + #[test] + fn weak_self_cyclic() { + struct Cycle { + x: Mutex>>, + } + + let a = Arc::new(Cycle { x: Mutex::new(None) }); + let b = Arc::downgrade(&a.clone()); + *a.x.lock().unwrap() = Some(b); + + // hopefully we don't double-free (or leak)... + } + + #[test] + fn drop_arc() { + let mut canary = atomic::AtomicUsize::new(0); + let x = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); + drop(x); + assert!(canary.load(Acquire) == 1); + } + + #[test] + fn drop_arc_weak() { + let mut canary = atomic::AtomicUsize::new(0); + let arc = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); + let arc_weak = Arc::downgrade(&arc); + assert!(canary.load(Acquire) == 0); + drop(arc); + assert!(canary.load(Acquire) == 1); + drop(arc_weak); + } + + #[test] + fn test_strong_count() { + let a = Arc::new(0); + assert!(Arc::strong_count(&a) == 1); + let w = Arc::downgrade(&a); + assert!(Arc::strong_count(&a) == 1); + let b = w.upgrade().expect(""); + assert!(Arc::strong_count(&b) == 2); + assert!(Arc::strong_count(&a) == 2); + drop(w); + drop(a); + assert!(Arc::strong_count(&b) == 1); + let c = b.clone(); + assert!(Arc::strong_count(&b) == 2); + assert!(Arc::strong_count(&c) == 2); + } + + #[test] + fn test_weak_count() { + let a = Arc::new(0); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 0); + let w = Arc::downgrade(&a); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 1); + let x = w.clone(); + assert!(Arc::weak_count(&a) == 2); + drop(w); + drop(x); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 0); + let c = a.clone(); + assert!(Arc::strong_count(&a) == 2); + assert!(Arc::weak_count(&a) == 0); + let d = Arc::downgrade(&c); + assert!(Arc::weak_count(&c) == 1); + assert!(Arc::strong_count(&c) == 2); + + drop(a); + drop(c); + drop(d); + } + + #[test] + fn show_arc() { + let a = Arc::new(5); + assert_eq!(format!("{:?}", a), "5"); + } + + // Make sure deriving works with Arc + #[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)] + struct Foo { + inner: Arc, + } + + #[test] + fn test_unsized() { + let x: Arc<[i32]> = Arc::new([1, 2, 3]); + assert_eq!(format!("{:?}", x), "[1, 2, 3]"); + let y = Arc::downgrade(&x.clone()); + drop(x); + assert!(y.upgrade().is_none()); + } + + #[test] + fn test_from_owned() { + let foo = 123; + let foo_arc = Arc::from(foo); + assert!(123 == *foo_arc); + } + + #[test] + fn test_new_weak() { + let foo: Weak = Weak::new(); + assert!(foo.upgrade().is_none()); + } + + #[test] + fn test_ptr_eq() { + let five = Arc::new(5); + let same_five = five.clone(); + let other_five = Arc::new(5); + + assert!(Arc::ptr_eq(&five, &same_five)); + assert!(!Arc::ptr_eq(&five, &other_five)); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn test_weak_count_locked() { + let mut a = Arc::new(atomic::AtomicBool::new(false)); + let a2 = a.clone(); + let t = thread::spawn(move || { + for _i in 0..1000000 { + Arc::get_mut(&mut a); + } + a.store(true, SeqCst); + }); + + while !a2.load(SeqCst) { + let n = Arc::weak_count(&a2); + assert!(n < 2, "bad weak count: {}", n); + } + t.join().unwrap(); + } + + #[test] + fn test_from_str() { + let r: Arc = Arc::from("foo"); + + assert_eq!(&r[..], "foo"); + } + + #[test] + fn test_copy_from_slice() { + let s: &[u32] = &[1, 2, 3]; + let r: Arc<[u32]> = Arc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); + } + + #[test] + fn test_clone_from_slice() { + #[derive(Clone, Debug, Eq, PartialEq)] + struct X(u32); + + let s: &[X] = &[X(1), X(2), X(3)]; + let r: Arc<[X]> = Arc::from(s); + + assert_eq!(&r[..], s); + } + + #[test] + #[should_panic] + fn test_clone_from_slice_panic() { + use std::string::{String, ToString}; + + struct Fail(u32, String); + + impl Clone for Fail { + fn clone(&self) -> Fail { + if self.0 == 2 { + panic!(); + } + Fail(self.0, self.1.clone()) + } + } + + let s: &[Fail] = &[ + Fail(0, "foo".to_string()), + Fail(1, "bar".to_string()), + Fail(2, "baz".to_string()), + ]; + + // Should panic, but not cause memory corruption + let _r: Arc<[Fail]> = Arc::from(s); + } + + #[test] + fn test_from_box() { + let b: Box = box 123; + let r: Arc = Arc::from(b); + + assert_eq!(*r, 123); + } + + #[test] + fn test_from_box_str() { + use std::string::String; + + let s = String::from("foo").into_boxed_str(); + let r: Arc = Arc::from(s); + + assert_eq!(&r[..], "foo"); + } + + #[test] + fn test_from_box_slice() { + let s = vec![1, 2, 3].into_boxed_slice(); + let r: Arc<[u32]> = Arc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); + } + + #[test] + fn test_from_box_trait() { + use std::fmt::Display; + use std::string::ToString; + + let b: Box = box 123; + let r: Arc = Arc::from(b); + + assert_eq!(r.to_string(), "123"); + } + + #[test] + fn test_from_box_trait_zero_sized() { + use std::fmt::Debug; + + let b: Box = box (); + let r: Arc = Arc::from(b); + + assert_eq!(format!("{:?}", r), "()"); + } + + #[test] + fn test_from_vec() { + let v = vec![1, 2, 3]; + let r: Arc<[u32]> = Arc::from(v); + + assert_eq!(&r[..], [1, 2, 3]); + } + + #[test] + fn test_downcast() { + use std::any::Any; + + let r1: Arc = Arc::new(i32::max_value()); + let r2: Arc = Arc::new("abc"); + + assert!(r1.clone().downcast::().is_err()); + + let r1i32 = r1.downcast::(); + assert!(r1i32.is_ok()); + assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value())); + + assert!(r2.clone().downcast::().is_err()); + + let r2str = r2.downcast::<&'static str>(); + assert!(r2str.is_ok()); + assert_eq!(r2str.unwrap(), Arc::new("abc")); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl borrow::Borrow for Arc { + fn borrow(&self) -> &T { + &**self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsRef for Arc { + fn as_ref(&self) -> &T { + &**self + } +} diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index 7b1947b56b8..f14fe3a20da 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -18,10 +18,10 @@ pub use self::if_arc::*; #[cfg(target_has_atomic = "ptr")] mod if_arc { use super::*; - use arc::Arc; use core::marker::PhantomData; use core::mem; use core::ptr::{self, NonNull}; + use sync::Arc; /// A way of waking up a specific task. /// diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 642b284c6c7..e12ef8d9eda 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -18,7 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc_crate::arc::{Arc, Weak}; +pub use alloc_crate::sync::{Arc, Weak}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; -- cgit 1.4.1-3-g733a5 From 3265189b68c82ea5ccab663a8db7f0449fa90667 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 29 Jun 2018 18:04:26 -0700 Subject: Use in-tree libbacktrace on Fuchsia --- src/libstd/build.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/build.rs b/src/libstd/build.rs index c001e4e8ceb..9d5aebde625 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -22,7 +22,6 @@ fn main() { if cfg!(feature = "backtrace") && !target.contains("cloudabi") && !target.contains("emscripten") && - !target.contains("fuchsia") && !target.contains("msvc") && !target.contains("wasm32") { @@ -68,10 +67,6 @@ fn main() { println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=shell32"); } else if target.contains("fuchsia") { - // use system-provided libbacktrace - if cfg!(feature = "backtrace") { - println!("cargo:rustc-link-lib=backtrace"); - } println!("cargo:rustc-link-lib=zircon"); println!("cargo:rustc-link-lib=fdio"); } else if target.contains("cloudabi") { -- cgit 1.4.1-3-g733a5 From ad97f8b491422d947c1c97d8e9f1bfecdb7f47ba Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 22 Jun 2018 09:48:43 -0600 Subject: Bootstrap from 1.28.0-beta.3 --- src/Cargo.lock | 29 +++--- src/bootstrap/channel.rs | 2 +- src/liballoc/lib.rs | 1 - src/libcore/intrinsics.rs | 4 - src/libcore/lib.rs | 1 - src/libcore/num/mod.rs | 192 -------------------------------------- src/libcore/num/wrapping.rs | 1 - src/libcore/panic.rs | 2 +- src/libcore/panicking.rs | 15 --- src/libcore/ptr.rs | 27 ------ src/libcore/slice/mod.rs | 3 - src/librustc/lib.rs | 1 - src/librustc_asan/lib.rs | 1 - src/librustc_lsan/lib.rs | 1 - src/librustc_metadata/lib.rs | 1 - src/librustc_msan/lib.rs | 1 - src/librustc_save_analysis/lib.rs | 1 - src/librustc_tsan/lib.rs | 1 - src/libstd/lib.rs | 5 +- src/libstd/panicking.rs | 100 +++++++------------- src/stage0.txt | 2 +- src/tools/cargo | 2 +- src/tools/rust-installer | 2 +- 23 files changed, 53 insertions(+), 342 deletions(-) (limited to 'src/libstd') diff --git a/src/Cargo.lock b/src/Cargo.lock index a9339055264..5d09507c41b 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -191,13 +191,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.29.0" +version = "0.30.0" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.17.0", + "crates-io 0.18.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -232,6 +232,7 @@ dependencies = [ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -299,7 +300,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -472,7 +473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crates-io" -version = "0.17.0" +version = "0.18.0" dependencies = [ "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1683,7 +1684,7 @@ dependencies = [ name = "rls" version = "0.128.0" dependencies = [ - "cargo 0.29.0", + "cargo 0.30.0", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.205 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1882,7 +1883,7 @@ dependencies = [ "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax_pos 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1895,7 +1896,7 @@ dependencies = [ "rustc-ap-serialize 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax_pos 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1969,7 +1970,7 @@ dependencies = [ "rustc-ap-rustc_data_structures 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1981,7 +1982,7 @@ dependencies = [ "rustc-ap-rustc_data_structures 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-serialize 164.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2192,7 +2193,7 @@ dependencies = [ "serialize 0.0.0", "syntax_pos 0.0.0", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2783,7 +2784,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2908,7 +2909,7 @@ name = "textwrap" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2984,7 +2985,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-width" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3388,7 +3389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index a2495f68c1f..04d576df955 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -24,7 +24,7 @@ use Build; use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.28.0"; +pub const CFG_RELEASE_NUM: &str = "1.29.0"; pub struct GitInfo { inner: Option, diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ec9b5eba561..42fc716bae2 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -105,7 +105,6 @@ #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] -#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(specialization)] #![feature(split_ascii_whitespace)] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 95f13daf841..89fe2d941a3 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1364,10 +1364,6 @@ extern "rust-intrinsic" { /// source as well as std's catch implementation. pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32; - #[cfg(stage0)] - /// docs my friends, its friday! - pub fn align_offset(ptr: *const (), align: usize) -> usize; - /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 40caee85541..cef126f36e8 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,7 +100,6 @@ #![feature(optin_builtin_traits)] #![feature(prelude_import)] #![feature(repr_simd, platform_intrinsics)] -#![cfg_attr(stage0, feature(repr_transparent))] #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 7e2dd304d7f..e0d267a6ce0 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -267,20 +267,11 @@ $EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } - } - doc_comment! { concat!("Returns the number of zeros in the binary representation of `self`. @@ -292,7 +283,6 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_zeros(self) -> u32 { @@ -300,16 +290,6 @@ Basic usage: } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentatio"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - doc_comment! { concat!("Returns the number of leading zeros in the binary representation of `self`. @@ -324,7 +304,6 @@ assert_eq!(n.leading_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn leading_zeros(self) -> u32 { @@ -332,16 +311,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() - } - } - doc_comment! { concat!("Returns the number of trailing zeros in the binary representation of `self`. @@ -356,7 +325,6 @@ assert_eq!(n.trailing_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { @@ -364,16 +332,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() - } - } - /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// @@ -442,21 +400,12 @@ $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self } - /// Dummy docs. See !stage0 documentation. - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn swap_bytes(self) -> Self { - (self as $UnsignedT).swap_bytes() as Self - } - /// Reverses the bit pattern of the integer. /// /// # Examples @@ -503,7 +452,6 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_be(x: Self) -> Self { @@ -518,16 +466,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts an integer from little endian to the target's endianness. @@ -548,7 +486,6 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_le(x: Self) -> Self { @@ -563,16 +500,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to big endian from the target's endianness. @@ -593,7 +520,6 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_be(self) -> Self { // or not to be? @@ -608,16 +534,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to little endian from the target's endianness. @@ -638,7 +554,6 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_le(self) -> Self { @@ -653,16 +568,6 @@ $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. @@ -2161,7 +2066,6 @@ Basic usage: assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_ones(self) -> u32 { @@ -2169,16 +2073,6 @@ assert_eq!(n.count_ones(), 3);", $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_ones(self) -> u32 { - unsafe { intrinsics::ctpop(self as $ActualT) as u32 } - } - } - doc_comment! { concat!("Returns the number of zeros in the binary representation of `self`. @@ -2190,7 +2084,6 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn count_zeros(self) -> u32 { @@ -2198,16 +2091,6 @@ Basic usage: } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - doc_comment! { concat!("Returns the number of leading zeros in the binary representation of `self`. @@ -2221,7 +2104,6 @@ Basic usage: assert_eq!(n.leading_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn leading_zeros(self) -> u32 { @@ -2229,16 +2111,6 @@ assert_eq!(n.leading_zeros(), 2);", $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn leading_zeros(self) -> u32 { - unsafe { intrinsics::ctlz(self as $ActualT) as u32 } - } - } - doc_comment! { concat!("Returns the number of trailing zeros in the binary representation of `self`. @@ -2253,7 +2125,6 @@ Basic usage: assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { @@ -2261,16 +2132,6 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn trailing_zeros(self) -> u32 { - unsafe { uint_cttz_call!(self, $BITS) as u32 } - } - } - /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// @@ -2343,21 +2204,12 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn swap_bytes(self) -> Self { unsafe { intrinsics::bswap(self as $ActualT) as Self } } - /// Dummy docs. See !stage0 documentation. - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn swap_bytes(self) -> Self { - unsafe { intrinsics::bswap(self as $ActualT) as Self } - } - /// Reverses the bit pattern of the integer. /// /// # Examples @@ -2404,7 +2256,6 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_be(x: Self) -> Self { @@ -2419,16 +2270,6 @@ if cfg!(target_endian = \"big\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts an integer from little endian to the target's endianness. @@ -2449,7 +2290,6 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn from_le(x: Self) -> Self { @@ -2464,16 +2304,6 @@ if cfg!(target_endian = \"little\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to big endian from the target's endianness. @@ -2494,7 +2324,6 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_be(self) -> Self { // or not to be? @@ -2509,16 +2338,6 @@ if cfg!(target_endian = \"big\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Converts `self` to little endian from the target's endianness. @@ -2539,7 +2358,6 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(not(stage0))] #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn to_le(self) -> Self { @@ -2554,16 +2372,6 @@ if cfg!(target_endian = \"little\") { } } - doc_comment! { - concat!("Dummy docs. See !stage0 documentation"), - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(stage0)] - #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } - } - } - doc_comment! { concat!("Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred. diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index d7f87d37f5b..1c826c2fa76 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -531,7 +531,6 @@ assert_eq!(n.trailing_zeros(), 3); /// assert_eq!(m, Wrapping(-22016)); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { Wrapping(self.0.reverse_bits()) diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 37ae05309af..1b4129b99fc 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -35,7 +35,7 @@ use fmt; /// /// panic!("Normal panic"); /// ``` -#[cfg_attr(not(stage0), lang = "panic_info")] +#[lang = "panic_info"] #[stable(feature = "panic_hooks", since = "1.10.0")] #[derive(Debug)] pub struct PanicInfo<'a> { diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 0d4f8d1141e..58407de9566 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -37,7 +37,6 @@ issue = "0")] use fmt; -#[cfg(not(stage0))] use panic::{Location, PanicInfo}; #[cold] #[inline(never)] // this is the slow path, always @@ -61,20 +60,6 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), len, index), file_line_col) } -#[cfg(stage0)] -#[cold] #[inline(never)] -pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - #[allow(improper_ctypes)] - extern { - #[lang = "panic_fmt"] - #[unwind(allowed)] - fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; - } - let (file, line, col) = *file_line_col; - unsafe { panic_impl(fmt, file, line, col) } -} - -#[cfg(not(stage0))] #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 81a8b3ef047..164b29d3515 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1243,7 +1243,6 @@ impl *const T { /// # } } /// ``` #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(not(stage0))] pub fn align_offset(self, align: usize) -> usize where T: Sized { if !align.is_power_of_two() { panic!("align_offset: align is not a power-of-two"); @@ -1252,18 +1251,6 @@ impl *const T { align_offset(self, align) } } - - /// definitely docs. - #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(stage0)] - pub fn align_offset(self, align: usize) -> usize where T: Sized { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { - intrinsics::align_offset(self as *const (), align) - } - } } @@ -2308,7 +2295,6 @@ impl *mut T { /// # } } /// ``` #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(not(stage0))] pub fn align_offset(self, align: usize) -> usize where T: Sized { if !align.is_power_of_two() { panic!("align_offset: align is not a power-of-two"); @@ -2317,18 +2303,6 @@ impl *mut T { align_offset(self, align) } } - - /// definitely docs. - #[unstable(feature = "align_offset", issue = "44488")] - #[cfg(stage0)] - pub fn align_offset(self, align: usize) -> usize where T: Sized { - if !align.is_power_of_two() { - panic!("align_offset: align is not a power-of-two"); - } - unsafe { - intrinsics::align_offset(self as *const (), align) - } - } } /// Align pointer `p`. @@ -2346,7 +2320,6 @@ impl *mut T { /// /// Any questions go to @nagisa. #[lang="align_offset"] -#[cfg(not(stage0))] pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { /// Calculate multiplicative modular inverse of `x` modulo `m`. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index e74e527927d..bcac9322ae8 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1708,7 +1708,6 @@ impl [T] { } /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`. - #[cfg(not(stage0))] fn align_to_offsets(&self) -> (usize, usize) { // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a // lowest number of `T`s. And how many `T`s we need for each such "multiple". @@ -1798,7 +1797,6 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_align_to", issue = "44488")] - #[cfg(not(stage0))] pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { // Note that most of this function will be constant-evaluated, if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { @@ -1851,7 +1849,6 @@ impl [T] { /// } /// ``` #[unstable(feature = "slice_align_to", issue = "44488")] - #[cfg(not(stage0))] pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { // Note that most of this function will be constant-evaluated, if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 102efe2bef3..95e2d0e2edb 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -49,7 +49,6 @@ #![feature(fs_read_write)] #![feature(iterator_find_map)] #![cfg_attr(windows, feature(libc))] -#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![feature(macro_vis_matcher)] #![feature(never_type)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_lsan/lib.rs +++ b/src/librustc_lsan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 0fbedcaff6e..dad1030cb61 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -16,7 +16,6 @@ #![feature(fs_read_write)] #![feature(libc)] #![feature(macro_at_most_once_rep)] -#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![feature(proc_macro_internals)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_msan/lib.rs +++ b/src/librustc_msan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 89d30fd666a..4c9cdc1e6d3 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -12,7 +12,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(custom_attribute)] -#![cfg_attr(stage0, feature(macro_lifetime_matcher))] #![allow(unused_attributes)] #![recursion_limit="256"] diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs index a7aeed76309..0c78fd74a23 100644 --- a/src/librustc_tsan/lib.rs +++ b/src/librustc_tsan/lib.rs @@ -10,7 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![cfg_attr(stage0, feature(global_allocator))] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index caad924ea5b..d73cb1f8349 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -322,7 +322,7 @@ #![feature(doc_keyword)] #![feature(float_internals)] #![feature(panic_info_message)] -#![cfg_attr(not(stage0), feature(panic_implementation))] +#![feature(panic_implementation)] #![default_lib_allocator] @@ -332,9 +332,6 @@ // `force_alloc_system` is *only* intended as a workaround for local rebuilds // with a rustc without jemalloc. // FIXME(#44236) shouldn't need MSVC logic -#![cfg_attr(all(not(target_env = "msvc"), - any(all(stage0, not(test)), feature = "force_alloc_system")), - feature(global_allocator))] #[cfg(all(not(target_env = "msvc"), any(all(stage0, not(test)), feature = "force_alloc_system")))] #[global_allocator] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 0808efa2ece..46b6cf60705 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -319,18 +319,6 @@ pub fn panicking() -> bool { /// Entry point of panic from the libcore crate. #[cfg(not(test))] -#[cfg(stage0)] -#[lang = "panic_fmt"] -pub extern fn rust_begin_panic(msg: fmt::Arguments, - file: &'static str, - line: u32, - col: u32) -> ! { - begin_panic_fmt(&msg, &(file, line, col)) -} - -/// Entry point of panic from the libcore crate. -#[cfg(not(test))] -#[cfg(not(stage0))] #[panic_implementation] #[unwind(allowed)] pub fn rust_begin_panic(info: &PanicInfo) -> ! { @@ -343,78 +331,54 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. -#[cfg(stage0)] #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - // We do two allocations here, unfortunately. But (a) they're - // required with the current scheme, and (b) we don't handle - // panic + OOM properly anyway (see comment in begin_panic - // below). - - rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); -} - -// NOTE(stage0) move into `continue_panic_fmt` on next stage0 update -struct PanicPayload<'a> { - inner: &'a fmt::Arguments<'a>, - string: Option, + let (file, line, col) = *file_line_col; + let info = PanicInfo::internal_constructor( + Some(msg), + Location::internal_constructor(file, line, col), + ); + continue_panic_fmt(&info) } -impl<'a> PanicPayload<'a> { - fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { - PanicPayload { inner, string: None } +fn continue_panic_fmt(info: &PanicInfo) -> ! { + struct PanicPayload<'a> { + inner: &'a fmt::Arguments<'a>, + string: Option, } - fn fill(&mut self) -> &mut String { - use fmt::Write; + impl<'a> PanicPayload<'a> { + fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { + PanicPayload { inner, string: None } + } - let inner = self.inner; - self.string.get_or_insert_with(|| { - let mut s = String::new(); - drop(s.write_fmt(*inner)); - s - }) - } -} + fn fill(&mut self) -> &mut String { + use fmt::Write; -unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { - let contents = mem::replace(self.fill(), String::new()); - Box::into_raw(Box::new(contents)) + let inner = self.inner; + self.string.get_or_insert_with(|| { + let mut s = String::new(); + drop(s.write_fmt(*inner)); + s + }) + } } - fn get(&mut self) -> &(Any + Send) { - self.fill() - } -} + unsafe impl<'a> BoxMeUp for PanicPayload<'a> { + fn box_me_up(&mut self) -> *mut (Any + Send) { + let contents = mem::replace(self.fill(), String::new()); + Box::into_raw(Box::new(contents)) + } -/// The entry point for panicking with a formatted message. -/// -/// This is designed to reduce the amount of code required at the call -/// site as much as possible (so that `panic!()` has as low an impact -/// on (e.g.) the inlining of other functions as possible), by moving -/// the actual formatting into this shared place. -#[cfg(not(stage0))] -#[unstable(feature = "libstd_sys_internals", - reason = "used by the panic! macro", - issue = "0")] -#[inline(never)] #[cold] -pub fn begin_panic_fmt(msg: &fmt::Arguments, - file_line_col: &(&'static str, u32, u32)) -> ! { - let (file, line, col) = *file_line_col; - let info = PanicInfo::internal_constructor( - Some(msg), - Location::internal_constructor(file, line, col), - ); - continue_panic_fmt(&info) -} + fn get(&mut self) -> &(Any + Send) { + self.fill() + } + } -#[cfg(not(stage0))] -fn continue_panic_fmt(info: &PanicInfo) -> ! { // We do two allocations here, unfortunately. But (a) they're // required with the current scheme, and (b) we don't handle // panic + OOM properly anyway (see comment in begin_panic diff --git a/src/stage0.txt b/src/stage0.txt index 435cfd2f6db..538f3a85176 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-05-10 +date: 2018-06-30 rustc: beta cargo: beta diff --git a/src/tools/cargo b/src/tools/cargo index e2348c2db29..5699afe508d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit e2348c2db296ce33428933c3ab8786d5f3c54a2e +Subproject commit 5699afe508d62924f6b38b19dc98296ad33d1659 diff --git a/src/tools/rust-installer b/src/tools/rust-installer index 118e078c5ba..89414e44dc9 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit 118e078c5badd520d18b92813fd88789c8d341ab +Subproject commit 89414e44dc94844888e59c08bc31dcccb1792800 -- cgit 1.4.1-3-g733a5 From 73166f751b7509dd95ce903ecdeab2dd5d89aa90 Mon Sep 17 00:00:00 2001 From: Dror Levin Date: Mon, 2 Jul 2018 17:38:15 +0300 Subject: Fill in tracking issue number for read_exact_at/write_all_at --- src/libstd/sys/unix/ext/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 4c2cea0d32c..507e9d88171 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -109,7 +109,7 @@ pub trait FileExt { /// Ok(()) /// } /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "0")] + #[unstable(feature = "rw_exact_all_at", issue = "51984")] fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.read_at(buf, offset) { @@ -204,7 +204,7 @@ pub trait FileExt { /// Ok(()) /// } /// ``` - #[unstable(feature = "rw_exact_all_at", issue = "0")] + #[unstable(feature = "rw_exact_all_at", issue = "51984")] fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { match self.write_at(buf, offset) { -- cgit 1.4.1-3-g733a5 From 9797665b286db3f34cc475560a68380012fadde7 Mon Sep 17 00:00:00 2001 From: Evan Simmons Date: Sun, 1 Jul 2018 14:30:16 -0700 Subject: Make Stdio handle UnwindSafe --- src/libstd/io/stdio.rs | 22 ++++++++++++++++++++++ src/libstd/sys_common/remutex.rs | 4 ++++ 2 files changed, 26 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 2472bed5ba4..fce85a200ba 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -712,9 +712,31 @@ pub fn _eprint(args: fmt::Arguments) { #[cfg(test)] mod tests { + use panic::{UnwindSafe, RefUnwindSafe}; use thread; use super::*; + #[test] + fn stdout_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stdoutlock_unwind_safe() { + assert_unwind_safe::(); + assert_unwind_safe::>(); + } + #[test] + fn stderr_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stderrlock_unwind_safe() { + assert_unwind_safe::(); + assert_unwind_safe::>(); + } + + fn assert_unwind_safe() {} + #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn panic_doesnt_poison() { diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs index 022056f8a8a..071a3a25c7a 100644 --- a/src/libstd/sys_common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -13,6 +13,7 @@ use marker; use ops::Deref; use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; use sys::mutex as sys; +use panic::{UnwindSafe, RefUnwindSafe}; /// A re-entrant mutual exclusion /// @@ -28,6 +29,9 @@ pub struct ReentrantMutex { unsafe impl Send for ReentrantMutex {} unsafe impl Sync for ReentrantMutex {} +impl UnwindSafe for ReentrantMutex {} +impl RefUnwindSafe for ReentrantMutex {} + /// An RAII implementation of a "scoped lock" of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked. -- cgit 1.4.1-3-g733a5 From ea6f9f9c5529bb3f222ccf95c75bc54609cd99b7 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 3 Jul 2018 11:13:16 +0200 Subject: Remove stability attributes on private types and leftover docs --- src/libstd/sys/redox/ext/unixsocket.rs | 2 -- src/libstd/sys/unix/ext/unixsocket.rs | 16 ---------------- 2 files changed, 18 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/unixsocket.rs b/src/libstd/sys/redox/ext/unixsocket.rs index be37575145a..5f7b2df8992 100644 --- a/src/libstd/sys/redox/ext/unixsocket.rs +++ b/src/libstd/sys/redox/ext/unixsocket.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "unix_socket", since = "1.10.0")] - use fmt; use io::{self, Error, ErrorKind, Initializer}; use net::Shutdown; diff --git a/src/libstd/sys/unix/ext/unixsocket.rs b/src/libstd/sys/unix/ext/unixsocket.rs index 124555141a3..ad2d7019cb8 100644 --- a/src/libstd/sys/unix/ext/unixsocket.rs +++ b/src/libstd/sys/unix/ext/unixsocket.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "unix_socket", since = "1.10.0")] - //! Unix-specific networking functionality #[cfg(unix)] @@ -144,20 +142,6 @@ impl<'a> fmt::Display for AsciiEscaped<'a> { } } -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); -/// stream.write_all(b"hello world").unwrap(); -/// let mut response = String::new(); -/// stream.read_to_string(&mut response).unwrap(); -/// println!("{}", response); -/// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub struct UnixStream(Socket); -- cgit 1.4.1-3-g733a5 From cdff2f3b3083f602736653e1428b5113dd2e7eee Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 29 Jun 2018 11:49:32 -0700 Subject: impl Clone for Box, Box, Box Implements #51908. --- src/libstd/ffi/c_str.rs | 8 ++++++++ src/libstd/ffi/os_str.rs | 8 ++++++++ src/libstd/path.rs | 8 ++++++++ 3 files changed, 24 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 6513d11dd51..b816f4b7850 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -706,6 +706,14 @@ impl From> for CString { } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + (**self).into() + } +} + #[stable(feature = "box_from_c_string", since = "1.20.0")] impl From for Box { #[inline] diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 0a3148029d0..b522d134837 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -628,6 +628,14 @@ impl From for Box { } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + self.to_os_string().into_boxed_os_str() + } +} + #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { #[inline] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 3dc1e9c3dad..2d868629278 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1410,6 +1410,14 @@ impl From for Box { } } +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + self.to_path_buf().into_boxed_path() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized + AsRef> From<&'a T> for PathBuf { fn from(s: &'a T) -> PathBuf { -- cgit 1.4.1-3-g733a5 From 0afc16a03942931254c05846f60f3afa00d147c3 Mon Sep 17 00:00:00 2001 From: Simon Ochsenreither Date: Thu, 5 Jul 2018 17:32:09 +0200 Subject: Deprecate `std::env::home_dir` and fix incorrect documentation --- src/libstd/env.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 91e417c64da..c0e1e2533a0 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -512,18 +512,20 @@ impl Error for JoinPathsError { /// /// # Unix /// -/// Returns the value of the 'HOME' environment variable if it is set -/// and not equal to the empty string. Otherwise, it tries to determine the -/// home directory by invoking the `getpwuid_r` function on the UID of the -/// current user. +/// - Returns the value of the 'HOME' environment variable if it is set +/// (including to an empty string). +/// - Otherwise, it tries to determine the home directory by invoking the `getpwuid_r` function +/// using the UID of the current user. An empty home directory field returned from the +/// `getpwuid_r` function is considered to be a valid value. +/// - Returns `None` if the current user has no entry in the /etc/passwd file. /// /// # Windows /// -/// Returns the value of the 'HOME' environment variable if it is -/// set and not equal to the empty string. Otherwise, returns the value of the -/// 'USERPROFILE' environment variable if it is set and not equal to the empty -/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to -/// return the appropriate path. +/// - Returns the value of the 'HOME' environment variable if it is set +/// (including to an empty string). +/// - Otherwise, returns the value of the 'USERPROFILE' environment variable if it is set +/// (including to an empty string). +/// - If both do not exist, [`GetUserProfileDirectory`][msdn] is used to return the path. /// /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx /// @@ -533,10 +535,13 @@ impl Error for JoinPathsError { /// use std::env; /// /// match env::home_dir() { -/// Some(path) => println!("{}", path.display()), +/// Some(path) => println!("Your home directory, probably: {}", path.display()), /// None => println!("Impossible to get your home dir!"), /// } /// ``` +#[rustc_deprecated(since = "1.29.0", + reason = "This function's behavior is unexpected and probably not what you want. \ + Consider using the home_dir function from crates.io/crates/dirs instead.")] #[stable(feature = "env", since = "1.0.0")] pub fn home_dir() -> Option { os_imp::home_dir() -- cgit 1.4.1-3-g733a5 From abac5e722f3786fe2692bde9ab626afb25dd02de Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 7 Jul 2018 06:50:55 +0200 Subject: Revert unification of interfaces --- src/libstd/sys/redox/ext/mod.rs | 1 - src/libstd/sys/redox/ext/net.rs | 695 +++++++++++++++++++++++++++++++- src/libstd/sys/unix/ext/mod.rs | 1 - src/libstd/sys/unix/ext/net.rs | 871 ++++++++++++++++++++++++++++++++++++++-- src/libstd/sys_common/mod.rs | 3 - 5 files changed, 1539 insertions(+), 32 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs index c86b5d78524..cb2c75ae0bf 100644 --- a/src/libstd/sys/redox/ext/mod.rs +++ b/src/libstd/sys/redox/ext/mod.rs @@ -36,7 +36,6 @@ pub mod io; pub mod net; pub mod process; pub mod thread; -pub(crate) mod unixsocket; /// A prelude for conveniently writing platform-specific code. /// diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 16eec67fb87..d29d28c8427 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -8,6 +8,695 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![stable(feature = "unix_socket", since = "1.10.0")] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub use sys_common::unixsocket::*; +#![unstable(feature = "unix_socket_redox", reason = "new feature", issue="51553")] + +//! Unix-specific networking functionality + +use fmt; +use io::{self, Error, ErrorKind, Initializer}; +use net::Shutdown; +use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; +use path::Path; +use time::Duration; +use sys::{cvt, fd::FileDesc, syscall}; + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +pub struct SocketAddr(()); + +impl SocketAddr { + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// ``` + pub fn as_pathname(&self) -> Option<&Path> { + None + } +} +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SocketAddr") + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); +/// stream.write_all(b"hello world").unwrap(); +/// let mut response = String::new(); +/// stream.read_to_string(&mut response).unwrap(); +/// println!("{}", response); +/// ``` +pub struct UnixStream(FileDesc); + +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + pub fn connect>(path: P) -> io::Result { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixStream) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixStream::connect: non-utf8 paths not supported on redox" + )) + } + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new)?; + let client = server.duplicate_path(b"connect")?; + let stream = server.duplicate_path(b"listen")?; + Ok((UnixStream(client), UnixStream(stream))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// ``` + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// ``` + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// ``` + pub fn peer_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + pub fn read_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + pub fn write_timeout(&self) -> io::Result> { + Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// ``` + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + pub fn take_error(&self) -> io::Result> { + Ok(None) + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// ``` + pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { + Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) + } +} + +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(FileDesc::new(fd)) + } +} + +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// ``` +pub struct UnixListener(FileDesc); + +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", &self.0.raw()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + pub fn bind>(path: P) -> io::Result { + if let Some(s) = path.as_ref().to_str() { + cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) + .map(FileDesc::new) + .map(UnixListener) + } else { + Err(Error::new( + ErrorKind::Other, + "UnixListener::bind: non-utf8 paths not supported on redox" + )) + } + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// ``` + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// ``` + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// ``` + pub fn local_addr(&self) -> io::Result { + Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// ``` + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/tmp/sock").unwrap(); + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + pub fn take_error(&self) -> io::Result> { + Ok(None) + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: struct.SocketAddr.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// ``` + pub fn incoming<'a>(&'a self) -> Incoming<'a> { + Incoming { listener: self } + } +} + +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + self.0.raw() + } +} + +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(FileDesc::new(fd)) + } +} + +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw() + } +} + +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// [`None`]: ../../../../std/option/enum.Option.html#variant.None +/// [`UnixListener`]: struct.UnixListener.html +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// ``` +#[derive(Debug)] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) + } +} diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index b7a1b45e9b7..88e4237f8e2 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -44,7 +44,6 @@ pub mod process; pub mod raw; pub mod thread; pub mod net; -pub(crate) mod unixsocket; /// A prelude for conveniently writing platform-specific code. /// diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 9251871baf6..55f43ccd7db 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -25,34 +25,32 @@ mod libc { pub struct sockaddr_un; } +use ascii; +use ffi::OsStr; use fmt; -use io; +use io::{self, Initializer}; use mem; use net::{self, Shutdown}; use os::unix::ffi::OsStrExt; use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; use path::Path; use time::Duration; -use sys::ext::unixsocket as inner; -use sys::net::Socket; use sys::{self, cvt}; +use sys::net::Socket; use sys_common::{self, AsInner, FromInner, IntoInner}; -#[stable(feature = "unix_socket", since = "1.10.0")] -pub use sys_common::unixsocket::*; - #[cfg(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "haiku", target_os = "bitrig"))] -pub(crate) use libc::MSG_NOSIGNAL; +use libc::MSG_NOSIGNAL; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "haiku", target_os = "bitrig")))] -pub(crate) const MSG_NOSIGNAL: libc::c_int = 0x0; +const MSG_NOSIGNAL: libc::c_int = 0x0; -pub(crate) fn sun_path_offset() -> usize { +fn sun_path_offset() -> usize { // Work with an actual instance of the type since using a null pointer is UB let addr: libc::sockaddr_un = unsafe { mem::uninitialized() }; let base = &addr as *const _ as usize; @@ -60,7 +58,7 @@ pub(crate) fn sun_path_offset() -> usize { path - base } -pub(crate) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { +unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { let mut addr: libc::sockaddr_un = mem::zeroed(); addr.sun_family = libc::AF_UNIX as libc::sa_family_t; @@ -89,22 +87,557 @@ pub(crate) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, Ok((addr, len as libc::socklen_t)) } -#[stable(feature = "into_raw_os", since = "1.4.0")] +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct SocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, +} + +impl SocketAddr { + fn new(f: F) -> io::Result + where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int + { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as libc::socklen_t; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + + fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address + } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket")); + } + + Ok(SocketAddr { + addr, + len, + }) + } + + /// Returns true if and only if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + if let AddressKind::Unnamed = self.address() { + true + } else { + false + } + } + + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { + Some(path) + } else { + None + } + } + + fn address<'a>(&'a self) -> AddressKind<'a> { + let len = self.len as usize - sun_path_offset(); + let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} + +struct AsciiEscaped<'a>(&'a [u8]); + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); +/// stream.write_all(b"hello world").unwrap(); +/// let mut response = String::new(); +/// stream.read_to_string(&mut response).unwrap(); +/// println!("{}", response); +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + inner(path.as_ref()) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; + Ok((UnixStream(i1), UnixStream(i2))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err + /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`Duration`]: ../../../../std/time/struct.Duration.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// let socket = UnixStream::connect("/tmp/sock").unwrap(); + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::TcpStream { fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } } -#[stable(feature = "into_raw_os", since = "1.4.0")] +#[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::TcpListener { fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } } -#[stable(feature = "into_raw_os", since = "1.4.0")] +#[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::UdpSocket { fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } } -#[stable(feature = "into_raw_os", since = "1.4.0")] +#[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for net::TcpStream { unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { let socket = sys::net::Socket::from_inner(fd); @@ -112,7 +645,7 @@ impl FromRawFd for net::TcpStream { } } -#[stable(feature = "into_raw_os", since = "1.4.0")] +#[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for net::TcpListener { unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { let socket = sys::net::Socket::from_inner(fd); @@ -120,7 +653,7 @@ impl FromRawFd for net::TcpListener { } } -#[stable(feature = "into_raw_os", since = "1.4.0")] +#[stable(feature = "from_raw_os", since = "1.1.0")] impl FromRawFd for net::UdpSocket { unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { let socket = sys::net::Socket::from_inner(fd); @@ -147,6 +680,300 @@ impl IntoRawFd for net::UdpSocket { } } +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(libc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + inner(path.as_ref()) + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = SocketAddr::from_parts(storage, len)?; + Ok((UnixStream(sock), addr)) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = UnixListener::bind("/tmp/sock").unwrap(); + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns None. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// [`None`]: ../../../../std/option/enum.Option.html#variant.None + /// [`SocketAddr`]: struct.SocketAddr.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming<'a>(&'a self) -> Incoming<'a> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// [`None`]: ../../../../std/option/enum.Option.html#variant.None +/// [`UnixListener`]: struct.UnixListener.html +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::max_value(), None) + } +} + /// A Unix datagram socket. /// /// # Examples @@ -323,9 +1150,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn local_addr(&self) -> io::Result { - inner::SocketAddr::new(|addr, len| unsafe { - libc::getsockname(*self.0.as_inner(), addr, len) - }).map(SocketAddr) + SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) } /// Returns the address of this socket's peer. @@ -346,9 +1171,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn peer_addr(&self) -> io::Result { - inner::SocketAddr::new(|addr, len| unsafe { - libc::getsockname(*self.0.as_inner(), addr, len) - }).map(SocketAddr) + SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } /// Receives data from the socket. @@ -371,7 +1194,7 @@ impl UnixDatagram { #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { let mut count = 0; - let addr = SocketAddr(inner::SocketAddr::new(|addr, len| { + let addr = SocketAddr::new(|addr, len| { unsafe { count = libc::recvfrom(*self.0.as_inner(), buf.as_mut_ptr() as *mut _, @@ -387,7 +1210,7 @@ impl UnixDatagram { -1 } } - })?); + })?; Ok((count as usize, addr)) } diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 89f5fd79f40..d0c4d6a7737 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -55,9 +55,6 @@ pub mod wtf8; pub mod bytestring; pub mod process; -#[cfg(any(all(unix, not(target_os = "emscripten")), target_os = "redox"))] -pub(crate) mod unixsocket; - cfg_if! { if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] { pub use sys::net; -- cgit 1.4.1-3-g733a5 From c007a78d23b684b8edaf624a93ec2d0579a37a86 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 7 Jul 2018 06:52:03 +0200 Subject: Add is_unnamed --- src/libstd/sys/redox/ext/net.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index d29d28c8427..4c5f8574621 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -67,6 +67,33 @@ impl SocketAddr { pub fn as_pathname(&self) -> Option<&Path> { None } + + /// Returns true if and only if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let socket = UnixListener::bind("/tmp/sock").unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// let socket = UnixDatagram::unbound().unwrap(); + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// ``` + pub fn is_unnamed(&self) -> bool { + false + } } impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { -- cgit 1.4.1-3-g733a5 From 5b795cf57e42aa31da7cb175d8ff27633085b5d7 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 7 Jul 2018 23:16:27 +0200 Subject: Reformat std prelude source to show it is the sum of core and alloc preludes --- src/libstd/prelude/v1.rs | 58 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index feedd4e1abe..53763da5e28 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -12,42 +12,68 @@ //! //! See the [module-level documentation](../index.html) for more. + + #![stable(feature = "rust1", since = "1.0.0")] // Re-exported core operators #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync}; +#[doc(no_inline)] +pub use marker::{Copy, Send, Sized, Sync}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce}; +#[doc(no_inline)] +pub use ops::{Drop, Fn, FnMut, FnOnce}; // Re-exported functions #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use mem::drop; +#[doc(no_inline)] +pub use mem::drop; // Re-exported types and traits #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use boxed::Box; +#[doc(no_inline)] +pub use clone::Clone; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use borrow::ToOwned; +#[doc(no_inline)] +pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use clone::Clone; +#[doc(no_inline)] +pub use convert::{AsRef, AsMut, Into, From}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +#[doc(no_inline)] +pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[doc(no_inline)] +pub use iter::{Iterator, Extend, IntoIterator}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use default::Default; +#[doc(no_inline)] +pub use iter::{DoubleEndedIterator, ExactSizeIterator}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::{Iterator, Extend, IntoIterator}; +#[doc(no_inline)] +pub use option::Option::{self, Some, None}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::{DoubleEndedIterator, ExactSizeIterator}; +#[doc(no_inline)] +pub use result::Result::{self, Ok, Err}; + + +// The file so far is equivalent to src/libcore/prelude/v1.rs, +// and below to src/liballoc/prelude.rs. +// Those files are duplicated rather than using glob imports +// because we want docs to show these re-exports as pointing to within `std`. + + #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use option::Option::{self, Some, None}; +#[doc(no_inline)] +pub use boxed::Box; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use result::Result::{self, Ok, Err}; +#[doc(no_inline)] +pub use borrow::ToOwned; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use slice::SliceConcatExt; +#[doc(no_inline)] +pub use slice::SliceConcatExt; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use string::{String, ToString}; +#[doc(no_inline)] +pub use string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use vec::Vec; +#[doc(no_inline)] +pub use vec::Vec; -- cgit 1.4.1-3-g733a5 From f580b983b1a35cfb0d25b56c5b201ebdbc39636c Mon Sep 17 00:00:00 2001 From: Fabian Drinck Date: Sun, 8 Jul 2018 16:07:09 +0200 Subject: Edit code example for File::open --- src/libstd/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 987687ea8e8..7632fbc41f5 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -356,9 +356,9 @@ impl File { /// use std::fs::File; /// /// fn main() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// # Ok(()) - /// # } + /// let mut f = File::open("foo.txt")?; + /// Ok(()) + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn open>(path: P) -> io::Result { -- cgit 1.4.1-3-g733a5 From 2c2add6e0259efd9b375c849d1bde187972b65b3 Mon Sep 17 00:00:00 2001 From: Kevin Zajler Date: Sun, 8 Jul 2018 18:07:17 +0200 Subject: Update std::ascii::ASCIIExt deprecation notes --- src/libstd/ascii.rs | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 6472edb0aa7..37641067734 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -163,7 +163,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_alphabetic)`. + /// For `str` use `.bytes().all(u8::is_ascii_alphabetic)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } @@ -176,7 +178,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_uppercase)`. + /// For `str` use `.bytes().all(u8::is_ascii_uppercase)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } @@ -189,7 +193,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_lowercase)`. + /// For `str` use `.bytes().all(u8::is_ascii_lowercase)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } @@ -203,7 +209,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_alphanumeric)`. + /// For `str` use `.bytes().all(u8::is_ascii_alphanumeric)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } @@ -216,7 +224,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_digit)`. + /// For `str` use `.bytes().all(u8::is_ascii_digit)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_digit(&self) -> bool { unimplemented!(); } @@ -230,7 +240,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_hexdigit)`. + /// For `str` use `.bytes().all(u8::is_ascii_hexdigit)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } @@ -248,7 +260,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_punctuation)`. + /// For `str` use `.bytes().all(u8::is_ascii_punctuation)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } @@ -261,7 +275,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_graphic)`. + /// For `str` use `.bytes().all(u8::is_ascii_graphic)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_graphic(&self) -> bool { unimplemented!(); } @@ -291,7 +307,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_whitespace)`. + /// For `str` use `.bytes().all(u8::is_ascii_whitespace)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } @@ -304,7 +322,9 @@ pub trait AsciiExt { /// # Note /// /// This method will be deprecated in favor of the identically-named - /// inherent methods on `u8`, `char`, `[u8]` and `str`. + /// inherent methods on `u8` and `char`. + /// For `[u8]` use `.iter().all(u8::is_ascii_control)`. + /// For `str` use `.bytes().all(u8::is_ascii_control)`. #[unstable(feature = "ascii_ctype", issue = "39658")] #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")] fn is_ascii_control(&self) -> bool { unimplemented!(); } -- cgit 1.4.1-3-g733a5 From 0b56e7f1a911f1157cd46cedbb1a0544e3ee3c3c Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sun, 8 Jul 2018 20:48:11 +0200 Subject: Delete leftover files --- src/libstd/sys/redox/ext/unixsocket.rs | 252 ------------ src/libstd/sys/unix/ext/unixsocket.rs | 354 ---------------- src/libstd/sys_common/unixsocket.rs | 731 --------------------------------- 3 files changed, 1337 deletions(-) delete mode 100644 src/libstd/sys/redox/ext/unixsocket.rs delete mode 100644 src/libstd/sys/unix/ext/unixsocket.rs delete mode 100644 src/libstd/sys_common/unixsocket.rs (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/unixsocket.rs b/src/libstd/sys/redox/ext/unixsocket.rs deleted file mode 100644 index 5f7b2df8992..00000000000 --- a/src/libstd/sys/redox/ext/unixsocket.rs +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use fmt; -use io::{self, Error, ErrorKind, Initializer}; -use net::Shutdown; -use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; -use path::Path; -use time::Duration; -use sys::{cvt, fd::FileDesc, syscall}; - -#[stable(feature = "unix_socket", since = "1.10.0")] -#[derive(Clone)] -pub struct SocketAddr(()); - -impl SocketAddr { - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - false - } - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - None - } -} -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "SocketAddr") - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(FileDesc); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect(path: &Path) -> io::Result { - if let Some(s) = path.to_str() { - cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) - .map(FileDesc::new) - .map(UnixStream) - } else { - Err(Error::new( - ErrorKind::Other, - "UnixStream::connect: non-utf8 paths not supported on redox" - )) - } - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) - .map(FileDesc::new)?; - let client = server.duplicate_path(b"connect")?; - let stream = server.duplicate_path(b"listen")?; - Ok((UnixStream(client), UnixStream(stream))) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - Ok(None) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { - Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - self.0.raw() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(FileDesc::new(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(FileDesc); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", &self.0.raw()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind(path: &Path) -> io::Result { - if let Some(s) = path.to_str() { - cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) - .map(FileDesc::new) - .map(UnixListener) - } else { - Err(Error::new( - ErrorKind::Other, - "UnixListener::bind: non-utf8 paths not supported on redox" - )) - } - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - Ok(None) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - self.0.raw() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(FileDesc::new(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw() - } -} diff --git a/src/libstd/sys/unix/ext/unixsocket.rs b/src/libstd/sys/unix/ext/unixsocket.rs deleted file mode 100644 index ad2d7019cb8..00000000000 --- a/src/libstd/sys/unix/ext/unixsocket.rs +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Unix-specific networking functionality - -#[cfg(unix)] -use libc; - -// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] -mod libc { - pub use libc::c_int; - pub type socklen_t = u32; - pub struct sockaddr; - #[derive(Clone)] - pub struct sockaddr_un; -} - -use ascii; -use ffi::OsStr; -use fmt; -use io::{self, Initializer}; -use mem; -use net::Shutdown; -use os::unix::ffi::OsStrExt; -use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; -use path::Path; -use time::Duration; -use sys::cvt; -use sys::net::Socket; -use sys::ext::net::*; -use sys_common::{AsInner, FromInner, IntoInner}; - -enum AddressKind<'a> { - Unnamed, - Pathname(&'a Path), - Abstract(&'a [u8]), -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -#[derive(Clone)] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn new(f: F) -> io::Result - where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) - -> io::Result - { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket")); - } - - Ok(SocketAddr { - addr, - len, - }) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { - true - } else { - false - } - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { - Some(path) - } else { - None - } - } - - fn address<'a>(&'a self) -> AddressKind<'a> { - let len = self.len as usize - sun_path_offset(); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} diff --git a/src/libstd/sys_common/unixsocket.rs b/src/libstd/sys_common/unixsocket.rs deleted file mode 100644 index c7d71ae6790..00000000000 --- a/src/libstd/sys_common/unixsocket.rs +++ /dev/null @@ -1,731 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "unix_socket", since = "1.10.0")] - -//! Unix-specific networking functionality - -use fmt; -use io::{self, Initializer}; -use net::Shutdown; -use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd}; -use path::Path; -use time::Duration; - -use sys::ext::unixsocket as inner; - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -#[derive(Clone)] -pub struct SocketAddr(pub(crate) inner::SocketAddr); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.0) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - UnixStream(inner::UnixStream::from_raw_fd(fd)) - } -} -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &self.0, buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - io::Read::initializer(&&self.0) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &self.0, buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - io::Read::initializer(&&self.0) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &self.0, buf) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &self.0) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &self.0, buf) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &self.0) - } -} - -impl SocketAddr { - /// Returns true if and only if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - self.0.is_unnamed() - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// let socket = UnixListener::bind("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// let socket = UnixDatagram::unbound().unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - self.0.as_pathname() - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap(); -/// stream.write_all(b"hello world").unwrap(); -/// let mut response = String::new(); -/// stream.read_to_string(&mut response).unwrap(); -/// println!("{}", response); -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(inner::UnixStream); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.0) - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - inner::UnixStream::connect(path.as_ref()).map(UnixStream) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - inner::UnixStream::pair().map(|(s1, s2)| (UnixStream(s1), UnixStream(s2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.try_clone().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - self.0.local_addr().map(SocketAddr) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - self.0.peer_addr().map(SocketAddr) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_read_timeout(timeout) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err - /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write - /// [`Duration`]: ../../../../std/time/struct.Duration.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap(); - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_write_timeout(timeout) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.read_timeout() - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.write_timeout() - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// let socket = UnixStream::connect("/tmp/sock").unwrap(); - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// pub fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(inner::UnixListener); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.0) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - UnixListener(inner::UnixListener::from_raw_fd(fd)) - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - inner::UnixListener::bind(path.as_ref()).map(UnixListener) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - self.0.accept().map(|(s, a)| (UnixStream(s), SocketAddr(a))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.try_clone().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - self.0.local_addr().map(SocketAddr) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = UnixListener::bind("/tmp/sock").unwrap(); - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns None. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`SocketAddr`]: struct.SocketAddr.html - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// pub fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming<'a>(&'a self) -> Incoming<'a> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// [`None`]: ../../../../std/option/enum.Option.html#variant.None -/// [`UnixListener`]: struct.UnixListener.html -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// pub fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// let listener = UnixListener::bind("/path/to/the/socket").unwrap(); -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -#[derive(Debug)] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} -- cgit 1.4.1-3-g733a5 From a1e1b5c3fb599ea8ea7ec7f785f3cc35c3be9666 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 18 Jun 2018 23:24:29 -0400 Subject: rework `LineWriter` example The original example didn't check the return value of `write()`, didn't flush the writer, and didn't properly demonstrate the buffering. Fixes #51621. --- src/libstd/io/buffered.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index ee297d3783e..ed085d5c0df 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -738,7 +738,7 @@ impl fmt::Display for IntoInnerError { /// reducing the number of actual writes to the file. /// /// ```no_run -/// use std::fs::File; +/// use std::fs::{self, File}; /// use std::io::prelude::*; /// use std::io::LineWriter; /// @@ -752,17 +752,31 @@ impl fmt::Display for IntoInnerError { /// let file = File::create("poem.txt")?; /// let mut file = LineWriter::new(file); /// -/// for &byte in road_not_taken.iter() { -/// file.write(&[byte]).unwrap(); -/// } +/// file.write_all(b"I shall be telling this with a sigh")?; +/// +/// // No bytes are written until a newline is encountered (or +/// // the internal buffer is filled). +/// assert_eq!(fs::read_to_string("poem.txt")?.as_bytes(), b""); +/// file.write_all(b"\n")?; +/// assert_eq!( +/// fs::read_to_string("poem.txt")?.as_bytes(), +/// &b"I shall be telling this with a sigh\n"[..], +/// ); /// -/// // let's check we did the right thing. -/// let mut file = File::open("poem.txt")?; -/// let mut contents = String::new(); +/// // Write the rest of the poem. +/// file.write_all(b"Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference.")?; /// -/// file.read_to_string(&mut contents)?; +/// // The last line of the poem doesn't end in a newline, so +/// // we have to flush or drop the `LineWriter` to finish +/// // writing. +/// file.flush()?; /// -/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// // Confirm the whole poem was written. +/// let mut poem = fs::read_to_string("poem.txt")?; +/// assert_eq!(poem.as_bytes(), &road_not_taken[..]); /// Ok(()) /// } /// ``` @@ -862,7 +876,7 @@ impl LineWriter { /// /// The internal buffer is written out before returning the writer. /// - // # Errors + /// # Errors /// /// An `Err` will be returned if an error occurs while flushing the buffer. /// -- cgit 1.4.1-3-g733a5 From 620599e8860b92db1ebbcef3f50671b937aec9cd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 8 Jul 2018 16:07:08 +0200 Subject: Remove `extern` on the `pub fn rust_oom` lang item in libstd, to match ABI of the declaration in liballoc This turned out to be important on Windows. Calling `handle_alloc_error(Layout::new::<[u8; 42]>())` caused: ``` Exception thrown at 0x00007FF7C70DC399 in a.exe: 0xC0000005: Access violation reading location 0x000000000000002A. ``` 0x2A equals 42, so it looks like the `Layout::size` field of type `usize` was interpreted as a pointer to read from. --- src/libstd/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index f6cecbea11f..cfdfbe1357d 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -127,7 +127,7 @@ fn default_alloc_error_hook(layout: Layout) { #[doc(hidden)] #[lang = "oom"] #[unstable(feature = "alloc_internals", issue = "0")] -pub extern fn rust_oom(layout: Layout) -> ! { +pub fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); let hook: fn(Layout) = if hook.is_null() { default_alloc_error_hook -- cgit 1.4.1-3-g733a5 From 239ec7d2dce9c19de16c9ee64addbb834119397c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 6 Jul 2018 15:49:52 +0200 Subject: Implement #[alloc_error_handler] This to-be-stable attribute is equivalent to `#[lang = "oom"]`. It is required when using the alloc crate without the std crate. It is called by `handle_alloc_error`, which is in turned called by "infallible" allocations APIs such as `Vec::push`. --- src/libcore/alloc.rs | 1 + src/librustc/middle/dead.rs | 12 +++++- src/librustc/middle/lang_items.rs | 3 ++ src/librustc/middle/weak_lang_items.rs | 3 ++ src/librustc_typeck/check/mod.rs | 47 ++++++++++++++++++++++ src/libstd/alloc.rs | 3 +- src/libstd/lib.rs | 3 +- src/libsyntax/feature_gate.rs | 8 ++++ .../alloc-error-handler-bad-signature-1.rs | 28 +++++++++++++ .../alloc-error-handler-bad-signature-2.rs | 27 +++++++++++++ .../alloc-error-handler-bad-signature-3.rs | 25 ++++++++++++ .../feature-gate-alloc-error-handler.rs | 21 ++++++++++ src/test/run-make-fulldeps/issue-51671/app.rs | 5 ++- src/test/ui/missing-alloc_error_handler.rs | 33 +++++++++++++++ src/test/ui/missing-alloc_error_handler.stderr | 4 ++ src/test/ui/missing-allocator.rs | 8 ++-- 16 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/alloc-error-handler-bad-signature-1.rs create mode 100644 src/test/compile-fail/alloc-error-handler-bad-signature-2.rs create mode 100644 src/test/compile-fail/alloc-error-handler-bad-signature-3.rs create mode 100644 src/test/compile-fail/feature-gate-alloc-error-handler.rs create mode 100644 src/test/ui/missing-alloc_error_handler.rs create mode 100644 src/test/ui/missing-alloc_error_handler.stderr (limited to 'src/libstd') diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 01221aecb62..b6ac248b79f 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -48,6 +48,7 @@ fn size_align() -> (usize, usize) { /// use specific allocators with looser requirements.) #[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(not(stage0), lang = "alloc_layout")] pub struct Layout { // size of the requested block of memory, measured in bytes. size_: usize, diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 226d19a9124..42775e3a183 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -288,7 +288,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt, id: ast::NodeId, attrs: &[ast::Attribute]) -> bool { - if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") { + if attr::contains_name(attrs, "lang") { + return true; + } + + // (To be) stable attribute for #[lang = "panic_impl"] + if attr::contains_name(attrs, "panic_implementation") { + return true; + } + + // (To be) stable attribute for #[lang = "oom"] + if attr::contains_name(attrs, "alloc_error_handler") { return true; } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index fe676919a7d..6c1ef851cbe 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -187,6 +187,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { } } else if attribute.check_name("panic_implementation") { return Some((Symbol::intern("panic_impl"), attribute.span)) + } else if attribute.check_name("alloc_error_handler") { + return Some((Symbol::intern("oom"), attribute.span)) } } @@ -308,6 +310,7 @@ language_item_table! { BoxFreeFnLangItem, "box_free", box_free_fn; DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; OomLangItem, "oom", oom; + AllocLayoutLangItem, "alloc_layout", alloc_layout; StartFnLangItem, "start", start_fn; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 180e75df1a6..d8570b43fbe 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -115,6 +115,9 @@ fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if lang_items::$item == lang_items::PanicImplLangItem { tcx.sess.err(&format!("`#[panic_implementation]` function required, \ but not found")); + } else if lang_items::$item == lang_items::OomLangItem { + tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \ + but not found")); } else { tcx.sess.err(&format!("language item required, but not found: `{}`", stringify!($name))); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 646c4f17568..c7ad3398873 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1182,7 +1182,54 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.tcx.sess.err("language item required, but not found: `panic_info`"); } } + } + + // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` + if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() { + if alloc_error_handler_did == fcx.tcx.hir.local_def_id(fn_id) { + if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() { + if declared_ret_ty.sty != ty::TyNever { + fcx.tcx.sess.span_err( + decl.output.span(), + "return type should be `!`", + ); + } + + let inputs = fn_sig.inputs(); + let span = fcx.tcx.hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_alloc_layout = match inputs[0].sty { + ty::TyAdt(ref adt, _) => { + adt.did == alloc_layout_did + }, + _ => false, + }; + + if !arg_is_alloc_layout { + fcx.tcx.sess.span_err( + decl.inputs[0].span, + "argument should be `Layout`", + ); + } + if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) { + if let Item_::ItemFn(_, _, ref generics, _) = item.node { + if !generics.params.is_empty() { + fcx.tcx.sess.span_err( + span, + "`#[alloc_error_handler]` function should have no type \ + parameters", + ); + } + } + } + } else { + fcx.tcx.sess.span_err(span, "function should have one argument"); + } + } else { + fcx.tcx.sess.err("language item required, but not found: `alloc_layout`"); + } + } } (fcx, gen_ty) diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index cfdfbe1357d..8db365cd21d 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -125,7 +125,8 @@ fn default_alloc_error_hook(layout: Layout) { #[cfg(not(test))] #[doc(hidden)] -#[lang = "oom"] +#[cfg_attr(stage0, lang = "oom")] +#[cfg_attr(not(stage0), alloc_error_handler)] #[unstable(feature = "alloc_internals", issue = "0")] pub fn rust_oom(layout: Layout) -> ! { let hook = HOOK.load(Ordering::SeqCst); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d73cb1f8349..fec14b8d67d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,8 +233,9 @@ // std is implemented with unstable features, many of which are internal // compiler details that will never be stable #![feature(alloc)] -#![feature(allocator_api)] +#![feature(alloc_error_handler)] #![feature(alloc_system)] +#![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index cbc421dbd32..e70d93ae85a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -481,6 +481,9 @@ declare_features! ( // Allows async and await syntax (active, async_await, "1.28.0", Some(50547), None), + + // #[alloc_error_handler] + (active, alloc_error_handler, "1.29.0", Some(51540), None), ); declare_features! ( @@ -1083,6 +1086,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "#[panic_implementation] is an unstable feature", cfg_fn!(panic_implementation))), + ("alloc_error_handler", Normal, Gated(Stability::Unstable, + "alloc_error_handler", + "#[alloc_error_handler] is an unstable feature", + cfg_fn!(alloc_error_handler))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs new file mode 100644 index 00000000000..e398f16a065 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-1.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler, panic_implementation)] +#![no_std] +#![no_main] + +use core::alloc::Layout; + +#[alloc_error_handler] +fn oom( + info: &Layout, //~ ERROR argument should be `Layout` +) -> () //~ ERROR return type should be `!` +{ + loop {} +} + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs new file mode 100644 index 00000000000..4fee9d27e51 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-2.rs @@ -0,0 +1,27 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler, panic_implementation)] +#![no_std] +#![no_main] + +struct Layout; + +#[alloc_error_handler] +fn oom( + info: Layout, //~ ERROR argument should be `Layout` +) { //~ ERROR return type should be `!` + loop {} +} + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs b/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs new file mode 100644 index 00000000000..828a78055d5 --- /dev/null +++ b/src/test/compile-fail/alloc-error-handler-bad-signature-3.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler, panic_implementation)] +#![no_std] +#![no_main] + +struct Layout; + +#[alloc_error_handler] +fn oom() -> ! { //~ ERROR function should have one argument + loop {} +} + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/compile-fail/feature-gate-alloc-error-handler.rs b/src/test/compile-fail/feature-gate-alloc-error-handler.rs new file mode 100644 index 00000000000..66691af2d03 --- /dev/null +++ b/src/test/compile-fail/feature-gate-alloc-error-handler.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-C panic=abort + +#![no_std] +#![no_main] + +use core::alloc::Layout; + +#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540) +fn oom(info: Layout) -> ! { + loop {} +} diff --git a/src/test/run-make-fulldeps/issue-51671/app.rs b/src/test/run-make-fulldeps/issue-51671/app.rs index 720ce1512f2..453602b800b 100644 --- a/src/test/run-make-fulldeps/issue-51671/app.rs +++ b/src/test/run-make-fulldeps/issue-51671/app.rs @@ -14,6 +14,7 @@ #![no_main] #![no_std] +use core::alloc::Layout; use core::panic::PanicInfo; #[panic_implementation] @@ -25,4 +26,6 @@ fn panic(_: &PanicInfo) -> ! { fn eh() {} #[lang = "oom"] -fn oom() {} +fn oom(_: Layout) -> ! { + loop {} +} diff --git a/src/test/ui/missing-alloc_error_handler.rs b/src/test/ui/missing-alloc_error_handler.rs new file mode 100644 index 00000000000..3842d48f8fa --- /dev/null +++ b/src/test/ui/missing-alloc_error_handler.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C panic=abort +// no-prefer-dynamic + +#![no_std] +#![crate_type = "staticlib"] +#![feature(panic_implementation, alloc_error_handler, alloc)] + +#[panic_implementation] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +extern crate alloc; + +#[global_allocator] +static A: MyAlloc = MyAlloc; + +struct MyAlloc; + +unsafe impl core::alloc::GlobalAlloc for MyAlloc { + unsafe fn alloc(&self, _: core::alloc::Layout) -> *mut u8 { 0 as _ } + unsafe fn dealloc(&self, _: *mut u8, _: core::alloc::Layout) {} +} diff --git a/src/test/ui/missing-alloc_error_handler.stderr b/src/test/ui/missing-alloc_error_handler.stderr new file mode 100644 index 00000000000..5489b2cbbfa --- /dev/null +++ b/src/test/ui/missing-alloc_error_handler.stderr @@ -0,0 +1,4 @@ +error: `#[alloc_error_handler]` function required, but not found + +error: aborting due to previous error + diff --git a/src/test/ui/missing-allocator.rs b/src/test/ui/missing-allocator.rs index 24282631b7e..c949dcb635a 100644 --- a/src/test/ui/missing-allocator.rs +++ b/src/test/ui/missing-allocator.rs @@ -13,14 +13,16 @@ #![no_std] #![crate_type = "staticlib"] -#![feature(panic_implementation, lang_items, alloc)] +#![feature(panic_implementation, alloc_error_handler, alloc)] #[panic_implementation] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } -#[lang = "oom"] -fn oom() {} +#[alloc_error_handler] +fn oom(_: core::alloc::Layout) -> ! { + loop {} +} extern crate alloc; -- cgit 1.4.1-3-g733a5 From 560d8079ec26f2a45ecb80e95d24917025e02104 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 10 Jul 2018 20:35:36 +0200 Subject: Deny bare trait objects in `src/libstd`. --- src/libstd/error.rs | 86 ++++++++++++++++++------------------ src/libstd/ffi/c_str.rs | 2 +- src/libstd/io/error.rs | 14 +++--- src/libstd/io/mod.rs | 4 +- src/libstd/io/stdio.rs | 8 ++-- src/libstd/lib.rs | 1 + src/libstd/net/parser.rs | 2 +- src/libstd/panic.rs | 2 +- src/libstd/panicking.rs | 36 +++++++-------- src/libstd/process.rs | 4 +- src/libstd/rt.rs | 2 +- src/libstd/sync/mpsc/mod.rs | 10 ++--- src/libstd/sync/mpsc/select.rs | 2 +- src/libstd/sync/once.rs | 2 +- src/libstd/sys/windows/thread.rs | 2 +- src/libstd/sys_common/at_exit_imp.rs | 4 +- src/libstd/sys_common/backtrace.rs | 10 ++--- src/libstd/sys_common/poison.rs | 2 +- src/libstd/sys_common/thread.rs | 2 +- src/libstd/thread/mod.rs | 2 +- 20 files changed, 99 insertions(+), 98 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 1958915602f..8d715ac0ec3 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -138,7 +138,7 @@ pub trait Error: Debug + Display { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn cause(&self) -> Option<&Error> { None } + fn cause(&self) -> Option<&dyn Error> { None } /// Get the `TypeId` of `self` #[doc(hidden)] @@ -151,22 +151,22 @@ pub trait Error: Debug + Display { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From for Box { - fn from(err: E) -> Box { +impl<'a, E: Error + 'a> From for Box { + fn from(err: E) -> Box { Box::new(err) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + Sync + 'a> From for Box { - fn from(err: E) -> Box { +impl<'a, E: Error + Send + Sync + 'a> From for Box { + fn from(err: E) -> Box { Box::new(err) } } #[stable(feature = "rust1", since = "1.0.0")] -impl From for Box { - fn from(err: String) -> Box { +impl From for Box { + fn from(err: String) -> Box { #[derive(Debug)] struct StringError(String); @@ -185,38 +185,38 @@ impl From for Box { } #[stable(feature = "string_box_error", since = "1.6.0")] -impl From for Box { - fn from(str_err: String) -> Box { - let err1: Box = From::from(str_err); - let err2: Box = err1; +impl From for Box { + fn from(str_err: String) -> Box { + let err1: Box = From::from(str_err); + let err2: Box = err1; err2 } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { From::from(String::from(err)) } } #[stable(feature = "string_box_error", since = "1.6.0")] -impl<'a> From<&'a str> for Box { - fn from(err: &'a str) -> Box { +impl<'a> From<&'a str> for Box { + fn from(err: &'a str) -> Box { From::from(String::from(err)) } } #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a, 'b> From> for Box { - fn from(err: Cow<'b, str>) -> Box { +impl<'a, 'b> From> for Box { + fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) } } #[stable(feature = "cow_box_error", since = "1.22.0")] -impl<'a> From> for Box { - fn from(err: Cow<'a, str>) -> Box { +impl<'a> From> for Box { + fn from(err: Cow<'a, str>) -> Box { From::from(String::from(err)) } } @@ -327,7 +327,7 @@ impl Error for Box { Error::description(&**self) } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { Error::cause(&**self) } } @@ -368,7 +368,7 @@ impl Error for char::ParseCharError { } // copied from any.rs -impl Error + 'static { +impl dyn Error + 'static { /// Returns true if the boxed type is the same as `T` #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] @@ -390,7 +390,7 @@ impl Error + 'static { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { unsafe { - Some(&*(self as *const Error as *const T)) + Some(&*(self as *const dyn Error as *const T)) } } else { None @@ -404,7 +404,7 @@ impl Error + 'static { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { unsafe { - Some(&mut *(self as *mut Error as *mut T)) + Some(&mut *(self as *mut dyn Error as *mut T)) } } else { None @@ -412,60 +412,60 @@ impl Error + 'static { } } -impl Error + 'static + Send { +impl dyn Error + 'static + Send { /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is(&self) -> bool { - ::is::(self) + ::is::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) + ::downcast_ref::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) + ::downcast_mut::(self) } } -impl Error + 'static + Send + Sync { +impl dyn Error + 'static + Send + Sync { /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn is(&self) -> bool { - ::is::(self) + ::is::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) + ::downcast_ref::(self) } /// Forwards to the method defined on the type `Any`. #[stable(feature = "error_downcast", since = "1.3.0")] #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) + ::downcast_mut::(self) } } -impl Error { +impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) -> Result, Box> { + pub fn downcast(self: Box) -> Result, Box> { if self.is::() { unsafe { - let raw: *mut Error = Box::into_raw(self); + let raw: *mut dyn Error = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) } } else { @@ -474,30 +474,30 @@ impl Error { } } -impl Error + Send { +impl dyn Error + Send { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. pub fn downcast(self: Box) - -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { + -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { // reapply the Send marker - transmute::, Box>(s) + transmute::, Box>(s) }) } } -impl Error + Send + Sync { +impl dyn Error + Send + Sync { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] /// Attempt to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { // reapply the Send+Sync marker - transmute::, Box>(s) + transmute::, Box>(s) }) } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 6513d11dd51..03e0d0aa6dd 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -883,7 +883,7 @@ impl Error for IntoStringError { "C string contained non-utf8 bytes" } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { Some(&self.error) } } diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index bdd675e6e2b..02a3ce8b9c4 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -83,7 +83,7 @@ enum Repr { #[derive(Debug)] struct Custom { kind: ErrorKind, - error: Box, + error: Box, } /// A list specifying general categories of I/O error. @@ -250,12 +250,12 @@ impl Error { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(kind: ErrorKind, error: E) -> Error - where E: Into> + where E: Into> { Self::_new(kind, error.into()) } - fn _new(kind: ErrorKind, error: Box) -> Error { + fn _new(kind: ErrorKind, error: Box) -> Error { Error { repr: Repr::Custom(Box::new(Custom { kind, @@ -373,7 +373,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { + pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -444,7 +444,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { + pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -478,7 +478,7 @@ impl Error { /// } /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] - pub fn into_inner(self) -> Option> { + pub fn into_inner(self) -> Option> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, @@ -551,7 +551,7 @@ impl error::Error for Error { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { match self.repr { Repr::Os(..) => None, Repr::Simple(..) => None, diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 2b4644bd013..85304874848 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1972,7 +1972,7 @@ impl BufRead for Take { } } -fn read_one_byte(reader: &mut Read) -> Option> { +fn read_one_byte(reader: &mut dyn Read) -> Option> { let mut buf = [0]; loop { return match reader.read(&mut buf) { @@ -2081,7 +2081,7 @@ impl std_error::Error for CharsError { CharsError::Other(ref e) => std_error::Error::description(e), } } - fn cause(&self) -> Option<&std_error::Error> { + fn cause(&self) -> Option<&dyn std_error::Error> { match *self { CharsError::NotUtf8 => None, CharsError::Other(ref e) => e.cause(), diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index fce85a200ba..fffe8fc559b 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -21,7 +21,7 @@ use thread::LocalKey; /// Stdout used by print! and println! macros thread_local! { - static LOCAL_STDOUT: RefCell>> = { + static LOCAL_STDOUT: RefCell>> = { RefCell::new(None) } } @@ -624,7 +624,7 @@ impl<'a> fmt::Debug for StderrLock<'a> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_panic(sink: Option>) -> Option> { +pub fn set_panic(sink: Option>) -> Option> { use panicking::LOCAL_STDERR; use mem; LOCAL_STDERR.with(move |slot| { @@ -648,7 +648,7 @@ pub fn set_panic(sink: Option>) -> Option> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_print(sink: Option>) -> Option> { +pub fn set_print(sink: Option>) -> Option> { use mem; LOCAL_STDOUT.with(move |slot| { mem::replace(&mut *slot.borrow_mut(), sink) @@ -670,7 +670,7 @@ pub fn set_print(sink: Option>) -> Option> { /// However, if the actual I/O causes an error, this function does panic. fn print_to( args: fmt::Arguments, - local_s: &'static LocalKey>>>, + local_s: &'static LocalKey>>>, global_s: fn() -> T, label: &str, ) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d73cb1f8349..006922383cf 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -221,6 +221,7 @@ // Don't link to std. We are std. #![no_std] +#![deny(bare_trait_objects)] #![deny(missing_docs)] #![deny(missing_debug_implementations)] diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index ae5037cc44e..234c5618a06 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -61,7 +61,7 @@ impl<'a> Parser<'a> { } // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [Box Option + 'static>]) + fn read_or(&mut self, parsers: &mut [Box Option + 'static>]) -> Option { for pf in parsers { if let Some(r) = self.read_atomically(|p: &mut Parser| pf(p)) { diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 451420ae88a..b8c1c4f9e68 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -421,6 +421,6 @@ pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { /// } /// ``` #[stable(feature = "resume_unwind", since = "1.9.0")] -pub fn resume_unwind(payload: Box) -> ! { +pub fn resume_unwind(payload: Box) -> ! { panicking::update_count_then_panic(payload) } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 46b6cf60705..283fd36af41 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -36,7 +36,7 @@ use sys_common::util; use thread; thread_local! { - pub static LOCAL_STDERR: RefCell>> = { + pub static LOCAL_STDERR: RefCell>> = { RefCell::new(None) } } @@ -64,7 +64,7 @@ extern { #[derive(Copy, Clone)] enum Hook { Default, - Custom(*mut (Fn(&PanicInfo) + 'static + Sync + Send)), + Custom(*mut (dyn Fn(&PanicInfo) + 'static + Sync + Send)), } static HOOK_LOCK: RWLock = RWLock::new(); @@ -104,7 +104,7 @@ static mut HOOK: Hook = Hook::Default; /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn set_hook(hook: Box) { +pub fn set_hook(hook: Box) { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -149,7 +149,7 @@ pub fn set_hook(hook: Box) { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] -pub fn take_hook() -> Box { +pub fn take_hook() -> Box { if thread::panicking() { panic!("cannot modify the panic hook from a panicking thread"); } @@ -197,7 +197,7 @@ fn default_hook(info: &PanicInfo) { let thread = thread_info::current_thread(); let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); - let write = |err: &mut ::io::Write| { + let write = |err: &mut dyn (::io::Write)| { let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location); @@ -248,7 +248,7 @@ pub fn update_panic_count(amt: isize) -> usize { pub use realstd::rt::update_panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -pub unsafe fn try R>(f: F) -> Result> { +pub unsafe fn try R>(f: F) -> Result> { #[allow(unions_with_drop_fields)] union Data { f: F, @@ -369,12 +369,12 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { } unsafe impl<'a> BoxMeUp for PanicPayload<'a> { - fn box_me_up(&mut self) -> *mut (Any + Send) { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { let contents = mem::replace(self.fill(), String::new()); Box::into_raw(Box::new(contents)) } - fn get(&mut self) -> &(Any + Send) { + fn get(&mut self) -> &(dyn Any + Send) { self.fill() } } @@ -419,15 +419,15 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 } unsafe impl BoxMeUp for PanicPayload { - fn box_me_up(&mut self) -> *mut (Any + Send) { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { let data = match self.inner.take() { - Some(a) => Box::new(a) as Box, + Some(a) => Box::new(a) as Box, None => Box::new(()), }; Box::into_raw(data) } - fn get(&mut self) -> &(Any + Send) { + fn get(&mut self) -> &(dyn Any + Send) { match self.inner { Some(ref a) => a, None => &(), @@ -441,7 +441,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 /// Executes the primary logic for a panic, including checking for recursive /// panics, panic hooks, and finally dispatching to the panic runtime to either /// abort or unwind. -fn rust_panic_with_hook(payload: &mut BoxMeUp, +fn rust_panic_with_hook(payload: &mut dyn BoxMeUp, message: Option<&fmt::Arguments>, file_line_col: &(&str, u32, u32)) -> ! { let (file, line, col) = *file_line_col; @@ -496,17 +496,17 @@ fn rust_panic_with_hook(payload: &mut BoxMeUp, } /// Shim around rust_panic. Called by resume_unwind. -pub fn update_count_then_panic(msg: Box) -> ! { +pub fn update_count_then_panic(msg: Box) -> ! { update_panic_count(1); - struct RewrapBox(Box); + struct RewrapBox(Box); unsafe impl BoxMeUp for RewrapBox { - fn box_me_up(&mut self) -> *mut (Any + Send) { + fn box_me_up(&mut self) -> *mut (dyn Any + Send) { Box::into_raw(mem::replace(&mut self.0, Box::new(()))) } - fn get(&mut self) -> &(Any + Send) { + fn get(&mut self) -> &(dyn Any + Send) { &*self.0 } } @@ -517,9 +517,9 @@ pub fn update_count_then_panic(msg: Box) -> ! { /// A private no-mangle function on which to slap yer breakpoints. #[no_mangle] #[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints -pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! { +pub fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { let code = unsafe { - let obj = &mut msg as *mut &mut BoxMeUp; + let obj = &mut msg as *mut &mut dyn BoxMeUp; __rust_start_panic(obj as usize) }; rtabort!("failed to initiate panic, error {}", code) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 00051d4487a..39692836866 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -813,13 +813,13 @@ impl fmt::Debug for Output { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let stdout_utf8 = str::from_utf8(&self.stdout); - let stdout_debug: &fmt::Debug = match stdout_utf8 { + let stdout_debug: &dyn fmt::Debug = match stdout_utf8 { Ok(ref str) => str, Err(_) => &self.stdout }; let stderr_utf8 = str::from_utf8(&self.stderr); - let stderr_debug: &fmt::Debug = match stderr_utf8 { + let stderr_debug: &dyn fmt::Debug = match stderr_utf8 { Ok(ref str) => str, Err(_) => &self.stderr }; diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 8f945470b7e..9e957bd87d7 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -29,7 +29,7 @@ pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; // To reduce the generated code of the new `lang_start`, this function is doing // the real work. #[cfg(not(test))] -fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), +fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + ::panic::RefUnwindSafe), argc: isize, argv: *const *const u8) -> isize { use panic; use sys; diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 2dd3aebe610..1dc0b1c0042 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1638,7 +1638,7 @@ impl error::Error for SendError { "sending on a closed channel" } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1681,7 +1681,7 @@ impl error::Error for TrySendError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1709,7 +1709,7 @@ impl error::Error for RecvError { "receiving on a closed channel" } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1742,7 +1742,7 @@ impl error::Error for TryRecvError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -1783,7 +1783,7 @@ impl error::Error for RecvTimeoutError { } } - fn cause(&self) -> Option<&error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index 9310dad9172..a7a284cfb79 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -93,7 +93,7 @@ pub struct Handle<'rx, T:Send+'rx> { next: *mut Handle<'static, ()>, prev: *mut Handle<'static, ()>, added: bool, - packet: &'rx (Packet+'rx), + packet: &'rx (dyn Packet+'rx), // due to our fun transmutes, we be sure to place this at the end. (nothing // previous relies on T) diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 7eb7be23128..1c63f99753a 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -301,7 +301,7 @@ impl Once { #[cold] fn call_inner(&'static self, ignore_poisoning: bool, - init: &mut FnMut(bool)) { + init: &mut dyn FnMut(bool)) { let mut state = self.state.load(Ordering::SeqCst); 'outer: loop { diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index b6f63303dc2..44ec872b244 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -28,7 +28,7 @@ pub struct Thread { } impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) + pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { let p = box p; diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index d268d9ad6f9..b28a4d2f8be 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -17,7 +17,7 @@ use ptr; use mem; use sys_common::mutex::Mutex; -type Queue = Vec>; +type Queue = Vec>; // NB these are specifically not types from `std::sync` as they currently rely // on poisoning and this module needs to operate at a lower level than requiring @@ -68,7 +68,7 @@ pub fn cleanup() { } } -pub fn push(f: Box) -> bool { +pub fn push(f: Box) -> bool { unsafe { let _guard = LOCK.lock(); if init() { diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 61d7ed463dd..6184ba4ded6 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -49,7 +49,7 @@ pub struct Frame { const MAX_NB_FRAMES: usize = 100; /// Prints the current backtrace. -pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { static LOCK: Mutex = Mutex::new(); // Use a lock to prevent mixed output in multithreading context. @@ -62,7 +62,7 @@ pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> { } } -fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> { let mut frames = [Frame { exact_position: ptr::null(), symbol_addr: ptr::null(), @@ -177,7 +177,7 @@ pub fn log_enabled() -> Option { /// /// These output functions should now be used everywhere to ensure consistency. /// You may want to also use `output_fileline`. -fn output(w: &mut Write, idx: usize, frame: Frame, +fn output(w: &mut dyn Write, idx: usize, frame: Frame, s: Option<&str>, format: PrintFormat) -> io::Result<()> { // Remove the `17: 0x0 - ` line. if format == PrintFormat::Short && frame.exact_position == ptr::null() { @@ -202,7 +202,7 @@ fn output(w: &mut Write, idx: usize, frame: Frame, /// /// See also `output`. #[allow(dead_code)] -fn output_fileline(w: &mut Write, +fn output_fileline(w: &mut dyn Write, file: &[u8], line: u32, format: PrintFormat) -> io::Result<()> { @@ -254,7 +254,7 @@ fn output_fileline(w: &mut Write, // Note that this demangler isn't quite as fancy as it could be. We have lots // of other information in our symbols like hashes, version, type information, // etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(writer: &mut Write, mut s: &str, format: PrintFormat) -> io::Result<()> { +pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { // During ThinLTO LLVM may import and rename internal symbols, so strip out // those endings first as they're one of the last manglings applied to // symbol names. diff --git a/src/libstd/sys_common/poison.rs b/src/libstd/sys_common/poison.rs index e74c40ae04b..1625efe4a2a 100644 --- a/src/libstd/sys_common/poison.rs +++ b/src/libstd/sys_common/poison.rs @@ -251,7 +251,7 @@ impl Error for TryLockError { } } - fn cause(&self) -> Option<&Error> { + fn cause(&self) -> Option<&dyn Error> { match *self { TryLockError::Poisoned(ref p) => Some(p), _ => None diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs index da6f58ef6bb..86a5e2b8694 100644 --- a/src/libstd/sys_common/thread.rs +++ b/src/libstd/sys_common/thread.rs @@ -21,7 +21,7 @@ pub unsafe fn start_thread(main: *mut u8) { let _handler = stack_overflow::Handler::new(); // Finally, let's run some code. - Box::from_raw(main as *mut Box)() + Box::from_raw(main as *mut Box)() } pub fn min_stack() -> usize { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 90f054186d1..cc0ec8a5b4d 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1175,7 +1175,7 @@ impl fmt::Debug for Thread { /// /// [`Result`]: ../../std/result/enum.Result.html #[stable(feature = "rust1", since = "1.0.0")] -pub type Result = ::result::Result>; +pub type Result = ::result::Result>; // This packet is used to communicate the return value between the child thread // and the parent thread. Memory is shared through the `Arc` within and there's -- cgit 1.4.1-3-g733a5 From b29a6fbabcb425f6e238a00946fb1c9869f657e9 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 10 Jul 2018 20:52:29 +0200 Subject: Add missing `dyn` for cloudabi, redox, unix and wasm --- src/libstd/sys/cloudabi/thread.rs | 2 +- src/libstd/sys/redox/thread.rs | 2 +- src/libstd/sys/unix/process/process_common.rs | 6 +++--- src/libstd/sys/unix/thread.rs | 2 +- src/libstd/sys/wasm/thread.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index 5d66936b2a4..8cca47efd22 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -32,7 +32,7 @@ unsafe impl Send for Thread {} unsafe impl Sync for Thread {} impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { + pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed(); diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index 110d46ca3ab..f4177087d77 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -28,7 +28,7 @@ unsafe impl Send for Thread {} unsafe impl Sync for Thread {} impl Thread { - pub unsafe fn new<'a>(_stack: usize, p: Box) -> io::Result { + pub unsafe fn new<'a>(_stack: usize, p: Box) -> io::Result { let p = box p; let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 6396bb3a49e..77f125f3c5b 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -52,7 +52,7 @@ pub struct Command { uid: Option, gid: Option, saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, + closures: Vec io::Result<()> + Send + Sync>>, stdin: Option, stdout: Option, stderr: Option, @@ -155,12 +155,12 @@ impl Command { self.gid } - pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { + pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { &mut self.closures } pub fn before_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { + f: Box io::Result<()> + Send + Sync>) { self.closures.push(f); } diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 7fdecc9c0c0..e26306c045d 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -49,7 +49,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, } impl Thread { - pub unsafe fn new<'a>(stack: usize, p: Box) + pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 728e678a2e8..8173a624211 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -19,7 +19,7 @@ pub struct Thread(Void); pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { - pub unsafe fn new<'a>(_stack: usize, _p: Box) + pub unsafe fn new<'a>(_stack: usize, _p: Box) -> io::Result { unsupported() -- cgit 1.4.1-3-g733a5 From 0f3f292b4c7a15b656a925e7ebe5f2d3955b8553 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Tue, 10 Jul 2018 22:47:59 -0400 Subject: remove sync::Once::call_once 'static - [std: Rewrite the `sync` modulehttps://github.com/rust-lang/rust/commit/71d4e77db8ad4b6d821da7e5d5300134ac95974e) (Nov 2014) ```diff - pub fn doit(&self, f: ||) { + pub fn doit(&'static self, f: ||) { ``` > ```text > The second layer is the layer provided by `std::sync` which is intended to be > the thinnest possible layer on top of `sys_common` which is entirely safe to > use. There are a few concerns which need to be addressed when making these > system primitives safe: > > * Once used, the OS primitives can never be **moved**. This means that they > essentially need to have a stable address. The static primitives use > `&'static self` to enforce this, and the non-static primitives all use a > `Box` to provide this guarantee. > ``` The author of this diff is @alexcrichton. `sync::Once` contains only a pointer to (privately hidden) `Waiter`s, which are all stack-allocated. The `'static` bound to `sync::Once` is thus unnecessary to guarantee that any OS primitives are non-relocatable. See https://internals.rust-lang.org/t/sync-once-per-instance/7918 for more context. --- src/libstd/sync/once.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 7eb7be23128..51c42995d5e 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -149,9 +149,9 @@ struct Waiter { // Helper struct used to clean up after a closure call with a `Drop` // implementation to also run on panic. -struct Finish { +struct Finish<'a> { panicked: bool, - me: &'static Once, + me: &'a Once, } impl Once { @@ -218,7 +218,7 @@ impl Once { /// /// [poison]: struct.Mutex.html#poisoning #[stable(feature = "rust1", since = "1.0.0")] - pub fn call_once(&'static self, f: F) where F: FnOnce() { + pub fn call_once(&self, f: F) where F: FnOnce() { // Fast path, just see if we've completed initialization. if self.state.load(Ordering::SeqCst) == COMPLETE { return @@ -275,7 +275,7 @@ impl Once { /// INIT.call_once(|| {}); /// ``` #[unstable(feature = "once_poison", issue = "33577")] - pub fn call_once_force(&'static self, f: F) where F: FnOnce(&OnceState) { + pub fn call_once_force(&self, f: F) where F: FnOnce(&OnceState) { // same as above, just with a different parameter to `call_inner`. if self.state.load(Ordering::SeqCst) == COMPLETE { return @@ -299,7 +299,7 @@ impl Once { // currently no way to take an `FnOnce` and call it via virtual dispatch // without some allocation overhead. #[cold] - fn call_inner(&'static self, + fn call_inner(&self, ignore_poisoning: bool, init: &mut FnMut(bool)) { let mut state = self.state.load(Ordering::SeqCst); @@ -390,7 +390,7 @@ impl fmt::Debug for Once { } } -impl Drop for Finish { +impl<'a> Drop for Finish<'a> { fn drop(&mut self) { // Swap out our state with however we finished. We should only ever see // an old state which was RUNNING. -- cgit 1.4.1-3-g733a5 From 1915cd1dc2d5ea66d322d52958271b8072ec4c97 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 11 Jul 2018 09:11:39 +0200 Subject: Add missing dyn in tests --- src/libstd/error.rs | 4 ++-- src/libstd/io/util.rs | 2 +- src/libstd/net/tcp.rs | 2 +- src/libstd/net/udp.rs | 2 +- src/libstd/thread/mod.rs | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 8d715ac0ec3..29534696abc 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -533,13 +533,13 @@ mod tests { #[test] fn downcasting() { let mut a = A; - let a = &mut a as &mut (Error + 'static); + let a = &mut a as &mut (dyn Error + 'static); assert_eq!(a.downcast_ref::(), Some(&A)); assert_eq!(a.downcast_ref::(), None); assert_eq!(a.downcast_mut::(), Some(&mut A)); assert_eq!(a.downcast_mut::(), None); - let a: Box = Box::new(A); + let a: Box = Box::new(A); match a.downcast::() { Ok(..) => panic!("expected error"), Err(e) => assert_eq!(*e.downcast::().unwrap(), A), diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 195310a26fe..33f741dbc38 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -223,7 +223,7 @@ mod tests { assert_eq!(copy(&mut r, &mut w).unwrap(), 4); let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); } #[test] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 0f60b5b3ee4..f6f589cb6bd 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -927,7 +927,7 @@ mod tests { use time::{Instant, Duration}; use thread; - fn each_ip(f: &mut FnMut(SocketAddr)) { + fn each_ip(f: &mut dyn FnMut(SocketAddr)) { f(next_test_ip4()); f(next_test_ip6()); } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index d25e29999cb..0ebe3284b4f 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -826,7 +826,7 @@ mod tests { use time::{Instant, Duration}; use thread; - fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) { + fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { f(next_test_ip4(), next_test_ip4()); f(next_test_ip6(), next_test_ip6()); } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index cc0ec8a5b4d..f7052e4834a 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1438,7 +1438,7 @@ mod tests { rx.recv().unwrap(); } - fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Box) { + fn avoid_copying_the_body(spawnfn: F) where F: FnOnce(Box) { let (tx, rx) = channel(); let x: Box<_> = box 1; @@ -1485,7 +1485,7 @@ mod tests { // (well, it would if the constant were 8000+ - I lowered it to be more // valgrind-friendly. try this at home, instead..!) const GENERATIONS: u32 = 16; - fn child_no(x: u32) -> Box { + fn child_no(x: u32) -> Box { return Box::new(move|| { if x < GENERATIONS { thread::spawn(move|| child_no(x+1)()); @@ -1531,10 +1531,10 @@ mod tests { #[test] fn test_try_panic_message_any() { match thread::spawn(move|| { - panic!(box 413u16 as Box); + panic!(box 413u16 as Box); }).join() { Err(e) => { - type T = Box; + type T = Box; assert!(e.is::()); let any = e.downcast::().unwrap(); assert!(any.is::()); -- cgit 1.4.1-3-g733a5 From c12a75742485dcc3db7b0f374e78f090c323830d Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 11 Jul 2018 14:39:22 -0400 Subject: simplify assertions --- src/libstd/io/buffered.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index ed085d5c0df..189569683a9 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -756,11 +756,11 @@ impl fmt::Display for IntoInnerError { /// /// // No bytes are written until a newline is encountered (or /// // the internal buffer is filled). -/// assert_eq!(fs::read_to_string("poem.txt")?.as_bytes(), b""); +/// assert_eq!(fs::read_to_string("poem.txt")?, ""); /// file.write_all(b"\n")?; /// assert_eq!( -/// fs::read_to_string("poem.txt")?.as_bytes(), -/// &b"I shall be telling this with a sigh\n"[..], +/// fs::read_to_string("poem.txt")?, +/// "I shall be telling this with a sigh\n", /// ); /// /// // Write the rest of the poem. @@ -775,8 +775,7 @@ impl fmt::Display for IntoInnerError { /// file.flush()?; /// /// // Confirm the whole poem was written. -/// let mut poem = fs::read_to_string("poem.txt")?; -/// assert_eq!(poem.as_bytes(), &road_not_taken[..]); +/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); /// Ok(()) /// } /// ``` -- cgit 1.4.1-3-g733a5 From e488cba6784eebc36b9869239b729a4e41048d3f Mon Sep 17 00:00:00 2001 From: Matt Kraai Date: Wed, 11 Jul 2018 17:19:41 -0700 Subject: Uncapitalize "If" --- src/libstd/sync/mpsc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 2dd3aebe610..cbda5afadcd 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -689,7 +689,7 @@ impl UnsafeFlavor for Receiver { /// only one [`Receiver`] is supported. /// /// If the [`Receiver`] is disconnected while trying to [`send`] with the -/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, If the +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the /// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will /// return a [`RecvError`]. /// -- cgit 1.4.1-3-g733a5 From a6fa656555583524d3c4e6cde702e1b63578cc44 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 11 Jul 2018 18:11:53 -0700 Subject: Use fast TLS on Fuchsia --- src/libstd/sys/unix/fast_thread_local.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index 6cdbe5df75d..d59d800a579 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -20,7 +20,7 @@ // fallback implementation to use as well. // // Due to rust-lang/rust#18804, make sure this is not generic! -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "fuchsia"))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { use libc; use mem; @@ -55,11 +55,6 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { _tlv_atexit(dtor, t); } -// Just use the thread_local fallback implementation, at least until there's -// a more direct implementation. -#[cfg(target_os = "fuchsia")] -pub use sys_common::thread_local::register_dtor_fallback as register_dtor; - pub fn requires_move_before_drop() -> bool { // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor -- cgit 1.4.1-3-g733a5 From e9a88eaaf9a42785aa91b67281ab265ba85bc43e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 12:48:10 +0200 Subject: make reference to dirs crate clickable in terminals --- src/libstd/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/env.rs b/src/libstd/env.rs index c0e1e2533a0..9066c0b7694 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -541,7 +541,7 @@ impl Error for JoinPathsError { /// ``` #[rustc_deprecated(since = "1.29.0", reason = "This function's behavior is unexpected and probably not what you want. \ - Consider using the home_dir function from crates.io/crates/dirs instead.")] + Consider using the home_dir function from https://crates.io/crates/dirs instead.")] #[stable(feature = "env", since = "1.0.0")] pub fn home_dir() -> Option { os_imp::home_dir() -- cgit 1.4.1-3-g733a5 From 72e2c00af48ac0c59f5dcae819a6842e8e2029cf Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Fri, 13 Jul 2018 14:25:22 +0900 Subject: Fix redox libstd leftover --- src/libstd/sys/redox/process.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index d0b94e14f54..02bc467541e 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -51,7 +51,7 @@ pub struct Command { uid: Option, gid: Option, saw_nul: bool, - closures: Vec io::Result<()> + Send + Sync>>, + closures: Vec io::Result<()> + Send + Sync>>, stdin: Option, stdout: Option, stderr: Option, @@ -122,7 +122,7 @@ impl Command { } pub fn before_exec(&mut self, - f: Box io::Result<()> + Send + Sync>) { + f: Box io::Result<()> + Send + Sync>) { self.closures.push(f); } -- cgit 1.4.1-3-g733a5 From acdafa0fb13a8d1e1e76ce4bf4725104a0b749cb Mon Sep 17 00:00:00 2001 From: Markus Wein Date: Wed, 11 Jul 2018 13:21:10 +0200 Subject: Document From conversions for OsString and OsStr --- src/libstd/ffi/os_str.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index b1c6e7af693..9b91bd0d41e 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -348,6 +348,11 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] impl From for OsString { + /// Converts a [`String`] into a [`OsString`]. + /// The conversion copies the data, and includes an allocation on the heap. + /// + /// [`String`]: ../string/struct.String.html + /// [`OsString`]: struct.OsString.html fn from(s: String) -> OsString { OsString { inner: Buf::from_string(s) } } @@ -630,6 +635,10 @@ impl<'a> From<&'a OsStr> for Box { #[stable(feature = "os_string_from_box", since = "1.18.0")] impl From> for OsString { + /// Converts a `Box` into a `OsString` without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`OsString`]: ../ffi/struct.OsString.html fn from(boxed: Box) -> OsString { boxed.into_os_string() } @@ -637,6 +646,10 @@ impl From> for OsString { #[stable(feature = "box_from_os_string", since = "1.20.0")] impl From for Box { + /// Converts a [`OsString`] into a [`Box`]`` without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`OsString`]: ../ffi/struct.OsString.html fn from(s: OsString) -> Box { s.into_boxed_os_str() } @@ -652,6 +665,10 @@ impl Clone for Box { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { + /// Converts a [`OsString`] into a [`Arc`]`` without copying or allocating. + /// + /// [`Arc`]: ../sync/struct.Arc.html + /// [`OsString`]: ../ffi/struct.OsString.html #[inline] fn from(s: OsString) -> Arc { let arc = s.inner.into_arc(); @@ -670,6 +687,10 @@ impl<'a> From<&'a OsStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { + /// Converts a [`OsString`] into a [`Rc`]`` without copying or allocating. + /// + /// [`Rc`]: ../rc/struct.Rc.html + /// [`OsString`]: ../ffi/struct.OsString.html #[inline] fn from(s: OsString) -> Rc { let rc = s.inner.into_rc(); -- cgit 1.4.1-3-g733a5 From b81ee0b370ebc1a9e15a5c6a68b2201ddbdaa36f Mon Sep 17 00:00:00 2001 From: Markus Wein Date: Wed, 11 Jul 2018 13:32:03 +0200 Subject: Document From conversions for CString and CStr --- src/libstd/ffi/c_str.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index b816f4b7850..14ace795819 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -642,6 +642,11 @@ impl fmt::Debug for CString { #[stable(feature = "cstring_into", since = "1.7.0")] impl From for Vec { + /// Converts a [`CString`] into a [`Vec`]``. + /// The conversion consumes the [`CString`], and removes the terminating NUL byte. + /// + /// [`Vec`]: ../vec/struct.Vec.html + /// [`CString`]: ../ffi/struct.CString.html #[inline] fn from(s: CString) -> Vec { s.into_bytes() @@ -700,6 +705,10 @@ impl<'a> From<&'a CStr> for Box { #[stable(feature = "c_string_from_box", since = "1.18.0")] impl From> for CString { + /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// + /// [`Box`]: ../boxed/struct.Box.html + /// [`CString`]: ../ffi/struct.CString.html #[inline] fn from(s: Box) -> CString { s.into_c_string() @@ -716,6 +725,10 @@ impl Clone for Box { #[stable(feature = "box_from_c_string", since = "1.20.0")] impl From for Box { + /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Box`]: ../boxed/struct.Box.html #[inline] fn from(s: CString) -> Box { s.into_boxed_c_str() @@ -748,6 +761,10 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { + /// Converts a [`CString`] into a [`Arc`]`` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Arc`]: ../sync/struct.Arc.html #[inline] fn from(s: CString) -> Arc { let arc: Arc<[u8]> = Arc::from(s.into_inner()); @@ -766,6 +783,10 @@ impl<'a> From<&'a CStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { + /// Converts a [`CString`] into a [`Rc`]`` without copying or allocating. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`Rc`]: ../rc/struct.Rc.html #[inline] fn from(s: CString) -> Rc { let rc: Rc<[u8]> = Rc::from(s.into_inner()); @@ -839,6 +860,10 @@ impl fmt::Display for NulError { #[stable(feature = "rust1", since = "1.0.0")] impl From for io::Error { + /// Converts a [`NulError`] into a [`io::Error`]. + /// + /// [`NulError`]: ../ffi/struct.NulError.html + /// [`io::Error`]: ../io/struct.Error.html fn from(_: NulError) -> io::Error { io::Error::new(io::ErrorKind::InvalidInput, "data provided contains a nul byte") -- cgit 1.4.1-3-g733a5 From a65d535c5f4f424b1ebda78ca6a7cee98c5ce3f3 Mon Sep 17 00:00:00 2001 From: Felix Rabe Date: Tue, 17 Jul 2018 14:18:58 +0200 Subject: Fix doc comment: use `?` instead of `.unwrap()` --- src/libstd/net/tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 0f60b5b3ee4..6b4bbdddf32 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -81,7 +81,7 @@ pub struct TcpStream(net_imp::TcpStream); /// } /// /// fn main() -> io::Result<()> { -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); +/// let listener = TcpListener::bind("127.0.0.1:80")?; /// /// // accept connections and process them serially /// for stream in listener.incoming() { -- cgit 1.4.1-3-g733a5 From 3e1254d956d944a2909f61f733427350cd96f410 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Jul 2018 20:51:31 +0200 Subject: sync::Once: Use Acquire on the hot path, and explain why we don't use it elsewhere --- src/libstd/sync/once.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 51c42995d5e..443e2a6980d 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -220,7 +220,11 @@ impl Once { #[stable(feature = "rust1", since = "1.0.0")] pub fn call_once(&self, f: F) where F: FnOnce() { // Fast path, just see if we've completed initialization. - if self.state.load(Ordering::SeqCst) == COMPLETE { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us. The cold path uses SeqCst consistently + // because the performance difference really does not matter there, + // and SeqCst minimizes the chances of something going wrong. + if self.state.load(Ordering::Acquire) == COMPLETE { return } @@ -277,7 +281,11 @@ impl Once { #[unstable(feature = "once_poison", issue = "33577")] pub fn call_once_force(&self, f: F) where F: FnOnce(&OnceState) { // same as above, just with a different parameter to `call_inner`. - if self.state.load(Ordering::SeqCst) == COMPLETE { + // An `Acquire` load is enough because that makes all the initialization + // operations visible to us. The cold path uses SeqCst consistently + // because the performance difference really does not matter there, + // and SeqCst minimizes the chances of something going wrong. + if self.state.load(Ordering::Acquire) == COMPLETE { return } -- cgit 1.4.1-3-g733a5 From 8b80c9f5a142821ab49c78dd7f86b63a2c839fb8 Mon Sep 17 00:00:00 2001 From: Tommi Komulainen Date: Thu, 19 Jul 2018 21:07:40 +0200 Subject: Cursor: update docs to clarify Cursor only works with in-memory buffers Reduce misconceptions about Cursor being more general than it really is. Fixes: #52470 --- src/libstd/io/cursor.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index aadd33b3954..3622df16b9d 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -14,12 +14,13 @@ use core::convert::TryInto; use cmp; use io::{self, Initializer, SeekFrom, Error, ErrorKind}; -/// A `Cursor` wraps another type and provides it with a +/// A `Cursor` wraps an in-memory buffer and provides it with a /// [`Seek`] implementation. /// -/// `Cursor`s are typically used with in-memory buffers to allow them to -/// implement [`Read`] and/or [`Write`], allowing these buffers to be used -/// anywhere you might use a reader or writer that does actual I/O. +/// `Cursor`s are used with in-memory buffers, anything implementing +/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], +/// allowing these buffers to be used anywhere you might use a reader or writer +/// that does actual I/O. /// /// The standard library implements some I/O traits on various types which /// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and @@ -87,11 +88,11 @@ pub struct Cursor { } impl Cursor { - /// Creates a new cursor wrapping the provided underlying I/O object. + /// Creates a new cursor wrapping the provided underlying in-memory buffer. /// - /// Cursor initial position is `0` even if underlying object (e. - /// g. `Vec`) is not empty. So writing to cursor starts with - /// overwriting `Vec` content, not with appending to it. + /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`) + /// is not empty. So writing to cursor starts with overwriting `Vec` + /// content, not with appending to it. /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From f53c145ef18db6543e8e5420e172e04b6054db2e Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 14 Jul 2018 20:50:30 -0700 Subject: Improve suggestion for missing fmt str in println Avoid using `concat!(fmt, "\n")` to improve the diagnostics being emitted when the first `println!()` argument isn't a formatting string literal. --- src/libstd/macros.rs | 10 ++++- src/libsyntax/ext/base.rs | 25 ++++++++----- src/libsyntax_ext/concat.rs | 15 ++++---- src/libsyntax_ext/format.rs | 28 +++++++++++--- .../conditional_array_execution.nll.stderr | 14 ++----- src/test/ui/const-eval/issue-43197.nll.stderr | 14 ++----- src/test/ui/const-eval/issue-44578.nll.stderr | 14 ++----- src/test/ui/fmt/format-string-error.rs | 2 + src/test/ui/fmt/format-string-error.stderr | 20 +++++----- src/test/ui/macros/bad_hello.rs | 5 ++- src/test/ui/macros/bad_hello.stderr | 20 +++++++--- src/test/ui/macros/format-foreign.stderr | 5 ++- src/test/ui/macros/format-unused-lables.stderr | 43 ++++++++++------------ src/test/ui/macros/trace-macro.stderr | 9 +++-- 14 files changed, 122 insertions(+), 102 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 75f038407c1..a4a6ed73c61 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -155,8 +155,14 @@ macro_rules! print { #[stable(feature = "rust1", since = "1.0.0")] macro_rules! println { () => (print!("\n")); - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); + ($fmt:expr) => ({ + print!($fmt); + print!("\n"); + }); + ($fmt:expr, $($arg:tt)*) => ({ + print!($fmt, $($arg)*); + print!("\n"); + }); } /// Macro for printing to the standard error. diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5ec44fb5898..b55c4f99206 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -959,29 +959,34 @@ impl<'a> ExtCtxt<'a> { /// Extract a string literal from the macro expanded version of `expr`, /// emitting `err_msg` if `expr` is not a string literal. This does not stop /// compilation on error, merely emits a non-fatal error and returns None. -pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) - -> Option> { +pub fn expr_to_spanned_string<'a>( + cx: &'a mut ExtCtxt, + expr: P, + err_msg: &str, +) -> Result, DiagnosticBuilder<'a>> { // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { expr.span = expr.span.apply_mark(cx.current_expansion.mark); expr }); - // we want to be able to handle e.g. concat("foo", "bar") + // we want to be able to handle e.g. `concat!("foo", "bar")` let expr = cx.expander().fold_expr(expr); - match expr.node { + Err(match expr.node { ast::ExprKind::Lit(ref l) => match l.node { - ast::LitKind::Str(s, style) => return Some(respan(expr.span, (s, style))), - _ => cx.span_err(l.span, err_msg) + ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))), + _ => cx.struct_span_err(l.span, err_msg) }, - _ => cx.span_err(expr.span, err_msg) - } - None + _ => cx.struct_span_err(expr.span, err_msg) + }) } pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) -> Option<(Symbol, ast::StrStyle)> { - expr_to_spanned_string(cx, expr, err_msg).map(|s| s.node) + expr_to_spanned_string(cx, expr, err_msg) + .map_err(|mut err| err.emit()) + .ok() + .map(|s| s.node) } /// Non-fatally assert that `tts` is empty. Note that this function diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index 69b4a83764e..d58f4ce17e2 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -27,6 +27,7 @@ pub fn expand_syntax_ext( None => return base::DummyResult::expr(sp), }; let mut accumulator = String::new(); + let mut missing_literal = vec![]; for e in es { match e.node { ast::ExprKind::Lit(ref lit) => match lit.node { @@ -51,17 +52,15 @@ pub fn expand_syntax_ext( } }, _ => { - let mut err = cx.struct_span_err(e.span, "expected a literal"); - let snippet = cx.codemap().span_to_snippet(e.span).unwrap(); - err.span_suggestion( - e.span, - "you might be missing a string literal to format with", - format!("\"{{}}\", {}", snippet), - ); - err.emit(); + missing_literal.push(e.span); } } } + if missing_literal.len() > 0 { + let mut err = cx.struct_span_err(missing_literal, "expected a literal"); + err.note("only `&str` literals can be passed to `concat!()`"); + err.emit(); + } let sp = sp.apply_mark(cx.current_expansion.mark); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 8587d11b227..6abf987d0ab 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -703,10 +703,24 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let mut macsp = ecx.call_site(); macsp = macsp.apply_mark(ecx.current_expansion.mark); - let msg = "format argument must be a string literal."; + let msg = "format argument must be a string literal"; + let fmt_sp = efmt.span; let fmt = match expr_to_spanned_string(ecx, efmt, msg) { - Some(fmt) => fmt, - None => return DummyResult::raw_expr(sp), + Ok(fmt) => fmt, + Err(mut err) => { + let sugg_fmt = match args.len() { + 0 => "{}".to_string(), + _ => format!("{}{{}}", "{}, ".repeat(args.len())), + + }; + err.span_suggestion( + fmt_sp.shrink_to_lo(), + "you might be missing a string literal to format with", + format!("\"{}\", ", sugg_fmt), + ); + err.emit(); + return DummyResult::raw_expr(sp); + }, }; let mut cx = Context { @@ -818,7 +832,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, errs.iter().map(|&(sp, _)| sp).collect::>(), "multiple unused formatting arguments" ); - diag.span_label(cx.fmtsp, "multiple unused arguments in this statement"); + diag.span_label(cx.fmtsp, "multiple missing formatting arguments"); diag } }; @@ -861,8 +875,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, } if show_doc_note { - diag.note(concat!(stringify!($kind), " formatting not supported; see \ - the documentation for `std::fmt`")); + diag.note(concat!( + stringify!($kind), + " formatting not supported; see the documentation for `std::fmt`", + )); } }}; } diff --git a/src/test/ui/const-eval/conditional_array_execution.nll.stderr b/src/test/ui/const-eval/conditional_array_execution.nll.stderr index 8bc302a2bef..3f82311d469 100644 --- a/src/test/ui/const-eval/conditional_array_execution.nll.stderr +++ b/src/test/ui/const-eval/conditional_array_execution.nll.stderr @@ -28,25 +28,19 @@ LL | println!("{}", FOO); | ^^^ referenced constant has errors error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:19:5 + --> $DIR/conditional_array_execution.rs:19:14 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ----- attempt to subtract with overflow ... LL | println!("{}", FOO); - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ error[E0080]: erroneous constant used - --> $DIR/conditional_array_execution.rs:19:5 + --> $DIR/conditional_array_execution.rs:19:14 | LL | println!("{}", FOO); - | ^^^^^^^^^^^^^^^---^^ - | | - | referenced constant has errors - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ --- referenced constant has errors error[E0080]: referenced constant has errors --> $DIR/conditional_array_execution.rs:19:20 diff --git a/src/test/ui/const-eval/issue-43197.nll.stderr b/src/test/ui/const-eval/issue-43197.nll.stderr index 5819e6a9254..e25cb29c114 100644 --- a/src/test/ui/const-eval/issue-43197.nll.stderr +++ b/src/test/ui/const-eval/issue-43197.nll.stderr @@ -51,25 +51,19 @@ LL | println!("{} {}", X, Y); | ^ referenced constant has errors error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:5 + --> $DIR/issue-43197.rs:24:14 | LL | const X: u32 = 0-1; | --- attempt to subtract with overflow ... LL | println!("{} {}", X, Y); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^^^^ error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:5 + --> $DIR/issue-43197.rs:24:14 | LL | println!("{} {}", X, Y); - | ^^^^^^^^^^^^^^^^^^-^^^^^ - | | - | referenced constant has errors - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^^^^ - referenced constant has errors error[E0080]: referenced constant has errors --> $DIR/issue-43197.rs:24:26 diff --git a/src/test/ui/const-eval/issue-44578.nll.stderr b/src/test/ui/const-eval/issue-44578.nll.stderr index eeb152e00ea..da040747991 100644 --- a/src/test/ui/const-eval/issue-44578.nll.stderr +++ b/src/test/ui/const-eval/issue-44578.nll.stderr @@ -1,23 +1,17 @@ error[E0080]: referenced constant has errors - --> $DIR/issue-44578.rs:35:5 + --> $DIR/issue-44578.rs:35:14 | LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; | ------------------------------------ index out of bounds: the len is 1 but the index is 1 ... LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ error[E0080]: erroneous constant used - --> $DIR/issue-44578.rs:35:5 + --> $DIR/issue-44578.rs:35:14 | LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^--------------------------^^ - | | - | referenced constant has errors - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ^^^^ -------------------------- referenced constant has errors error[E0080]: referenced constant has errors --> $DIR/issue-44578.rs:35:20 diff --git a/src/test/ui/fmt/format-string-error.rs b/src/test/ui/fmt/format-string-error.rs index 5b13686240e..e48aa489f43 100644 --- a/src/test/ui/fmt/format-string-error.rs +++ b/src/test/ui/fmt/format-string-error.rs @@ -10,8 +10,10 @@ fn main() { println!("{"); + //~^ ERROR invalid format string: expected `'}'` but string was terminated println!("{{}}"); println!("}"); + //~^ ERROR invalid format string: unmatched `}` found let _ = format!("{_foo}", _foo = 6usize); //~^ ERROR invalid format string: invalid argument name `_foo` let _ = format!("{_}", _ = 6usize); diff --git a/src/test/ui/fmt/format-string-error.stderr b/src/test/ui/fmt/format-string-error.stderr index ff766ddc8fa..4c7ef11b29e 100644 --- a/src/test/ui/fmt/format-string-error.stderr +++ b/src/test/ui/fmt/format-string-error.stderr @@ -1,23 +1,21 @@ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/format-string-error.rs:12:5 + --> $DIR/format-string-error.rs:12:16 | LL | println!("{"); - | ^^^^^^^^^^^^^^ expected `'}'` in format string + | ^ expected `'}'` in format string | = note: if you intended to print `{`, you can escape it using `{{` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/format-string-error.rs:14:5 + --> $DIR/format-string-error.rs:15:15 | LL | println!("}"); - | ^^^^^^^^^^^^^^ unmatched `}` in format string + | ^ unmatched `}` in format string | = note: if you intended to print `}`, you can escape it using `}}` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: invalid format string: invalid argument name `_foo` - --> $DIR/format-string-error.rs:15:23 + --> $DIR/format-string-error.rs:17:23 | LL | let _ = format!("{_foo}", _foo = 6usize); | ^^^^ invalid argument name in format string @@ -25,7 +23,7 @@ LL | let _ = format!("{_foo}", _foo = 6usize); = note: argument names cannot start with an underscore error: invalid format string: invalid argument name `_` - --> $DIR/format-string-error.rs:17:23 + --> $DIR/format-string-error.rs:19:23 | LL | let _ = format!("{_}", _ = 6usize); | ^ invalid argument name in format string @@ -33,7 +31,7 @@ LL | let _ = format!("{_}", _ = 6usize); = note: argument names cannot start with an underscore error: invalid format string: expected `'}'` but string was terminated - --> $DIR/format-string-error.rs:19:23 + --> $DIR/format-string-error.rs:21:23 | LL | let _ = format!("{"); | ^ expected `'}'` in format string @@ -41,7 +39,7 @@ LL | let _ = format!("{"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: unmatched `}` found - --> $DIR/format-string-error.rs:21:22 + --> $DIR/format-string-error.rs:23:22 | LL | let _ = format!("}"); | ^ unmatched `}` in format string @@ -49,7 +47,7 @@ LL | let _ = format!("}"); = note: if you intended to print `}`, you can escape it using `}}` error: invalid format string: expected `'}'`, found `'/'` - --> $DIR/format-string-error.rs:23:23 + --> $DIR/format-string-error.rs:25:23 | LL | let _ = format!("{/}"); | ^ expected `}` in format string diff --git a/src/test/ui/macros/bad_hello.rs b/src/test/ui/macros/bad_hello.rs index 174dcc9b6cd..cccaf7998c9 100644 --- a/src/test/ui/macros/bad_hello.rs +++ b/src/test/ui/macros/bad_hello.rs @@ -9,5 +9,8 @@ // except according to those terms. fn main() { - println!(3 + 4); //~ ERROR expected a literal + println!(3 + 4); + //~^ ERROR format argument must be a string literal + println!(3, 4); + //~^ ERROR format argument must be a string literal } diff --git a/src/test/ui/macros/bad_hello.stderr b/src/test/ui/macros/bad_hello.stderr index 0bfb060f844..87ea515182f 100644 --- a/src/test/ui/macros/bad_hello.stderr +++ b/src/test/ui/macros/bad_hello.stderr @@ -1,12 +1,22 @@ -error: expected a literal +error: format argument must be a string literal --> $DIR/bad_hello.rs:12:14 | -LL | println!(3 + 4); //~ ERROR expected a literal +LL | println!(3 + 4); | ^^^^^ help: you might be missing a string literal to format with | -LL | println!("{}", 3 + 4); //~ ERROR expected a literal - | ^^^^^^^^^^^ +LL | println!("{}", 3 + 4); + | ^^^^^ + +error: format argument must be a string literal + --> $DIR/bad_hello.rs:14:14 + | +LL | println!(3, 4); + | ^ +help: you might be missing a string literal to format with + | +LL | println!("{}, {}", 3, 4); + | ^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/format-foreign.stderr b/src/test/ui/macros/format-foreign.stderr index 6804ce95fa8..401b2f6d67e 100644 --- a/src/test/ui/macros/format-foreign.stderr +++ b/src/test/ui/macros/format-foreign.stderr @@ -2,12 +2,13 @@ error: multiple unused formatting arguments --> $DIR/format-foreign.rs:12:30 | LL | println!("%.*3$s %s!/n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments - | -------------------------^^^^^^^^--^^^^^^^--^-- multiple unused arguments in this statement + | -------------- ^^^^^^^^ ^^^^^^^ ^ + | | + | multiple missing formatting arguments | = help: `%.*3$s` should be written as `{:.2$}` = help: `%s` should be written as `{}` = note: printf formatting not supported; see the documentation for `std::fmt` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: argument never used --> $DIR/format-foreign.rs:13:29 diff --git a/src/test/ui/macros/format-unused-lables.stderr b/src/test/ui/macros/format-unused-lables.stderr index 777b492dcb6..f764190438f 100644 --- a/src/test/ui/macros/format-unused-lables.stderr +++ b/src/test/ui/macros/format-unused-lables.stderr @@ -2,24 +2,21 @@ error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:12:22 | LL | println!("Test", 123, 456, 789); - | -----------------^^^--^^^--^^^-- multiple unused arguments in this statement - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + | ------ ^^^ ^^^ ^^^ + | | + | multiple missing formatting arguments error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:16:9 | -LL | / println!("Test2", -LL | | 123, //~ ERROR multiple unused formatting arguments - | | ^^^ -LL | | 456, - | | ^^^ -LL | | 789 - | | ^^^ -LL | | ); - | |______- multiple unused arguments in this statement - | - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) +LL | println!("Test2", + | ------- multiple missing formatting arguments +LL | 123, //~ ERROR multiple unused formatting arguments + | ^^^ +LL | 456, + | ^^^ +LL | 789 + | ^^^ error: named argument never used --> $DIR/format-unused-lables.rs:21:35 @@ -30,18 +27,18 @@ LL | println!("Some stuff", UNUSED="args"); //~ ERROR named argument never u error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:24:9 | -LL | / println!("Some more $STUFF", -LL | | "woo!", //~ ERROR multiple unused formatting arguments - | | ^^^^^^ -LL | | STUFF= -LL | | "things" - | | ^^^^^^^^ -LL | | , UNUSED="args"); - | |_______________________^^^^^^_- multiple unused arguments in this statement +LL | println!("Some more $STUFF", + | ------------------ multiple missing formatting arguments +LL | "woo!", //~ ERROR multiple unused formatting arguments + | ^^^^^^ +LL | STUFF= +LL | "things" + | ^^^^^^^^ +LL | , UNUSED="args"); + | ^^^^^^ | = help: `$STUFF` should be written as `{STUFF}` = note: shell formatting not supported; see the documentation for `std::fmt` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index 938f876872f..c98e42ea647 100644 --- a/src/test/ui/macros/trace-macro.stderr +++ b/src/test/ui/macros/trace-macro.stderr @@ -5,8 +5,9 @@ LL | println!("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: expanding `println! { "Hello, World!" }` - = note: to `print ! ( concat ! ( "Hello, World!" , "/n" ) )` - = note: expanding `print! { concat ! ( "Hello, World!" , "/n" ) }` - = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( "Hello, World!" , "/n" ) ) - )` + = note: to `{ print ! ( "Hello, World!" ) ; print ! ( "/n" ) ; }` + = note: expanding `print! { "Hello, World!" }` + = note: to `$crate :: io :: _print ( format_args ! ( "Hello, World!" ) )` + = note: expanding `print! { "/n" }` + = note: to `$crate :: io :: _print ( format_args ! ( "/n" ) )` -- cgit 1.4.1-3-g733a5 From fbce952193d38328c39262cf2fb7f7bfbe088a70 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 15 Jul 2018 11:52:11 -0700 Subject: review comments: modify note wording and change `println` - Don't print the newline on its own to avoid the possibility of printing it out of order due to `stdout` locking. - Modify wording of `concat!()` with non-literals to not mislead into believing that only `&str` literals are accepted. - Add test for `concat!()` with non-literals. --- src/libstd/macros.rs | 9 +-------- src/libsyntax_ext/concat.rs | 2 +- src/test/ui/macros/bad-concat.rs | 18 ++++++++++++++++++ src/test/ui/macros/bad-concat.stderr | 10 ++++++++++ src/test/ui/macros/trace-macro.stderr | 9 ++++----- 5 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/macros/bad-concat.rs create mode 100644 src/test/ui/macros/bad-concat.stderr (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a4a6ed73c61..7f3c8fcdd5a 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -155,14 +155,7 @@ macro_rules! print { #[stable(feature = "rust1", since = "1.0.0")] macro_rules! println { () => (print!("\n")); - ($fmt:expr) => ({ - print!($fmt); - print!("\n"); - }); - ($fmt:expr, $($arg:tt)*) => ({ - print!($fmt, $($arg)*); - print!("\n"); - }); + ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); } /// Macro for printing to the standard error. diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index d58f4ce17e2..99dba8af754 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -58,7 +58,7 @@ pub fn expand_syntax_ext( } if missing_literal.len() > 0 { let mut err = cx.struct_span_err(missing_literal, "expected a literal"); - err.note("only `&str` literals can be passed to `concat!()`"); + err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`"); err.emit(); } let sp = sp.apply_mark(cx.current_expansion.mark); diff --git a/src/test/ui/macros/bad-concat.rs b/src/test/ui/macros/bad-concat.rs new file mode 100644 index 00000000000..e7adee8ce85 --- /dev/null +++ b/src/test/ui/macros/bad-concat.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x: u32 = 42; + let y: f64 = 3.14; + let z = "foo"; + let _ = concat!(x, y, z, "bar"); + //~^ ERROR expected a literal + //~| NOTE only literals +} diff --git a/src/test/ui/macros/bad-concat.stderr b/src/test/ui/macros/bad-concat.stderr new file mode 100644 index 00000000000..b97e4f26824 --- /dev/null +++ b/src/test/ui/macros/bad-concat.stderr @@ -0,0 +1,10 @@ +error: expected a literal + --> $DIR/bad-concat.rs:15:21 + | +LL | let _ = concat!(x, y, z, "bar"); + | ^ ^ ^ + | + = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()` + +error: aborting due to previous error + diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index c98e42ea647..6d8a329be80 100644 --- a/src/test/ui/macros/trace-macro.stderr +++ b/src/test/ui/macros/trace-macro.stderr @@ -5,9 +5,8 @@ LL | println!("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: expanding `println! { "Hello, World!" }` - = note: to `{ print ! ( "Hello, World!" ) ; print ! ( "/n" ) ; }` - = note: expanding `print! { "Hello, World!" }` - = note: to `$crate :: io :: _print ( format_args ! ( "Hello, World!" ) )` - = note: expanding `print! { "/n" }` - = note: to `$crate :: io :: _print ( format_args ! ( "/n" ) )` + = note: to `print ! ( "{}/n" , format_args ! ( "Hello, World!" ) )` + = note: expanding `print! { "{}/n" , format_args ! ( "Hello, World!" ) }` + = note: to `$crate :: io :: _print ( + format_args ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) )` -- cgit 1.4.1-3-g733a5 From e613bfb7015744c25ce838b64bf8db31acff49f6 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 15 Jul 2018 12:28:42 -0700 Subject: Same change as `println` for `eprintln` --- src/libstd/macros.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 7f3c8fcdd5a..527bab759b0 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -211,8 +211,7 @@ macro_rules! eprint { #[stable(feature = "eprint", since = "1.19.0")] macro_rules! eprintln { () => (eprint!("\n")); - ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); + ($($arg:tt)*) => (eprint!("{}\n", format_args!($($arg)*))); } #[macro_export] -- cgit 1.4.1-3-g733a5 From 154dee2dccd45f929b0a3d2ce2d45739513f77c8 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 19 Jul 2018 18:53:26 -0700 Subject: rework println --- src/libfmt_macros/lib.rs | 6 +++++- src/libstd/macros.rs | 26 ++++++++++++++++++++++++-- src/libsyntax_ext/format.rs | 22 ++++++++++++++++++++-- src/libsyntax_ext/lib.rs | 10 ++++++++++ src/test/ui/macros/trace-macro.stderr | 8 ++++---- 5 files changed, 63 insertions(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 51c3efb41ad..ee590bc3b5e 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -273,7 +273,11 @@ impl<'a> Parser<'a> { } } else { let msg = format!("expected `{:?}` but string was terminated", c); - let pos = self.input.len() + 1; // point at closing `"` + // point at closing `"`, unless the last char is `\n` to account for `println` + let pos = match self.input.chars().last() { + Some('\n') => self.input.len(), + _ => self.input.len() + 1, + }; if c == '}' { self.err_with_note(msg, format!("expected `{:?}`", c), diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 527bab759b0..a4bcf7fd26c 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -153,9 +153,17 @@ macro_rules! print { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] macro_rules! println { () => (print!("\n")); - ($($arg:tt)*) => (print!("{}\n", format_args!($($arg)*))); + ($($arg:tt)*) => ({ + #[cfg(not(stage0))] { + ($crate::io::_print(format_args_nl!($($arg)*))); + } + #[cfg(stage0)] { + print!("{}\n", format_args!($($arg)*)) + } + }) } /// Macro for printing to the standard error. @@ -211,7 +219,8 @@ macro_rules! eprint { #[stable(feature = "eprint", since = "1.19.0")] macro_rules! eprintln { () => (eprint!("\n")); - ($($arg:tt)*) => (eprint!("{}\n", format_args!($($arg)*))); + ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); } #[macro_export] @@ -397,6 +406,19 @@ pub mod builtin { ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); } + /// Internal version of [`format_args`]. + /// + /// This macro differs from [`format_args`] in that it appends a newline to the format string + /// and nothing more. It is perma-unstable. + /// + /// [`format_args`]: ../std/macro.format_args.html + #[doc(hidden)] + #[unstable(feature = "println_format_args", issue="0")] + #[macro_export] + macro_rules! format_args_nl { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); + } /// Inspect an environment variable at compile time. /// /// This macro will expand to the value of the named environment variable at diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 6abf987d0ab..d3e5adf6835 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -683,7 +683,20 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp = sp.apply_mark(ecx.current_expansion.mark); match parse_args(ecx, sp, tts) { Some((efmt, args, names)) => { - MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names)) + MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, false)) + } + None => DummyResult::expr(sp), + } +} + +pub fn expand_format_args_nl<'cx>(ecx: &'cx mut ExtCtxt, + mut sp: Span, + tts: &[tokenstream::TokenTree]) + -> Box { + sp = sp.apply_mark(ecx.current_expansion.mark); + match parse_args(ecx, sp, tts) { + Some((efmt, args, names)) => { + MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, true)) } None => DummyResult::expr(sp), } @@ -695,7 +708,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, efmt: P, args: Vec>, - names: HashMap) + names: HashMap, + append_newline: bool) -> P { // NOTE: this verbose way of initializing `Vec>` is because // `ArgumentType` does not derive `Clone`. @@ -706,6 +720,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let msg = "format argument must be a string literal"; let fmt_sp = efmt.span; let fmt = match expr_to_spanned_string(ecx, efmt, msg) { + Ok(mut fmt) if append_newline => { + fmt.node.0 = Symbol::intern(&format!("{}\n", fmt.node.0)); + fmt + } Ok(fmt) => fmt, Err(mut err) => { let sugg_fmt = match args.len() { diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index bdf7a8d7040..ff76e788b3c 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -139,6 +139,16 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, unstable_feature: None, edition: hygiene::default_edition(), }); + register(Symbol::intern("format_args_nl"), + NormalTT { + expander: Box::new(format::expand_format_args_nl), + def_info: None, + allow_internal_unstable: true, + allow_internal_unsafe: false, + local_inner_macros: false, + unstable_feature: None, + edition: hygiene::default_edition(), + }); for (name, ext) in user_exts { register(name, ext); diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index 6d8a329be80..2a30d983751 100644 --- a/src/test/ui/macros/trace-macro.stderr +++ b/src/test/ui/macros/trace-macro.stderr @@ -5,8 +5,8 @@ LL | println!("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: expanding `println! { "Hello, World!" }` - = note: to `print ! ( "{}/n" , format_args ! ( "Hello, World!" ) )` - = note: expanding `print! { "{}/n" , format_args ! ( "Hello, World!" ) }` - = note: to `$crate :: io :: _print ( - format_args ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) )` + = note: to `{ + # [ cfg ( not ( stage0 ) ) ] { + ( $crate :: io :: _print ( format_args_nl ! ( "Hello, World!" ) ) ) ; } # [ + cfg ( stage0 ) ] { print ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) } }` -- cgit 1.4.1-3-g733a5 From a18be44d6318b04a604d1a9b3f965fbdaab8abf6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 21 Jul 2018 02:49:34 +0300 Subject: Avoid using `#[macro_export]` for documenting builtin macros --- src/libcore/macros.rs | 49 +++++++++++++++---------------------------- src/librustc/hir/lowering.rs | 3 ++- src/librustdoc/clean/mod.rs | 12 +++++------ src/libstd/macros.rs | 34 +++++++++++++++--------------- src/libsyntax/feature_gate.rs | 3 ++- 5 files changed, 43 insertions(+), 58 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c830c22ee5f..83f9dfea8f2 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -543,6 +543,7 @@ macro_rules! unimplemented { /// into libsyntax itself. /// /// For more information, see documentation for `std`'s macros. +#[cfg(dox)] mod builtin { /// Unconditionally causes compilation to fail with the given error message when encountered. @@ -551,8 +552,7 @@ mod builtin { /// /// [`std::compile_error!`]: ../std/macro.compile_error.html #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ }); @@ -564,8 +564,7 @@ mod builtin { /// /// [`std::format_args!`]: ../std/macro.format_args.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); @@ -577,8 +576,7 @@ mod builtin { /// /// [`std::env!`]: ../std/macro.env.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -590,8 +588,7 @@ mod builtin { /// /// [`std::option_env!`]: ../std/macro.option_env.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -603,8 +600,7 @@ mod builtin { /// /// [`std::concat_idents!`]: ../std/macro.concat_idents.html #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! concat_idents { ($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ }); @@ -616,8 +612,7 @@ mod builtin { /// /// [`std::concat!`]: ../std/macro.concat.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }); @@ -629,8 +624,7 @@ mod builtin { /// /// [`std::line!`]: ../std/macro.line.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -639,8 +633,7 @@ mod builtin { /// /// [`std::column!`]: ../std/macro.column.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -649,8 +642,7 @@ mod builtin { /// /// [`std::file!`]: ../std/macro.file.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its arguments. @@ -659,8 +651,7 @@ mod builtin { /// /// [`std::stringify!`]: ../std/macro.stringify.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -669,8 +660,7 @@ mod builtin { /// /// [`std::include_str!`]: ../std/macro.include_str.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -682,8 +672,7 @@ mod builtin { /// /// [`std::include_bytes!`]: ../std/macro.include_bytes.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -695,8 +684,7 @@ mod builtin { /// /// [`std::module_path!`]: ../std/macro.module_path.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags, at compile-time. @@ -705,8 +693,7 @@ mod builtin { /// /// [`std::cfg!`]: ../std/macro.cfg.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -715,8 +702,7 @@ mod builtin { /// /// [`std::include!`]: ../std/macro.include.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -727,9 +713,8 @@ mod builtin { /// For more information, see the documentation for [`std::assert!`]. /// /// [`std::assert!`]: ../std/macro.assert.html - #[macro_export] + #[rustc_doc_only_macro] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(dox)] macro_rules! assert { ($cond:expr) => ({ /* compiler built-in */ }); ($cond:expr,) => ({ /* compiler built-in */ }); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 99db718bdf8..8e27a9914f4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3191,7 +3191,8 @@ impl<'a> LoweringContext<'a> { let mut vis = self.lower_visibility(&i.vis, None); let attrs = self.lower_attrs(&i.attrs); if let ItemKind::MacroDef(ref def) = i.node { - if !def.legacy || attr::contains_name(&i.attrs, "macro_export") { + if !def.legacy || attr::contains_name(&i.attrs, "macro_export") || + attr::contains_name(&i.attrs, "rustc_doc_only_macro") { let body = self.lower_token_stream(def.stream()); self.exported_macros.push(hir::MacroDef { name, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b7edf73f7ce..44a1cfa6246 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1253,15 +1253,13 @@ fn macro_resolve(cx: &DocContext, path_str: &str) -> Option { .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false); if let Ok(def) = res { if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) { - Some(def) - } else { - None + return Some(def); } - } else if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { - Some(*def) - } else { - None } + if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) { + return Some(*def); + } + None } #[derive(Debug)] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 75f038407c1..57ae5d3f862 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -303,7 +303,7 @@ macro_rules! assert_approx_eq { /// macro, but are documented here. Their implementations can be found hardcoded /// into libsyntax itself. #[cfg(dox)] -pub mod builtin { +mod builtin { /// Unconditionally causes compilation to fail with the given error message when encountered. /// @@ -341,7 +341,7 @@ pub mod builtin { /// /// [`panic!`]: ../std/macro.panic.html #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ }); @@ -393,7 +393,7 @@ pub mod builtin { /// assert_eq!(s, format!("hello {}", "world")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); @@ -431,7 +431,7 @@ pub mod builtin { /// error: what's that?! /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -457,7 +457,7 @@ pub mod builtin { /// println!("the secret key might be: {:?}", key); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -488,7 +488,7 @@ pub mod builtin { /// # } /// ``` #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat_idents { ($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ }); @@ -510,7 +510,7 @@ pub mod builtin { /// assert_eq!(s, "test10btrue"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }); @@ -538,7 +538,7 @@ pub mod builtin { /// println!("defined on line: {}", current_line); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -563,7 +563,7 @@ pub mod builtin { /// println!("defined on column: {}", current_col); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -587,7 +587,7 @@ pub mod builtin { /// println!("defined in file: {}", this_file); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its arguments. @@ -606,7 +606,7 @@ pub mod builtin { /// assert_eq!(one_plus_one, "1 + 1"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -640,7 +640,7 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -677,7 +677,7 @@ pub mod builtin { /// /// Compiling 'main.rs' and running the resulting binary will print "adiós". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -701,7 +701,7 @@ pub mod builtin { /// test::foo(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags, at compile-time. @@ -723,7 +723,7 @@ pub mod builtin { /// }; /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -766,7 +766,7 @@ pub mod builtin { /// Compiling 'main.rs' and running the resulting binary will print /// "🙈🙊🙉🙈🙊🙉". #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -819,7 +819,7 @@ pub mod builtin { /// assert!(a + b == 30, "a = {}, b = {}", a, b); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] + #[rustc_doc_only_macro] macro_rules! assert { ($cond:expr) => ({ /* compiler built-in */ }); ($cond:expr,) => ({ /* compiler built-in */ }); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d35249b6343..6164a2bf42f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -686,7 +686,8 @@ pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, Att } pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) + BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) || + attr.name().as_str().starts_with("rustc_") } // Attributes that have a special meaning to rustc or rustdoc -- cgit 1.4.1-3-g733a5 From d77defcca114c14e6bbedc24697ead76a249a567 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 19 Jul 2018 07:01:37 -0700 Subject: Update stdsimd to undo an accidental stabilization Closes #52403 --- src/libcore/lib.rs | 3 --- src/libstd/lib.rs | 4 ---- src/stdsimd | 2 +- src/test/rustdoc-js/multi-query.js | 1 - 4 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index bbe6ae8619f..72074e1dbce 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -244,9 +244,6 @@ macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*) #[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 mod coresimd; -#[unstable(feature = "stdsimd", issue = "48556")] -#[cfg(not(stage0))] -pub use coresimd::simd; #[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(not(stage0))] pub use coresimd::arch; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fec14b8d67d..3c01de2e997 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -532,12 +532,8 @@ mod stdsimd; #[cfg(not(stage0))] mod coresimd { pub use core::arch; - pub use core::simd; } -#[unstable(feature = "stdsimd", issue = "48556")] -#[cfg(all(not(stage0), not(test)))] -pub use stdsimd::simd; #[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(all(not(stage0), not(test)))] pub use stdsimd::arch; diff --git a/src/stdsimd b/src/stdsimd index 886ff388fbb..b9de11ab430 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 886ff388fbbe8798e292431d824a5ff3c3458f4d +Subproject commit b9de11ab43090c71ff7ab159a479394df1f968ab diff --git a/src/test/rustdoc-js/multi-query.js b/src/test/rustdoc-js/multi-query.js index 3793ca6599c..3f583a3600a 100644 --- a/src/test/rustdoc-js/multi-query.js +++ b/src/test/rustdoc-js/multi-query.js @@ -15,6 +15,5 @@ const EXPECTED = { { 'path': 'std', 'name': 'str' }, { 'path': 'std', 'name': 'u8' }, { 'path': 'std::ffi', 'name': 'CStr' }, - { 'path': 'std::simd', 'name': 'u8x2' }, ], }; -- cgit 1.4.1-3-g733a5 From c581b96f39a8c9e75261ae735d976e989488e637 Mon Sep 17 00:00:00 2001 From: Felix Rabe Date: Sat, 21 Jul 2018 11:49:52 +0200 Subject: Typo --- src/libstd/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 2d868629278..0c60129494d 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1836,7 +1836,7 @@ impl Path { /// * On Unix, a path has a root if it begins with `/`. /// /// * On Windows, a path has a root if it: - /// * has no prefix and begins with a separator, e.g. `\\windows` + /// * has no prefix and begins with a separator, e.g. `\windows` /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` /// * has any non-disk prefix, e.g. `\\server\share` /// -- cgit 1.4.1-3-g733a5 From 00d500052c72775ab994b5634195976f85b4e0d6 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 21 Jul 2018 15:50:46 -0700 Subject: Gate `format_args_nll` behind feature flag --- src/libstd/macros.rs | 2 +- src/libsyntax/ext/expand.rs | 1 + src/libsyntax/feature_gate.rs | 4 ++++ src/libsyntax_ext/format.rs | 15 +++++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a4bcf7fd26c..49de9f80271 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -413,7 +413,7 @@ pub mod builtin { /// /// [`format_args`]: ../std/macro.format_args.html #[doc(hidden)] - #[unstable(feature = "println_format_args", issue="0")] + #[unstable(feature = "format_args_nl", issue="0")] #[macro_export] macro_rules! format_args_nl { ($fmt:expr) => ({ /* compiler built-in */ }); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1241e230b26..4d1ca50a893 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1592,6 +1592,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_trace_macros = trace_macros, fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = custom_derive, + fn enable_format_args_nl = format_args_nl, fn use_extern_macros_enabled = use_extern_macros, fn macros_in_extern_enabled = macros_in_extern, fn proc_macro_mod = proc_macro_mod, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0f200479fe2..5b5453d5502 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -129,6 +129,7 @@ declare_features! ( // rustc internal, for now: (active, intrinsics, "1.0.0", None, None), (active, lang_items, "1.0.0", None, None), + (active, format_args_nl, "1.29.0", None, None), (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), (active, linkage, "1.0.0", Some(29603), None), @@ -1327,6 +1328,9 @@ pub const EXPLAIN_LOG_SYNTAX: &'static str = pub const EXPLAIN_CONCAT_IDENTS: &'static str = "`concat_idents` is not stable enough for use and is subject to change"; +pub const EXPLAIN_FORMAT_ARGS_NL: &'static str = + "`format_args_nl` is only for internal language use and is subject to change"; + pub const EXPLAIN_TRACE_MACROS: &'static str = "`trace_macros` is not stable enough for use and is subject to change"; pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str = diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 9f153c36733..5b8f059fd14 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -17,6 +17,7 @@ use syntax::ast; use syntax::ext::base::*; use syntax::ext::base; use syntax::ext::build::AstBuilder; +use syntax::feature_gate; use syntax::parse::token; use syntax::ptr::P; use syntax::symbol::Symbol; @@ -693,6 +694,20 @@ pub fn expand_format_args_nl<'cx>(ecx: &'cx mut ExtCtxt, mut sp: Span, tts: &[tokenstream::TokenTree]) -> Box { + //if !ecx.ecfg.enable_allow_internal_unstable() { + + // For some reason, the only one that actually works for `println` is the first check + if !sp.allows_unstable() // the enclosing span is marked as `#[allow_insternal_unsable]` + || !ecx.ecfg.enable_allow_internal_unstable() // NOTE: when is this enabled? + || !ecx.ecfg.enable_format_args_nl() // enabled using `#[feature(format_args_nl]` + { + feature_gate::emit_feature_err(&ecx.parse_sess, + "format_args_nl", + sp, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_FORMAT_ARGS_NL); + return base::DummyResult::expr(sp); + } sp = sp.apply_mark(ecx.current_expansion.mark); match parse_args(ecx, sp, tts) { Some((efmt, args, names)) => { -- cgit 1.4.1-3-g733a5 From a7a68370a72cc553c8ca983fe593062235360b9b Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 21 Jul 2018 15:56:37 -0700 Subject: Change `eprintln!()` Address #30143 as well. `writeln!()` hasn't been changed. --- src/libstd/macros.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 49de9f80271..f06b8f621f2 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -217,10 +217,17 @@ macro_rules! eprint { /// ``` #[macro_export] #[stable(feature = "eprint", since = "1.19.0")] +#[allow_internal_unstable] macro_rules! eprintln { () => (eprint!("\n")); - ($fmt:expr) => (eprint!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*)); + ($($arg:tt)*) => ({ + #[cfg(not(stage0))] { + ($crate::io::_eprint(format_args_nl!($($arg)*))); + } + #[cfg(stage0)] { + eprint!("{}\n", format_args!($($arg)*)) + } + }) } #[macro_export] -- cgit 1.4.1-3-g733a5 From 6aa17a3c687c3e78ba65953f88d763ab2b437384 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 21 Jul 2018 17:59:17 -0700 Subject: Don't use the new `eprintln` for stage0 and stage1 I'm not entirely sure why (or if) this is needed. --- src/libstd/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index f06b8f621f2..6309ca069fe 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -221,10 +221,10 @@ macro_rules! eprint { macro_rules! eprintln { () => (eprint!("\n")); ($($arg:tt)*) => ({ - #[cfg(not(stage0))] { + #[cfg(all(not(stage0), not(stage1)))] { ($crate::io::_eprint(format_args_nl!($($arg)*))); } - #[cfg(stage0)] { + #[cfg(any(stage0, stage1))] { eprint!("{}\n", format_args!($($arg)*)) } }) -- cgit 1.4.1-3-g733a5 From 3c817259e3ff08b673c74b48742d118a238befe6 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 21 Jul 2018 18:24:10 -0700 Subject: fix tidy ~ again --- src/libstd/macros.rs | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6309ca069fe..76f38646308 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -413,19 +413,6 @@ pub mod builtin { ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); } - /// Internal version of [`format_args`]. - /// - /// This macro differs from [`format_args`] in that it appends a newline to the format string - /// and nothing more. It is perma-unstable. - /// - /// [`format_args`]: ../std/macro.format_args.html - #[doc(hidden)] - #[unstable(feature = "format_args_nl", issue="0")] - #[macro_export] - macro_rules! format_args_nl { - ($fmt:expr) => ({ /* compiler built-in */ }); - ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); - } /// Inspect an environment variable at compile time. /// /// This macro will expand to the value of the named environment variable at -- cgit 1.4.1-3-g733a5 From 49c8ba91c73c97404d3308133594702a2bf48fd1 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Mon, 23 Jul 2018 15:32:57 +0200 Subject: Change single char str patterns to chars --- src/librustc/dep_graph/debug.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_mir/util/pretty.rs | 6 +++--- src/librustc_target/abi/mod.rs | 4 ++-- src/libstd/sys/redox/net/mod.rs | 4 ++-- src/libstd/sys/unix/os.rs | 2 +- src/tools/tidy/src/deps.rs | 2 +- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/style.rs | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs index e56333aba9b..f0e43e78a50 100644 --- a/src/librustc/dep_graph/debug.rs +++ b/src/librustc/dep_graph/debug.rs @@ -40,7 +40,7 @@ impl DepNodeFilter { /// Tests whether `node` meets the filter, returning true if so. pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{:?}", node); - self.text.split("&") + self.text.split('&') .map(|s| s.trim()) .all(|f| debug_str.contains(f)) } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index fdcae38fc6a..262a617cb69 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { &attr::Stable {since: stab_since}) = (&stab.rustc_depr, &stab.level) { // Explicit version of iter::order::lt to handle parse errors properly for (dep_v, stab_v) in - dep_since.as_str().split(".").zip(stab_since.as_str().split(".")) { + dep_since.as_str().split('.').zip(stab_since.as_str().split('.')) { if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::(), stab_v.parse()) { match dep_v.cmp(&stab_v) { Ordering::Less => { diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 6472e588bc6..0c4edb44272 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -117,8 +117,8 @@ pub fn dump_enabled<'a, 'gcx, 'tcx>( // see notes on #41697 below tcx.item_path_str(source.def_id) }); - filters.split("|").any(|or_filter| { - or_filter.split("&").all(|and_filter| { + filters.split('|').any(|or_filter| { + or_filter.split('&').all(|and_filter| { and_filter == "all" || pass_name.contains(and_filter) || node_path.contains(and_filter) }) }) @@ -388,7 +388,7 @@ struct ExtraComments<'cx, 'gcx: 'tcx, 'tcx: 'cx> { impl<'cx, 'gcx, 'tcx> ExtraComments<'cx, 'gcx, 'tcx> { fn push(&mut self, lines: &str) { - for line in lines.split("\n") { + for line in lines.split('\n') { self.comments.push(line.to_string()); } } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 57622692426..df09be00c34 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -92,8 +92,8 @@ impl TargetDataLayout { let mut dl = TargetDataLayout::default(); let mut i128_align_src = 64; - for spec in target.data_layout.split("-") { - match &spec.split(":").collect::>()[..] { + for spec in target.data_layout.split('-') { + match &spec.split(':').collect::>()[..] { &["e"] => dl.endian = Endian::Little, &["E"] => dl.endian = Endian::Big, &["a", ref a..] => dl.aggregate_align = align(a, "a")?, diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs index 0291d7f0e92..67f22231d5f 100644 --- a/src/libstd/sys/redox/net/mod.rs +++ b/src/libstd/sys/redox/net/mod.rs @@ -41,12 +41,12 @@ impl Iterator for LookupHost { pub fn lookup_host(host: &str) -> Result { let mut ip_string = String::new(); File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?; - let ip: Vec = ip_string.trim().split(".").map(|part| part.parse::() + let ip: Vec = ip_string.trim().split('.').map(|part| part.parse::() .unwrap_or(0)).collect(); let mut dns_string = String::new(); File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?; - let dns: Vec = dns_string.trim().split(".").map(|part| part.parse::() + let dns: Vec = dns_string.trim().split('.').map(|part| part.parse::() .unwrap_or(0)).collect(); if ip.len() == 4 && dns.len() == 4 { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 82d05f78850..addf555eb10 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -564,7 +564,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> { // ignoring any extra dot-separated parts. Otherwise return None. #[cfg(target_env = "gnu")] fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split(".").map(str::parse::).fuse(); + let mut parsed_ints = version.split('.').map(str::parse::).fuse(); match (parsed_ints.next(), parsed_ints.next()) { (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), _ => None diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 942d27202ec..5105fc4ca4c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -165,7 +165,7 @@ impl<'a> Crate<'a> { impl<'a> CrateVersion<'a> { /// Returns the struct and whether or not the dep is in-tree pub fn from_str(s: &'a str) -> (Self, bool) { - let mut parts = s.split(" "); + let mut parts = s.split(' '); let name = parts.next().unwrap(); let version = parts.next().unwrap(); let path = parts.next().unwrap(); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 4c0db993809..c9bc1b9d849 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -257,7 +257,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { None } else { next_feature_is_rustc_internal = false; - let s = issue_str.split("(").nth(1).unwrap().split(")").nth(0).unwrap(); + let s = issue_str.split('(').nth(1).unwrap().split(')').nth(0).unwrap(); Some(s.parse().unwrap()) }; Some((name.to_owned(), diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index b784a0e4c5f..f2f35f0f586 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -131,7 +131,7 @@ pub fn check(path: &Path, bad: &mut bool) { let skip_length = contents.contains("ignore-tidy-linelength"); let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace"); let mut trailing_new_lines = 0; - for (i, line) in contents.split("\n").enumerate() { + for (i, line) in contents.split('\n').enumerate() { let mut err = |msg: &str| { tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); }; -- cgit 1.4.1-3-g733a5 From ed5edcb3186e87715143bbd53ab1dfa69771cbf9 Mon Sep 17 00:00:00 2001 From: Markus Wein Date: Mon, 23 Jul 2018 15:38:15 +0200 Subject: Seperate summaries from rest of the comment --- src/libstd/ffi/c_str.rs | 1 + src/libstd/ffi/os_str.rs | 1 + 2 files changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 14ace795819..01558457f6c 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -643,6 +643,7 @@ impl fmt::Debug for CString { #[stable(feature = "cstring_into", since = "1.7.0")] impl From for Vec { /// Converts a [`CString`] into a [`Vec`]``. + /// /// The conversion consumes the [`CString`], and removes the terminating NUL byte. /// /// [`Vec`]: ../vec/struct.Vec.html diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 9b91bd0d41e..9e501a84e05 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -349,6 +349,7 @@ impl OsString { #[stable(feature = "rust1", since = "1.0.0")] impl From for OsString { /// Converts a [`String`] into a [`OsString`]. + /// /// The conversion copies the data, and includes an allocation on the heap. /// /// [`String`]: ../string/struct.String.html -- cgit 1.4.1-3-g733a5 From 1581971635b725764f23be86a618decffb0d754e Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Tue, 24 Jul 2018 05:27:45 +0200 Subject: Stablize Redox Unix Sockets --- src/libstd/sys/redox/ext/net.rs | 42 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sys/redox/ext/net.rs b/src/libstd/sys/redox/ext/net.rs index 4c5f8574621..2ab77703242 100644 --- a/src/libstd/sys/redox/ext/net.rs +++ b/src/libstd/sys/redox/ext/net.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "unix_socket_redox", reason = "new feature", issue="51553")] +#![stable(feature = "unix_socket_redox", since = "1.29")] //! Unix-specific networking functionality @@ -37,6 +37,7 @@ use sys::{cvt, fd::FileDesc, syscall}; /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` #[derive(Clone)] +#[stable(feature = "unix_socket_redox", since = "1.29")] pub struct SocketAddr(()); impl SocketAddr { @@ -64,6 +65,7 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.as_pathname(), None); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn as_pathname(&self) -> Option<&Path> { None } @@ -91,10 +93,12 @@ impl SocketAddr { /// let addr = socket.local_addr().expect("Couldn't get local address"); /// assert_eq!(addr.is_unnamed(), true); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn is_unnamed(&self) -> bool { false } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl fmt::Debug for SocketAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "SocketAddr") @@ -115,8 +119,10 @@ impl fmt::Debug for SocketAddr { /// stream.read_to_string(&mut response).unwrap(); /// println!("{}", response); /// ``` +#[stable(feature = "unix_socket_redox", since = "1.29")] pub struct UnixStream(FileDesc); +#[stable(feature = "unix_socket_redox", since = "1.29")] impl fmt::Debug for UnixStream { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixStream"); @@ -147,6 +153,7 @@ impl UnixStream { /// } /// }; /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn connect>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC)) @@ -177,6 +184,7 @@ impl UnixStream { /// } /// }; /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn pair() -> io::Result<(UnixStream, UnixStream)> { let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC)) .map(FileDesc::new)?; @@ -200,6 +208,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixStream) } @@ -214,6 +223,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.local_addr().expect("Couldn't get local address"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox")) } @@ -228,6 +238,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// let addr = socket.peer_addr().expect("Couldn't get peer address"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn peer_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox")) } @@ -266,6 +277,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn set_read_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox")) } @@ -304,6 +316,7 @@ impl UnixStream { /// let err = result.unwrap_err(); /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput) /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn set_write_timeout(&self, _timeout: Option) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox")) } @@ -320,6 +333,7 @@ impl UnixStream { /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn read_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox")) } @@ -336,6 +350,7 @@ impl UnixStream { /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout"); /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0))); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn write_timeout(&self) -> io::Result> { Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox")) } @@ -350,6 +365,7 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -369,6 +385,7 @@ impl UnixStream { /// /// # Platform specific /// On Redox this always returns None. + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -390,11 +407,13 @@ impl UnixStream { /// let socket = UnixStream::connect("/tmp/sock").unwrap(); /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox")) } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl io::Read for UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { io::Read::read(&mut &*self, buf) @@ -406,6 +425,7 @@ impl io::Read for UnixStream { } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl<'a> io::Read for &'a UnixStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) @@ -417,6 +437,7 @@ impl<'a> io::Read for &'a UnixStream { } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl io::Write for UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { io::Write::write(&mut &*self, buf) @@ -427,6 +448,7 @@ impl io::Write for UnixStream { } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl<'a> io::Write for &'a UnixStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) @@ -437,18 +459,21 @@ impl<'a> io::Write for &'a UnixStream { } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl AsRawFd for UnixStream { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl FromRawFd for UnixStream { unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { UnixStream(FileDesc::new(fd)) } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl IntoRawFd for UnixStream { fn into_raw_fd(self) -> RawFd { self.0.into_raw() @@ -483,8 +508,10 @@ impl IntoRawFd for UnixStream { /// } /// } /// ``` +#[stable(feature = "unix_socket_redox", since = "1.29")] pub struct UnixListener(FileDesc); +#[stable(feature = "unix_socket_redox", since = "1.29")] impl fmt::Debug for UnixListener { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("UnixListener"); @@ -512,6 +539,7 @@ impl UnixListener { /// } /// }; /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn bind>(path: P) -> io::Result { if let Some(s) = path.as_ref().to_str() { cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC)) @@ -545,6 +573,7 @@ impl UnixListener { /// Err(e) => println!("accept function failed: {:?}", e), /// } /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(()))) } @@ -564,6 +593,7 @@ impl UnixListener { /// /// let listener_copy = listener.try_clone().expect("try_clone failed"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn try_clone(&self) -> io::Result { self.0.duplicate().map(UnixListener) } @@ -579,6 +609,7 @@ impl UnixListener { /// /// let addr = listener.local_addr().expect("Couldn't get local address"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn local_addr(&self) -> io::Result { Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox")) } @@ -594,6 +625,7 @@ impl UnixListener { /// /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0.set_nonblocking(nonblocking) } @@ -614,6 +646,7 @@ impl UnixListener { /// /// # Platform specific /// On Redox this always returns None. + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn take_error(&self) -> io::Result> { Ok(None) } @@ -649,29 +682,34 @@ impl UnixListener { /// } /// } /// ``` + #[stable(feature = "unix_socket_redox", since = "1.29")] pub fn incoming<'a>(&'a self) -> Incoming<'a> { Incoming { listener: self } } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl AsRawFd for UnixListener { fn as_raw_fd(&self) -> RawFd { self.0.raw() } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl FromRawFd for UnixListener { unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { UnixListener(FileDesc::new(fd)) } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl IntoRawFd for UnixListener { fn into_raw_fd(self) -> RawFd { self.0.into_raw() } } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; @@ -712,10 +750,12 @@ impl<'a> IntoIterator for &'a UnixListener { /// } /// ``` #[derive(Debug)] +#[stable(feature = "unix_socket_redox", since = "1.29")] pub struct Incoming<'a> { listener: &'a UnixListener, } +#[stable(feature = "unix_socket_redox", since = "1.29")] impl<'a> Iterator for Incoming<'a> { type Item = io::Result; -- cgit 1.4.1-3-g733a5 From 4f3ab4986ec96d9c93f34dc53d0a4a1279288451 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Mon, 23 Jul 2018 22:00:51 -0700 Subject: libstd: Prefer `Option::map`/etc over `match` where applicable --- src/libstd/net/parser.rs | 5 +---- src/libstd/path.rs | 5 +---- src/libstd/sys_common/backtrace.rs | 9 ++++----- 3 files changed, 6 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index ae5037cc44e..008c5da171f 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -53,10 +53,7 @@ impl<'a> Parser<'a> { F: FnOnce(&mut Parser) -> Option, { self.read_atomically(move |p| { - match cb(p) { - Some(x) => if p.is_eof() {Some(x)} else {None}, - None => None, - } + cb(p).filter(|_| p.is_eof()) }) } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0c60129494d..688a7e99f10 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1065,10 +1065,7 @@ impl<'a> Iterator for Ancestors<'a> { fn next(&mut self) -> Option { let next = self.next; - self.next = match next { - Some(path) => path.parent(), - None => None, - }; + self.next = next.and_then(Path::parent); next } } diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 61d7ed463dd..2db47bd5947 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -156,16 +156,15 @@ pub fn log_enabled() -> Option { _ => return Some(PrintFormat::Full), } - let val = match env::var_os("RUST_BACKTRACE") { - Some(x) => if &x == "0" { + let val = env::var_os("RUST_BACKTRACE").and_then(|x| + if &x == "0" { None } else if &x == "full" { Some(PrintFormat::Full) } else { Some(PrintFormat::Short) - }, - None => None, - }; + } + ); ENABLED.store(match val { Some(v) => v as isize, None => 1, -- cgit 1.4.1-3-g733a5 From 66c4dc9769b7ae456fe2960dc5a1e037b2432184 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Fri, 13 Jul 2018 14:25:22 +0900 Subject: Add missing dyn --- src/liballoc/tests/arc.rs | 6 +++--- src/liballoc/tests/btree/set.rs | 2 +- src/liballoc/tests/lib.rs | 2 +- src/liballoc/tests/rc.rs | 6 +++--- src/libcore/tests/any.rs | 16 +++++++++------ src/libcore/tests/hash/mod.rs | 2 +- src/libcore/tests/intrinsics.rs | 2 +- src/libcore/tests/mem.rs | 4 ++-- src/libcore/tests/option.rs | 2 +- src/libcore/tests/ptr.rs | 20 +++++++++--------- src/libcore/tests/result.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/core.rs | 2 +- src/librustdoc/html/highlight.rs | 4 ++-- src/librustdoc/html/layout.rs | 4 ++-- src/librustdoc/html/render.rs | 2 +- src/librustdoc/test.rs | 2 +- src/libstd/sys/redox/process.rs | 4 ++-- src/tools/compiletest/src/header.rs | 2 +- src/tools/compiletest/src/read2.rs | 6 +++--- src/tools/error_index_generator/main.rs | 36 ++++++++++++++++----------------- src/tools/tidy/src/features.rs | 2 +- src/tools/tidy/src/lib.rs | 4 ++-- 23 files changed, 69 insertions(+), 65 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/tests/arc.rs b/src/liballoc/tests/arc.rs index 753873dd294..d90c22a3b18 100644 --- a/src/liballoc/tests/arc.rs +++ b/src/liballoc/tests/arc.rs @@ -18,7 +18,7 @@ fn uninhabited() { a = a.clone(); assert!(a.upgrade().is_none()); - let mut a: Weak = a; // Unsizing + let mut a: Weak = a; // Unsizing a = a.clone(); assert!(a.upgrade().is_none()); } @@ -39,7 +39,7 @@ fn slice() { #[test] fn trait_object() { let a: Arc = Arc::new(4); - let a: Arc = a; // Unsizing + let a: Arc = a; // Unsizing // Exercise is_dangling() with a DST let mut a = Arc::downgrade(&a); @@ -49,7 +49,7 @@ fn trait_object() { let mut b = Weak::::new(); b = b.clone(); assert!(b.upgrade().is_none()); - let mut b: Weak = b; // Unsizing + let mut b: Weak = b; // Unsizing b = b.clone(); assert!(b.upgrade().is_none()); } diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 6171b8ba624..0330bda5e32 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -40,7 +40,7 @@ fn test_hash() { } fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) - where F: FnOnce(&BTreeSet, &BTreeSet, &mut FnMut(&i32) -> bool) -> bool + where F: FnOnce(&BTreeSet, &BTreeSet, &mut dyn FnMut(&i32) -> bool) -> bool { let mut set_a = BTreeSet::new(); let mut set_b = BTreeSet::new(); diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 2c361598e89..91bc778ad4c 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -63,7 +63,7 @@ fn test_boxed_hasher() { 5u32.hash(&mut hasher_1); assert_eq!(ordinary_hash, hasher_1.finish()); - let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; + let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; 5u32.hash(&mut hasher_2); assert_eq!(ordinary_hash, hasher_2.finish()); } diff --git a/src/liballoc/tests/rc.rs b/src/liballoc/tests/rc.rs index baa0406acfc..9ec7c831444 100644 --- a/src/liballoc/tests/rc.rs +++ b/src/liballoc/tests/rc.rs @@ -18,7 +18,7 @@ fn uninhabited() { a = a.clone(); assert!(a.upgrade().is_none()); - let mut a: Weak = a; // Unsizing + let mut a: Weak = a; // Unsizing a = a.clone(); assert!(a.upgrade().is_none()); } @@ -39,7 +39,7 @@ fn slice() { #[test] fn trait_object() { let a: Rc = Rc::new(4); - let a: Rc = a; // Unsizing + let a: Rc = a; // Unsizing // Exercise is_dangling() with a DST let mut a = Rc::downgrade(&a); @@ -49,7 +49,7 @@ fn trait_object() { let mut b = Weak::::new(); b = b.clone(); assert!(b.upgrade().is_none()); - let mut b: Weak = b; // Unsizing + let mut b: Weak = b; // Unsizing b = b.clone(); assert!(b.upgrade().is_none()); } diff --git a/src/libcore/tests/any.rs b/src/libcore/tests/any.rs index 2d3e81aa131..a80bf939530 100644 --- a/src/libcore/tests/any.rs +++ b/src/libcore/tests/any.rs @@ -17,7 +17,7 @@ static TEST: &'static str = "Test"; #[test] fn any_referenced() { - let (a, b, c) = (&5 as &Any, &TEST as &Any, &Test as &Any); + let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any); assert!(a.is::()); assert!(!b.is::()); @@ -34,7 +34,11 @@ fn any_referenced() { #[test] fn any_owning() { - let (a, b, c) = (box 5_usize as Box, box TEST as Box, box Test as Box); + let (a, b, c) = ( + box 5_usize as Box, + box TEST as Box, + box Test as Box, + ); assert!(a.is::()); assert!(!b.is::()); @@ -51,7 +55,7 @@ fn any_owning() { #[test] fn any_downcast_ref() { - let a = &5_usize as &Any; + let a = &5_usize as &dyn Any; match a.downcast_ref::() { Some(&5) => {} @@ -69,9 +73,9 @@ fn any_downcast_mut() { let mut a = 5_usize; let mut b: Box<_> = box 7_usize; - let a_r = &mut a as &mut Any; + let a_r = &mut a as &mut dyn Any; let tmp: &mut usize = &mut *b; - let b_r = tmp as &mut Any; + let b_r = tmp as &mut dyn Any; match a_r.downcast_mut::() { Some(x) => { @@ -113,7 +117,7 @@ fn any_downcast_mut() { #[test] fn any_fixed_vec() { let test = [0_usize; 8]; - let test = &test as &Any; + let test = &test as &dyn Any; assert!(test.is::<[usize; 8]>()); assert!(!test.is::<[usize; 10]>()); } diff --git a/src/libcore/tests/hash/mod.rs b/src/libcore/tests/hash/mod.rs index 8716421b424..85c9d41b65b 100644 --- a/src/libcore/tests/hash/mod.rs +++ b/src/libcore/tests/hash/mod.rs @@ -128,7 +128,7 @@ fn test_custom_state() { fn test_indirect_hasher() { let mut hasher = MyHasher { hash: 0 }; { - let mut indirect_hasher: &mut Hasher = &mut hasher; + let mut indirect_hasher: &mut dyn Hasher = &mut hasher; 5u32.hash(&mut indirect_hasher); } assert_eq!(hasher.hash, 5); diff --git a/src/libcore/tests/intrinsics.rs b/src/libcore/tests/intrinsics.rs index 2b380abf63c..9f3cba26a62 100644 --- a/src/libcore/tests/intrinsics.rs +++ b/src/libcore/tests/intrinsics.rs @@ -22,7 +22,7 @@ fn test_typeid_sized_types() { #[test] fn test_typeid_unsized_types() { trait Z {} - struct X(str); struct Y(Z + 'static); + struct X(str); struct Y(dyn Z + 'static); assert_eq!(TypeId::of::(), TypeId::of::()); assert_eq!(TypeId::of::(), TypeId::of::()); diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs index f55a1c81463..714f2babbdf 100644 --- a/src/libcore/tests/mem.rs +++ b/src/libcore/tests/mem.rs @@ -109,11 +109,11 @@ fn test_transmute() { trait Foo { fn dummy(&self) { } } impl Foo for isize {} - let a = box 100isize as Box; + let a = box 100isize as Box; unsafe { let x: ::core::raw::TraitObject = transmute(a); assert!(*(x.data as *const isize) == 100); - let _x: Box = transmute(x); + let _x: Box = transmute(x); } unsafe { diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index bc3e61a4f54..324ebf43565 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -240,7 +240,7 @@ fn test_collect() { assert!(v == None); // test that it does not take more elements than it needs - let mut functions: [Box Option<()>>; 3] = + let mut functions: [Box Option<()>>; 3] = [box || Some(()), box || None, box || panic!()]; let v: Option> = functions.iter_mut().map(|f| (*f)()).collect(); diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index 31bc1d67768..92160910d8f 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -84,16 +84,16 @@ fn test_is_null() { assert!(nms.is_null()); // Pointers to unsized types -- trait objects - let ci: *const ToString = &3; + let ci: *const dyn ToString = &3; assert!(!ci.is_null()); - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(!mi.is_null()); - let nci: *const ToString = null::(); + let nci: *const dyn ToString = null::(); assert!(nci.is_null()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.is_null()); } @@ -140,16 +140,16 @@ fn test_as_ref() { assert_eq!(nms.as_ref(), None); // Pointers to unsized types -- trait objects - let ci: *const ToString = &3; + let ci: *const dyn ToString = &3; assert!(ci.as_ref().is_some()); - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(mi.as_ref().is_some()); - let nci: *const ToString = null::(); + let nci: *const dyn ToString = null::(); assert!(nci.as_ref().is_none()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.as_ref().is_none()); } } @@ -182,10 +182,10 @@ fn test_as_mut() { assert_eq!(nms.as_mut(), None); // Pointers to unsized types -- trait objects - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(mi.as_mut().is_some()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.as_mut().is_none()); } } diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index d9927ce4487..0616252c82c 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -81,7 +81,7 @@ fn test_collect() { assert!(v == Err(2)); // test that it does not take more elements than it needs - let mut functions: [Box Result<(), isize>>; 3] = + let mut functions: [Box Result<(), isize>>; 3] = [box || Ok(()), box || Err(1), box || panic!()]; let v: Result, isize> = functions.iter_mut().map(|f| (*f)()).collect(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 98684b27973..c601f138d0a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -375,7 +375,7 @@ impl fmt::Debug for Item { let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate) .map(|id| self.def_id >= *id).unwrap_or(false)); - let def_id: &fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; + let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; fmt.debug_struct("Item") .field("source", &self.source) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6e1b4589547..4b8dbaf4211 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -55,7 +55,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { /// The stack of module NodeIds up till this point pub mod_ids: RefCell>, pub crate_name: Option, - pub cstore: Rc, + pub cstore: Rc, pub populated_all_crate_impls: Cell, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 5939d5341e3..6cf9b143373 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -395,7 +395,7 @@ impl Class { fn write_header(class: Option<&str>, id: Option<&str>, - out: &mut Write) + out: &mut dyn Write) -> io::Result<()> { write!(out, "
    ,
         write!(out, "class=\"rust {}\">\n", class.unwrap_or(""))
     }
     
    -fn write_footer(out: &mut Write) -> io::Result<()> {
    +fn write_footer(out: &mut dyn Write) -> io::Result<()> {
         write!(out, "
    \n") } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 5e93b20ea17..af7c0a04215 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -32,7 +32,7 @@ pub struct Page<'a> { } pub fn render( - dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T, + dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T, css_file_extension: bool, themes: &[PathBuf]) -> io::Result<()> { @@ -194,7 +194,7 @@ pub fn render( ) } -pub fn redirect(dst: &mut io::Write, url: &str) -> io::Result<()> { +pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> { //
  • for PathBuf { fn from_iter>(iter: I) -> PathBuf { -- cgit 1.4.1-3-g733a5 From 88f32d15afac7bc5cff5daca7a0ac80fdedb6dce Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 5 Mar 2018 18:37:05 +0100 Subject: Remove a couple of `isize` references from hashmap docs Also fix a spelling mistake. --- src/libstd/collections/hash/map.rs | 54 +++++++++++++++++++------------------- src/libstd/collections/hash/set.rs | 4 +-- 2 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4dfdc23ebee..b023fec810e 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -620,7 +620,7 @@ impl HashMap { /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// let mut map: HashMap<&str, i32> = HashMap::new(); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -637,7 +637,7 @@ impl HashMap { /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::with_capacity(10); + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -724,7 +724,7 @@ impl HashMap /// use std::collections::hash_map::RandomState; /// /// let hasher = RandomState::new(); - /// let map: HashMap = HashMap::with_hasher(hasher); + /// let map: HashMap = HashMap::with_hasher(hasher); /// let hasher: &RandomState = map.hasher(); /// ``` #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] @@ -741,7 +741,7 @@ impl HashMap /// /// ``` /// use std::collections::HashMap; - /// let map: HashMap = HashMap::with_capacity(100); + /// let map: HashMap = HashMap::with_capacity(100); /// assert!(map.capacity() >= 100); /// ``` #[inline] @@ -770,7 +770,7 @@ impl HashMap /// /// ``` /// use std::collections::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// let mut map: HashMap<&str, i32> = HashMap::new(); /// map.reserve(10); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -849,7 +849,7 @@ impl HashMap /// ``` /// use std::collections::HashMap; /// - /// let mut map: HashMap = HashMap::with_capacity(100); + /// let mut map: HashMap = HashMap::with_capacity(100); /// map.insert(1, 2); /// map.insert(3, 4); /// assert!(map.capacity() >= 100); @@ -1306,7 +1306,7 @@ impl HashMap /// ``` /// use std::collections::HashMap; /// - /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); /// map.retain(|&k, _| k % 2 == 0); /// assert_eq!(map.len(), 4); /// ``` @@ -1722,7 +1722,7 @@ impl IntoIterator for HashMap /// map.insert("c", 3); /// /// // Not possible with .iter() - /// let vec: Vec<(&str, isize)> = map.into_iter().collect(); + /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); /// ``` fn into_iter(self) -> IntoIter { IntoIter { inner: self.table.into_iter() } @@ -2786,24 +2786,24 @@ mod test_map { assert_eq!(m2.len(), 2); } - thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } + thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } #[derive(Hash, PartialEq, Eq)] - struct Dropable { + struct Droppable { k: usize, } - impl Dropable { - fn new(k: usize) -> Dropable { + impl Droppable { + fn new(k: usize) -> Droppable { DROP_VECTOR.with(|slot| { slot.borrow_mut()[k] += 1; }); - Dropable { k: k } + Droppable { k: k } } } - impl Drop for Dropable { + impl Drop for Droppable { fn drop(&mut self) { DROP_VECTOR.with(|slot| { slot.borrow_mut()[self.k] -= 1; @@ -2811,9 +2811,9 @@ mod test_map { } } - impl Clone for Dropable { - fn clone(&self) -> Dropable { - Dropable::new(self.k) + impl Clone for Droppable { + fn clone(&self) -> Droppable { + Droppable::new(self.k) } } @@ -2833,8 +2833,8 @@ mod test_map { }); for i in 0..100 { - let d1 = Dropable::new(i); - let d2 = Dropable::new(i + 100); + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); m.insert(d1, d2); } @@ -2845,7 +2845,7 @@ mod test_map { }); for i in 0..50 { - let k = Dropable::new(i); + let k = Droppable::new(i); let v = m.remove(&k); assert!(v.is_some()); @@ -2892,8 +2892,8 @@ mod test_map { }); for i in 0..100 { - let d1 = Dropable::new(i); - let d2 = Dropable::new(i + 100); + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); hm.insert(d1, d2); } @@ -2943,13 +2943,13 @@ mod test_map { #[test] fn test_empty_remove() { - let mut m: HashMap = HashMap::new(); + let mut m: HashMap = HashMap::new(); assert_eq!(m.remove(&0), None); } #[test] fn test_empty_entry() { - let mut m: HashMap = HashMap::new(); + let mut m: HashMap = HashMap::new(); match m.entry(0) { Occupied(_) => panic!(), Vacant(_) => {} @@ -2960,7 +2960,7 @@ mod test_map { #[test] fn test_empty_iter() { - let mut m: HashMap = HashMap::new(); + let mut m: HashMap = HashMap::new(); assert_eq!(m.drain().next(), None); assert_eq!(m.keys().next(), None); assert_eq!(m.values().next(), None); @@ -3461,7 +3461,7 @@ mod test_map { fn test_entry_take_doesnt_corrupt() { #![allow(deprecated)] //rand // Test for #19292 - fn check(m: &HashMap) { + fn check(m: &HashMap) { for k in m.keys() { assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); @@ -3570,7 +3570,7 @@ mod test_map { #[test] fn test_retain() { - let mut map: HashMap = (0..100).map(|x|(x, x*10)).collect(); + let mut map: HashMap = (0..100).map(|x|(x, x*10)).collect(); map.retain(|&k, _| k % 2 == 0); assert_eq!(map.len(), 50); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e9427fb40a0..67d413b5a38 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -724,7 +724,7 @@ impl HashSet /// use std::collections::HashSet; /// /// let xs = [1,2,3,4,5,6]; - /// let mut set: HashSet = xs.iter().cloned().collect(); + /// let mut set: HashSet = xs.iter().cloned().collect(); /// set.retain(|&k| k % 2 == 0); /// assert_eq!(set.len(), 3); /// ``` @@ -1745,7 +1745,7 @@ mod test_set { #[test] fn test_retain() { let xs = [1, 2, 3, 4, 5, 6]; - let mut set: HashSet = xs.iter().cloned().collect(); + let mut set: HashSet = xs.iter().cloned().collect(); set.retain(|&k| k % 2 == 0); assert_eq!(set.len(), 3); assert!(set.contains(&2)); -- cgit 1.4.1-3-g733a5 From 2e7e68b76223b9f14b54852584a5334f33a8798d Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 5 Mar 2018 15:58:54 -0300 Subject: while let all the things --- src/librustc/hir/print.rs | 9 ++------- src/librustc/middle/reachable.rs | 6 +----- .../obligation_forest/mod.rs | 8 +------- src/libstd/sys_common/wtf8.rs | 23 +++++++++------------- src/libsyntax_ext/format.rs | 17 ++++++---------- src/libsyntax_pos/lib.rs | 7 +------ 6 files changed, 20 insertions(+), 50 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index ed8cea3eb65..d91aa3a3851 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -2208,13 +2208,8 @@ impl<'a> State<'a> { if self.next_comment().is_none() { self.s.hardbreak()?; } - loop { - match self.next_comment() { - Some(ref cmnt) => { - self.print_comment(cmnt)?; - } - _ => break, - } + while let Some(ref cmnt) = self.next_comment() { + self.print_comment(cmnt)? } Ok(()) } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 749685182a8..5658b5b6832 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -206,11 +206,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Step 2: Mark all symbols that the symbols on the worklist touch. fn propagate(&mut self) { let mut scanned = FxHashSet(); - loop { - let search_item = match self.worklist.pop() { - Some(item) => item, - None => break, - }; + while let Some(search_item) = self.worklist.pop() { if !scanned.insert(search_item) { continue } diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 02cae52166a..42a17d33fa6 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -415,13 +415,7 @@ impl ObligationForest { } } - loop { - // non-standard `while let` to bypass #6393 - let i = match error_stack.pop() { - Some(i) => i, - None => break - }; - + while let Some(i) = error_stack.pop() { let node = &self.nodes[i]; match node.state.get() { diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 46d554d6411..9fff8b91f96 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -428,20 +428,15 @@ impl fmt::Debug for Wtf8 { formatter.write_str("\"")?; let mut pos = 0; - loop { - match self.next_surrogate(pos) { - None => break, - Some((surrogate_pos, surrogate)) => { - write_str_escaped( - formatter, - unsafe { str::from_utf8_unchecked( - &self.bytes[pos .. surrogate_pos] - )}, - )?; - write!(formatter, "\\u{{{:x}}}", surrogate)?; - pos = surrogate_pos + 3; - } - } + while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) { + write_str_escaped( + formatter, + unsafe { str::from_utf8_unchecked( + &self.bytes[pos .. surrogate_pos] + )}, + )?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; + pos = surrogate_pos + 3; } write_str_escaped( formatter, diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index a7822414c69..8fd95aa1ca8 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -732,18 +732,13 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let mut parser = parse::Parser::new(fmt_str); let mut pieces = vec![]; - loop { - match parser.next() { - Some(mut piece) => { - if !parser.errors.is_empty() { - break; - } - cx.verify_piece(&piece); - cx.resolve_name_inplace(&mut piece); - pieces.push(piece); - } - None => break, + while let Some(mut piece) = parser.next() { + if !parser.errors.is_empty() { + break; } + cx.verify_piece(&piece); + cx.resolve_name_inplace(&mut piece); + pieces.push(piece); } let numbered_position_args = pieces.iter().any(|arg: &parse::Piece| { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9f746adbe65..ed9eb5d5c92 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -322,12 +322,7 @@ impl Span { pub fn macro_backtrace(mut self) -> Vec { let mut prev_span = DUMMY_SP; let mut result = vec![]; - loop { - let info = match self.ctxt().outer().expn_info() { - Some(info) => info, - None => break, - }; - + while let Some(info) = self.ctxt().outer().expn_info() { let (pre, post) = match info.callee.format { ExpnFormat::MacroAttribute(..) => ("#[", "]"), ExpnFormat::MacroBang(..) => ("", "!"), -- cgit 1.4.1-3-g733a5 From 1b3d1fc2aad94f73d927057f497cb086f1fb0d83 Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Mon, 5 Mar 2018 16:39:09 -0500 Subject: Move tests, re-export items from core::ascii --- src/libcore/ascii.rs | 356 +-------------------------------- src/libcore/tests/ascii.rs | 349 +++++++++++++++++++++++++++++++++ src/libstd/ascii.rs | 477 +-------------------------------------------- 3 files changed, 353 insertions(+), 829 deletions(-) create mode 100644 src/libcore/tests/ascii.rs (limited to 'src/libstd') diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index d61b9199560..f409536d1b0 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -19,7 +19,7 @@ //! //! [`escape_default`]: fn.escape_default.html -#![stable(feature = "rust1", since = "1.0.0")] +#![stable(feature = "core_ascii", since = "1.26.0")] use fmt; use ops::Range; @@ -145,357 +145,3 @@ impl fmt::Debug for EscapeDefault { f.pad("EscapeDefault { .. }") } } - - -#[cfg(test)] -mod tests { - use char::from_u32; - - #[test] - fn test_is_ascii() { - assert!(b"".is_ascii()); - assert!(b"banana\0\x7F".is_ascii()); - assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); - assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); - assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); - assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); - - assert!("".is_ascii()); - assert!("banana\0\u{7F}".is_ascii()); - assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); - } - - #[test] - fn test_to_ascii_uppercase() { - assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); - assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); - - for i in 0..501 { - let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), - (from_u32(upper).unwrap()).to_string()); - } - } - - #[test] - fn test_to_ascii_lowercase() { - assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); - // Dotted capital I, Kelvin sign, Sharp S. - assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), - (from_u32(lower).unwrap()).to_string()); - } - } - - #[test] - fn test_make_ascii_lower_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_lowercase(); - assert_eq!(x, $to); - } - } - } - test!(b'A', b'a'); - test!(b'a', b'a'); - test!(b'!', b'!'); - test!('A', 'a'); - test!('À', 'À'); - test!('a', 'a'); - test!('!', '!'); - test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); - test!("HİKß".to_string(), "hİKß"); - } - - - #[test] - fn test_make_ascii_upper_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_uppercase(); - assert_eq!(x, $to); - } - } - } - test!(b'a', b'A'); - test!(b'A', b'A'); - test!(b'!', b'!'); - test!('a', 'A'); - test!('à', 'à'); - test!('A', 'A'); - test!('!', '!'); - test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); - test!("hıKß".to_string(), "HıKß"); - - let mut x = "Hello".to_string(); - x[..3].make_ascii_uppercase(); // Test IndexMut on String. - assert_eq!(x, "HELlo") - } - - #[test] - fn test_eq_ignore_ascii_case() { - assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); - assert!(!"Ürl".eq_ignore_ascii_case("ürl")); - // Dotted capital I, Kelvin sign, Sharp S. - assert!("HİKß".eq_ignore_ascii_case("hİKß")); - assert!(!"İ".eq_ignore_ascii_case("i")); - assert!(!"K".eq_ignore_ascii_case("k")); - assert!(!"ß".eq_ignore_ascii_case("s")); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( - &from_u32(lower).unwrap().to_string())); - } - } - - #[test] - fn inference_works() { - let x = "a".to_string(); - x.eq_ignore_ascii_case("A"); - } - - // Shorthands used by the is_ascii_* tests. - macro_rules! assert_all { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if !b.$what() { - panic!("expected {}({}) but it isn't", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if !b.$what() { - panic!("expected {}(0x{:02x})) but it isn't", - stringify!($what), b); - } - } - assert!($str.$what()); - assert!($str.as_bytes().$what()); - )+ - }}; - ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) - } - macro_rules! assert_none { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if b.$what() { - panic!("expected not-{}({}) but it is", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if b.$what() { - panic!("expected not-{}(0x{:02x})) but it is", - stringify!($what), b); - } - } - )* - }}; - ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) - } - - #[test] - fn test_is_ascii_alphabetic() { - assert_all!(is_ascii_alphabetic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_alphabetic, - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_uppercase() { - assert_all!(is_ascii_uppercase, - "", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_uppercase, - "abcdefghijklmnopqrstuvwxyz", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_lowercase() { - assert_all!(is_ascii_lowercase, - "abcdefghijklmnopqrstuvwxyz", - ); - assert_none!(is_ascii_lowercase, - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_alphanumeric() { - assert_all!(is_ascii_alphanumeric, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - ); - assert_none!(is_ascii_alphanumeric, - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_digit() { - assert_all!(is_ascii_digit, - "", - "0123456789", - ); - assert_none!(is_ascii_digit, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_hexdigit() { - assert_all!(is_ascii_hexdigit, - "", - "0123456789", - "abcdefABCDEF", - ); - assert_none!(is_ascii_hexdigit, - "ghijklmnopqrstuvwxyz", - "GHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_punctuation() { - assert_all!(is_ascii_punctuation, - "", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_punctuation, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_graphic() { - assert_all!(is_ascii_graphic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_graphic, - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_whitespace() { - assert_all!(is_ascii_whitespace, - "", - " \t\n\x0c\r", - ); - assert_none!(is_ascii_whitespace, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x0b\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_control() { - assert_all!(is_ascii_control, - "", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - assert_none!(is_ascii_control, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " ", - ); - } -} diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs new file mode 100644 index 00000000000..9cc3cd18be5 --- /dev/null +++ b/src/libcore/tests/ascii.rs @@ -0,0 +1,349 @@ +use char::from_u32; + +#[test] +fn test_is_ascii() { + assert!(b"".is_ascii()); + assert!(b"banana\0\x7F".is_ascii()); + assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); + assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); + assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); + assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); + + assert!("".is_ascii()); + assert!("banana\0\u{7F}".is_ascii()); + assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); +} + +#[test] +fn test_to_ascii_uppercase() { + assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); + assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); + + for i in 0..501 { + let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } + else { i }; + assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), + (from_u32(upper).unwrap()).to_string()); + } +} + +#[test] +fn test_to_ascii_lowercase() { + assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); + // Dotted capital I, Kelvin sign, Sharp S. + assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); + + for i in 0..501 { + let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } + else { i }; + assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), + (from_u32(lower).unwrap()).to_string()); + } +} + +#[test] +fn test_make_ascii_lower_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_lowercase(); + assert_eq!(x, $to); + } + } + } + test!(b'A', b'a'); + test!(b'a', b'a'); + test!(b'!', b'!'); + test!('A', 'a'); + test!('À', 'À'); + test!('a', 'a'); + test!('!', '!'); + test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); + test!("HİKß".to_string(), "hİKß"); +} + + +#[test] +fn test_make_ascii_upper_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_uppercase(); + assert_eq!(x, $to); + } + } + } + test!(b'a', b'A'); + test!(b'A', b'A'); + test!(b'!', b'!'); + test!('a', 'A'); + test!('à', 'à'); + test!('A', 'A'); + test!('!', '!'); + test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); + test!("hıKß".to_string(), "HıKß"); + + let mut x = "Hello".to_string(); + x[..3].make_ascii_uppercase(); // Test IndexMut on String. + assert_eq!(x, "HELlo") +} + +#[test] +fn test_eq_ignore_ascii_case() { + assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); + assert!(!"Ürl".eq_ignore_ascii_case("ürl")); + // Dotted capital I, Kelvin sign, Sharp S. + assert!("HİKß".eq_ignore_ascii_case("hİKß")); + assert!(!"İ".eq_ignore_ascii_case("i")); + assert!(!"K".eq_ignore_ascii_case("k")); + assert!(!"ß".eq_ignore_ascii_case("s")); + + for i in 0..501 { + let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } + else { i }; + assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( + &from_u32(lower).unwrap().to_string())); + } +} + +#[test] +fn inference_works() { + let x = "a".to_string(); + x.eq_ignore_ascii_case("A"); +} + +// Shorthands used by the is_ascii_* tests. +macro_rules! assert_all { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if !b.$what() { + panic!("expected {}({}) but it isn't", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if !b.$what() { + panic!("expected {}(0x{:02x})) but it isn't", + stringify!($what), b); + } + } + assert!($str.$what()); + assert!($str.as_bytes().$what()); + )+ + }}; + ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) +} +macro_rules! assert_none { + ($what:ident, $($str:tt),+) => {{ + $( + for b in $str.chars() { + if b.$what() { + panic!("expected not-{}({}) but it is", + stringify!($what), b); + } + } + for b in $str.as_bytes().iter() { + if b.$what() { + panic!("expected not-{}(0x{:02x})) but it is", + stringify!($what), b); + } + } + )* + }}; + ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) +} + +#[test] +fn test_is_ascii_alphabetic() { + assert_all!(is_ascii_alphabetic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + ); + assert_none!(is_ascii_alphabetic, + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_uppercase() { + assert_all!(is_ascii_uppercase, + "", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + ); + assert_none!(is_ascii_uppercase, + "abcdefghijklmnopqrstuvwxyz", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_lowercase() { + assert_all!(is_ascii_lowercase, + "abcdefghijklmnopqrstuvwxyz", + ); + assert_none!(is_ascii_lowercase, + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_alphanumeric() { + assert_all!(is_ascii_alphanumeric, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + ); + assert_none!(is_ascii_alphanumeric, + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_digit() { + assert_all!(is_ascii_digit, + "", + "0123456789", + ); + assert_none!(is_ascii_digit, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_hexdigit() { + assert_all!(is_ascii_hexdigit, + "", + "0123456789", + "abcdefABCDEF", + ); + assert_none!(is_ascii_hexdigit, + "ghijklmnopqrstuvwxyz", + "GHIJKLMNOQPRSTUVWXYZ", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_punctuation() { + assert_all!(is_ascii_punctuation, + "", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ); + assert_none!(is_ascii_punctuation, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_graphic() { + assert_all!(is_ascii_graphic, + "", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + ); + assert_none!(is_ascii_graphic, + " \t\n\x0c\r", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_whitespace() { + assert_all!(is_ascii_whitespace, + "", + " \t\n\x0c\r", + ); + assert_none!(is_ascii_whitespace, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x0b\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); +} + +#[test] +fn test_is_ascii_control() { + assert_all!(is_ascii_control, + "", + "\x00\x01\x02\x03\x04\x05\x06\x07", + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + "\x10\x11\x12\x13\x14\x15\x16\x17", + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + "\x7f", + ); + assert_none!(is_ascii_control, + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOQPRSTUVWXYZ", + "0123456789", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + " ", + ); +} diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 430c9df396a..70fef9ef5d4 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -30,6 +30,9 @@ use fmt; use ops::Range; use iter::FusedIterator; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::ascii::{EscapeDefault, escape_default}; + /// Extension methods for ASCII-subset only operations. /// /// Be aware that operations on seemingly non-ASCII characters can sometimes @@ -483,477 +486,3 @@ impl AsciiExt for str { self.bytes().all(|b| b.is_ascii_control()) } } - -/// An iterator over the escaped version of a byte. -/// -/// This `struct` is created by the [`escape_default`] function. See its -/// documentation for more. -/// -/// [`escape_default`]: fn.escape_default.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct EscapeDefault { - range: Range, - data: [u8; 4], -} - -/// Returns an iterator that produces an escaped version of a `u8`. -/// -/// The default is chosen with a bias toward producing literals that are -/// legal in a variety of languages, including C++11 and similar C-family -/// languages. The exact rules are: -/// -/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. -/// - Single-quote, double-quote and backslash chars are backslash-escaped. -/// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex escapes of the form '\xNN'. -/// - Unicode escapes are never generated by this function. -/// -/// # Examples -/// -/// ``` -/// use std::ascii; -/// -/// let escaped = ascii::escape_default(b'0').next().unwrap(); -/// assert_eq!(b'0', escaped); -/// -/// let mut escaped = ascii::escape_default(b'\t'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b't', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\r'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'r', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\n'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'n', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\''); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'\'', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'"'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'"', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\\'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// -/// let mut escaped = ascii::escape_default(b'\x9d'); -/// -/// assert_eq!(b'\\', escaped.next().unwrap()); -/// assert_eq!(b'x', escaped.next().unwrap()); -/// assert_eq!(b'9', escaped.next().unwrap()); -/// assert_eq!(b'd', escaped.next().unwrap()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn escape_default(c: u8) -> EscapeDefault { - let (data, len) = match c { - b'\t' => ([b'\\', b't', 0, 0], 2), - b'\r' => ([b'\\', b'r', 0, 0], 2), - b'\n' => ([b'\\', b'n', 0, 0], 2), - b'\\' => ([b'\\', b'\\', 0, 0], 2), - b'\'' => ([b'\\', b'\'', 0, 0], 2), - b'"' => ([b'\\', b'"', 0, 0], 2), - b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), - _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), - }; - - return EscapeDefault { range: (0.. len), data: data }; - - fn hexify(b: u8) -> u8 { - match b { - 0 ... 9 => b'0' + b, - _ => b'a' + b - 10, - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EscapeDefault { - type Item = u8; - fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i]) } - fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for EscapeDefault { - fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| self.data[i]) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for EscapeDefault {} -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for EscapeDefault {} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for EscapeDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("EscapeDefault { .. }") - } -} - - -#[cfg(test)] -mod tests { - //! Note that most of these tests are not testing `AsciiExt` methods, but - //! test inherent ascii methods of char, u8, str and [u8]. `AsciiExt` is - //! just using those methods, though. - use super::AsciiExt; - use char::from_u32; - - #[test] - fn test_is_ascii() { - assert!(b"".is_ascii()); - assert!(b"banana\0\x7F".is_ascii()); - assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); - assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); - assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); - assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); - - assert!("".is_ascii()); - assert!("banana\0\u{7F}".is_ascii()); - assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); - } - - #[test] - fn test_to_ascii_uppercase() { - assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL"); - assert_eq!("hıKß".to_ascii_uppercase(), "HıKß"); - - for i in 0..501 { - let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(), - (from_u32(upper).unwrap()).to_string()); - } - } - - #[test] - fn test_to_ascii_lowercase() { - assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl"); - // Dotted capital I, Kelvin sign, Sharp S. - assert_eq!("HİKß".to_ascii_lowercase(), "hİKß"); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(), - (from_u32(lower).unwrap()).to_string()); - } - } - - #[test] - fn test_make_ascii_lower_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_lowercase(); - assert_eq!(x, $to); - } - } - } - test!(b'A', b'a'); - test!(b'a', b'a'); - test!(b'!', b'!'); - test!('A', 'a'); - test!('À', 'À'); - test!('a', 'a'); - test!('!', '!'); - test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); - test!("HİKß".to_string(), "hİKß"); - } - - - #[test] - fn test_make_ascii_upper_case() { - macro_rules! test { - ($from: expr, $to: expr) => { - { - let mut x = $from; - x.make_ascii_uppercase(); - assert_eq!(x, $to); - } - } - } - test!(b'a', b'A'); - test!(b'A', b'A'); - test!(b'!', b'!'); - test!('a', 'A'); - test!('à', 'à'); - test!('A', 'A'); - test!('!', '!'); - test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); - test!("hıKß".to_string(), "HıKß"); - - let mut x = "Hello".to_string(); - x[..3].make_ascii_uppercase(); // Test IndexMut on String. - assert_eq!(x, "HELlo") - } - - #[test] - fn test_eq_ignore_ascii_case() { - assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); - assert!(!"Ürl".eq_ignore_ascii_case("ürl")); - // Dotted capital I, Kelvin sign, Sharp S. - assert!("HİKß".eq_ignore_ascii_case("hİKß")); - assert!(!"İ".eq_ignore_ascii_case("i")); - assert!(!"K".eq_ignore_ascii_case("k")); - assert!(!"ß".eq_ignore_ascii_case("s")); - - for i in 0..501 { - let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } - else { i }; - assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case( - &from_u32(lower).unwrap().to_string())); - } - } - - #[test] - fn inference_works() { - let x = "a".to_string(); - x.eq_ignore_ascii_case("A"); - } - - // Shorthands used by the is_ascii_* tests. - macro_rules! assert_all { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if !b.$what() { - panic!("expected {}({}) but it isn't", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if !b.$what() { - panic!("expected {}(0x{:02x})) but it isn't", - stringify!($what), b); - } - } - assert!($str.$what()); - assert!($str.as_bytes().$what()); - )+ - }}; - ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) - } - macro_rules! assert_none { - ($what:ident, $($str:tt),+) => {{ - $( - for b in $str.chars() { - if b.$what() { - panic!("expected not-{}({}) but it is", - stringify!($what), b); - } - } - for b in $str.as_bytes().iter() { - if b.$what() { - panic!("expected not-{}(0x{:02x})) but it is", - stringify!($what), b); - } - } - )* - }}; - ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) - } - - #[test] - fn test_is_ascii_alphabetic() { - assert_all!(is_ascii_alphabetic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_alphabetic, - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_uppercase() { - assert_all!(is_ascii_uppercase, - "", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - ); - assert_none!(is_ascii_uppercase, - "abcdefghijklmnopqrstuvwxyz", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_lowercase() { - assert_all!(is_ascii_lowercase, - "abcdefghijklmnopqrstuvwxyz", - ); - assert_none!(is_ascii_lowercase, - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_alphanumeric() { - assert_all!(is_ascii_alphanumeric, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - ); - assert_none!(is_ascii_alphanumeric, - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_digit() { - assert_all!(is_ascii_digit, - "", - "0123456789", - ); - assert_none!(is_ascii_digit, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_hexdigit() { - assert_all!(is_ascii_hexdigit, - "", - "0123456789", - "abcdefABCDEF", - ); - assert_none!(is_ascii_hexdigit, - "ghijklmnopqrstuvwxyz", - "GHIJKLMNOQPRSTUVWXYZ", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_punctuation() { - assert_all!(is_ascii_punctuation, - "", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_punctuation, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_graphic() { - assert_all!(is_ascii_graphic, - "", - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - ); - assert_none!(is_ascii_graphic, - " \t\n\x0c\r", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_whitespace() { - assert_all!(is_ascii_whitespace, - "", - " \t\n\x0c\r", - ); - assert_none!(is_ascii_whitespace, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x0b\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - } - - #[test] - fn test_is_ascii_control() { - assert_all!(is_ascii_control, - "", - "\x00\x01\x02\x03\x04\x05\x06\x07", - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - "\x10\x11\x12\x13\x14\x15\x16\x17", - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - "\x7f", - ); - assert_none!(is_ascii_control, - "abcdefghijklmnopqrstuvwxyz", - "ABCDEFGHIJKLMNOQPRSTUVWXYZ", - "0123456789", - "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", - " ", - ); - } -} -- cgit 1.4.1-3-g733a5 From aa1ded9286d7ff5bdc0c9b389fc10d564c23c4db Mon Sep 17 00:00:00 2001 From: 1011X <1011XXXXX@gmail.com> Date: Mon, 5 Mar 2018 18:13:56 -0500 Subject: Remove unnecessary imports --- src/libstd/ascii.rs | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 70fef9ef5d4..0837ff91c14 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -26,10 +26,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; -use ops::Range; -use iter::FusedIterator; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::ascii::{EscapeDefault, escape_default}; -- cgit 1.4.1-3-g733a5 From 517083fbad1cab6652efe66f36ed7f085eb67b61 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Wed, 7 Mar 2018 16:13:15 +0900 Subject: Make `assert` macro a built-in procedural macro --- src/libcore/macros.rs | 15 +++++++++++ src/libstd/lib.rs | 3 ++- src/libstd/macros.rs | 54 ++++++++++++++++++++++++++++++++++++++ src/libsyntax_ext/assert.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++ src/libsyntax_ext/lib.rs | 2 ++ 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/libsyntax_ext/assert.rs (limited to 'src/libstd') diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 52eb9f29d57..8a87bea71e2 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -76,6 +76,7 @@ macro_rules! panic { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] macro_rules! assert { ($cond:expr) => ( if !$cond { @@ -784,4 +785,18 @@ mod builtin { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); } + + /// Ensure that a boolean expression is `true` at runtime. + /// + /// For more information, see the documentation for [`std::assert!`]. + /// + /// [`std::assert!`]: ../std/macro.assert.html + #[macro_export] + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(dox)] + macro_rules! assert { + ($cond:expr) => ({ /* compiler built-in */ }); + ($cond:expr,) => ({ /* compiler built-in */ }); + ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a7e1c0ce732..b2e45f0f437 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -355,8 +355,9 @@ use prelude::v1::*; // We want to re-export a few macros from core but libcore has already been // imported by the compiler (via our #[no_std] attribute) In this case we just // add a new crate name so we can attach the re-exports to it. -#[macro_reexport(assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, +#[macro_reexport(assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, unreachable, unimplemented, write, writeln, try)] +#[cfg_attr(stage0, macro_reexport(assert))] extern crate core as __core; #[macro_use] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a18c811d196..da982af498b 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -719,6 +719,60 @@ pub mod builtin { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); } + + /// Ensure that a boolean expression is `true` at runtime. + /// + /// This will invoke the [`panic!`] macro if the provided expression cannot be + /// evaluated to `true` at runtime. + /// + /// # Uses + /// + /// Assertions are always checked in both debug and release builds, and cannot + /// be disabled. See [`debug_assert!`] for assertions that are not enabled in + /// release builds by default. + /// + /// Unsafe code relies on `assert!` to enforce run-time invariants that, if + /// violated could lead to unsafety. + /// + /// Other use-cases of `assert!` include [testing] and enforcing run-time + /// invariants in safe code (whose violation cannot result in unsafety). + /// + /// # Custom Messages + /// + /// This macro has a second form, where a custom panic message can + /// be provided with or without arguments for formatting. See [`std::fmt`] + /// for syntax for this form. + /// + /// [`panic!`]: macro.panic.html + /// [`debug_assert!`]: macro.debug_assert.html + /// [testing]: ../book/second-edition/ch11-01-writing-tests.html#checking-results-with-the-assert-macro + /// [`std::fmt`]: ../std/fmt/index.html + /// + /// # Examples + /// + /// ``` + /// // the panic message for these assertions is the stringified value of the + /// // expression given. + /// assert!(true); + /// + /// fn some_computation() -> bool { true } // a very simple function + /// + /// assert!(some_computation()); + /// + /// // assert with a custom message + /// let x = true; + /// assert!(x, "x wasn't true!"); + /// + /// let a = 3; let b = 27; + /// assert!(a + b == 30, "a = {}, b = {}", a, b); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + macro_rules! assert { + ($cond:expr) => ({ /* compiler built-in */ }); + ($cond:expr,) => ({ /* compiler built-in */ }); + ($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ }); + } } /// A macro for defining #[cfg] if-else statements. diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs new file mode 100644 index 00000000000..7962ec26c37 --- /dev/null +++ b/src/libsyntax_ext/assert.rs @@ -0,0 +1,64 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast::*; +use syntax::codemap::Spanned; +use syntax::ext::base::*; +use syntax::ext::build::AstBuilder; +use syntax::parse::token; +use syntax::print::pprust; +use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax_pos::Span; + +pub fn expand_assert<'cx>( + cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[TokenTree], +) -> Box { + let mut parser = cx.new_parser_from_tts(tts); + let cond_expr = panictry!(parser.parse_expr()); + let custom_msg_args = if parser.eat(&token::Comma) { + let ts = parser.parse_tokens(); + if !ts.is_empty() { + Some(ts) + } else { + None + } + } else { + None + }; + + let sp = sp.with_ctxt(sp.ctxt().apply_mark(cx.current_expansion.mark)); + let panic_call = Mac_ { + path: Path::from_ident(sp, Ident::from_str("panic")), + tts: if let Some(ts) = custom_msg_args { + ts.into() + } else { + let panic_str = format!("assertion failed: {}", pprust::expr_to_string(&cond_expr)); + TokenStream::from(token::Literal( + token::Lit::Str_(Name::intern(&panic_str)), + None, + )).into() + }, + }; + let if_expr = cx.expr_if( + sp, + cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), + cx.expr( + sp, + ExprKind::Mac(Spanned { + span: sp, + node: panic_call, + }), + ), + None, + ); + MacEager::expr(if_expr) +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 772dec72ab9..a01878530b2 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -26,6 +26,7 @@ extern crate proc_macro; extern crate rustc_data_structures; extern crate rustc_errors as errors; +mod assert; mod asm; mod cfg; mod compile_error; @@ -111,6 +112,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, log_syntax: log_syntax::expand_syntax_ext, trace_macros: trace_macros::expand_trace_macros, compile_error: compile_error::expand_compile_error, + assert: assert::expand_assert, } // format_args uses `unstable` things internally. -- cgit 1.4.1-3-g733a5 From 2d7472fadcfd6b214d6fcfb1313104bdf56609fb Mon Sep 17 00:00:00 2001 From: Anthony Defranceschi Date: Fri, 9 Mar 2018 00:36:07 +0100 Subject: Modify part of `line!` documentation. In accordance with #46997, I've replaced: > The returned line is not the invocation of the line! macro itself [...] By > The returned line is *not necessarily* the line of the `line!` invocation itself [...] --- src/libstd/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a18c811d196..5fb3b85b8cd 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -472,7 +472,7 @@ pub mod builtin { /// The expanded expression has type `u32` and is 1-based, so the first line /// in each file evaluates to 1, the second to 2, etc. This is consistent /// with error messages by common compilers or popular editors. - /// The returned line is not the invocation of the `line!` macro itself, + /// The returned line is *not necessarily* the line of the `line!` invocation itself, /// but rather the first macro invocation leading up to the invocation /// of the `line!` macro. /// -- cgit 1.4.1-3-g733a5 From a0758cdcffcd3810c6bc3eef06fa8193c6e10f28 Mon Sep 17 00:00:00 2001 From: Anthony Defranceschi Date: Fri, 9 Mar 2018 00:43:54 +0100 Subject: Modify part of `column!` documentation. Just like `line!` documentation, I've replaced: > The returned column is not the invocation of the `column!` macro itself By > The returned column is *not necessarily* the line of the `column!` invocation itself See #46997. --- src/libstd/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a18c811d196..9543540cb5b 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -497,7 +497,7 @@ pub mod builtin { /// The expanded expression has type `u32` and is 1-based, so the first column /// in each line evaluates to 1, the second to 2, etc. This is consistent /// with error messages by common compilers or popular editors. - /// The returned column is not the invocation of the `column!` macro itself, + /// The returned column is *not necessarily* the line of the `column!` invocation itself, /// but rather the first macro invocation leading up to the invocation /// of the `column!` macro. /// -- cgit 1.4.1-3-g733a5 From 908328fca03c1bf69ce335974f4dcabd8e5d18f4 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sun, 11 Mar 2018 07:41:13 -0400 Subject: Document when types have OS-dependent sizes As per issue #43601, types that can change size depending on the target operating system should say so in their documentation. I used this template when adding doc comments: The size of a(n) struct may vary depending on the target operating system, and may change between Rust releases. For enums, I used "instance" instead of "struct". --- src/libstd/io/stdio.rs | 9 +++++++++ src/libstd/net/addr.rs | 9 +++++++++ src/libstd/net/ip.rs | 9 +++++++++ src/libstd/time.rs | 6 ++++++ 4 files changed, 33 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 1f73054e3be..4565b7fa0d6 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -30,18 +30,27 @@ thread_local! { /// /// This handle is not synchronized or buffered in any fashion. Constructed via /// the `std::io::stdio::stdin_raw` function. +/// +/// The size of a StdinRaw struct may vary depending on the target operating +/// system, and may change between Rust releases. struct StdinRaw(stdio::Stdin); /// A handle to a raw instance of the standard output stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via /// the `std::io::stdio::stdout_raw` function. +/// +/// The size of a StdoutRaw struct may vary depending on the target operating +/// system, and may change between Rust releases. struct StdoutRaw(stdio::Stdout); /// A handle to a raw instance of the standard output stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via /// the `std::io::stdio::stderr_raw` function. +/// +/// The size of a StderrRaw struct may vary depending on the target operating +/// system, and may change between Rust releases. struct StderrRaw(stdio::Stderr); /// Constructs a new raw handle to the standard input of this process. diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index fa430939f05..75b05063839 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -28,6 +28,9 @@ use slice; /// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and /// [`SocketAddrV6`]'s respective documentation for more details. /// +/// The size of a SocketAddr instance may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// [IP address]: ../../std/net/enum.IpAddr.html /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html @@ -61,6 +64,9 @@ pub enum SocketAddr { /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// +/// The size of a SocketAddrV4 struct may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html @@ -88,6 +94,9 @@ pub struct SocketAddrV4 { inner: c::sockaddr_in } /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// +/// The size of a SocketAddrV6 struct may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 0d73a6f4fd7..36a34e147d5 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -26,6 +26,9 @@ use sys_common::{AsInner, FromInner}; /// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their /// respective documentation for more details. /// +/// The size of an IpAddr instance may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html /// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html /// @@ -61,6 +64,9 @@ pub enum IpAddr { /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// +/// The size of an Ipv4Addr struct may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 /// [`IpAddr`]: ../../std/net/enum.IpAddr.html /// @@ -93,6 +99,9 @@ pub struct Ipv4Addr { /// /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// +/// The size of an Ipv6Addr struct may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [`IpAddr`]: ../../std/net/enum.IpAddr.html /// diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 12f2a9bb85f..054450a5186 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -49,6 +49,9 @@ pub use core::time::Duration; /// allows measuring the duration between two instants (or comparing two /// instants). /// +/// The size of an Instant struct may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// Example: /// /// ```no_run @@ -88,6 +91,9 @@ pub struct Instant(time::Instant); /// fixed point in time, a `SystemTime` can be converted to a human-readable time, /// or perhaps some other string representation. /// +/// The size of a SystemTime struct may vary depending on the target operating +/// system, and may change between Rust releases. +/// /// [`Instant`]: ../../std/time/struct.Instant.html /// [`Result`]: ../../std/result/enum.Result.html /// [`Duration`]: ../../std/time/struct.Duration.html -- cgit 1.4.1-3-g733a5 From 994bfd414138e623f315f4273841b9f006ac72ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 26 Feb 2018 09:07:16 -0800 Subject: Update Cargo submodule Required moving all fulldeps tests depending on `rand` to different locations as now there's multiple `rand` crates that can't be implicitly linked against. --- src/Cargo.lock | 702 ++++++++++----------- src/bootstrap/builder.rs | 4 +- src/liballoc/Cargo.toml | 2 +- src/liballoc/tests/binary_heap.rs | 83 ++- src/liballoc/tests/slice.rs | 165 +++++ src/libcore/Cargo.toml | 3 + src/libcore/tests/lib.rs | 1 + src/libcore/tests/num/flt2dec/mod.rs | 1 + src/libcore/tests/num/flt2dec/random.rs | 160 +++++ src/libcore/tests/slice.rs | 71 ++- src/libstd/Cargo.toml | 2 +- src/libstd/tests/env.rs | 95 +++ .../run-pass-fulldeps/binary-heap-panic-safe.rs | 101 --- src/test/run-pass-fulldeps/env.rs | 99 --- src/test/run-pass-fulldeps/flt2dec.rs | 163 ----- src/test/run-pass-fulldeps/sort-unstable.rs | 83 --- .../run-pass-fulldeps/vector-sort-panic-safe.rs | 181 ------ src/tools/cargo | 2 +- src/tools/tidy/src/deps.rs | 2 + 19 files changed, 926 insertions(+), 994 deletions(-) create mode 100644 src/libcore/tests/num/flt2dec/random.rs create mode 100644 src/libstd/tests/env.rs delete mode 100644 src/test/run-pass-fulldeps/binary-heap-panic-safe.rs delete mode 100644 src/test/run-pass-fulldeps/env.rs delete mode 100644 src/test/run-pass-fulldeps/flt2dec.rs delete mode 100644 src/test/run-pass-fulldeps/sort-unstable.rs delete mode 100644 src/test/run-pass-fulldeps/vector-sort-panic-safe.rs (limited to 'src/libstd') diff --git a/src/Cargo.lock b/src/Cargo.lock index 646ddf1a744..3252fda970b 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -28,7 +28,7 @@ name = "alloc" version = "0.0.0" dependencies = [ "core 0.0.0", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "std_unicode 0.0.0", ] @@ -39,7 +39,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.0.0", ] @@ -81,7 +81,7 @@ name = "atty" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -93,8 +93,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -103,8 +103,8 @@ name = "backtrace-sys" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -131,16 +131,16 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -158,8 +158,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "build-manifest" version = "0.1.0" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -177,48 +177,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.26.0" +version = "0.27.0" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cargotest 0.1.0", - "core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.15.0", + "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crates-io 0.16.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "git2-curl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -227,9 +227,9 @@ name = "cargo_metadata" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -239,25 +239,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cargotest" -version = "0.1.0" -dependencies = [ - "cargo 0.26.0", - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -266,7 +250,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -279,7 +263,7 @@ name = "chrono" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -308,9 +292,9 @@ dependencies = [ "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -329,11 +313,11 @@ dependencies = [ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -349,11 +333,11 @@ dependencies = [ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -361,7 +345,7 @@ name = "cmake" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -377,14 +361,14 @@ name = "commoncrypto-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -393,16 +377,16 @@ name = "compiletest" version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -414,11 +398,11 @@ dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -429,41 +413,39 @@ version = "0.1.0" [[package]] name = "core" version = "0.0.0" +dependencies = [ + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "core-foundation" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-foundation-sys" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crates-io" -version = "0.15.0" +version = "0.16.0" dependencies = [ "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "crossbeam" version = "0.3.2" @@ -502,14 +484,13 @@ dependencies = [ [[package]] name = "crypto-hash" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -519,11 +500,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -532,10 +513,10 @@ name = "curl-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -552,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -574,9 +555,9 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -619,7 +600,7 @@ name = "enum_primitive" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -637,19 +618,19 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "env_logger" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -704,7 +685,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -721,7 +702,7 @@ name = "flate2" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -752,7 +733,7 @@ name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -782,26 +763,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "git2" -version = "0.6.11" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "git2-curl" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -811,29 +792,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "graphviz" version = "0.0.0" -[[package]] -name = "hamcrest" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "handlebars" version = "0.29.1" @@ -843,16 +815,11 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "hex" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "hex" version = "0.3.1" @@ -895,18 +862,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ignore" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -931,7 +899,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -967,8 +935,8 @@ name = "jobserver" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -983,9 +951,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1003,10 +971,10 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1025,6 +993,11 @@ name = "lazycell" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazycell" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.0.0" @@ -1034,21 +1007,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.36" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.6.19" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1058,9 +1031,9 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1069,8 +1042,8 @@ name = "libz-sys" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1108,9 +1081,9 @@ name = "lzma-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1126,7 +1099,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1135,12 +1108,12 @@ dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1150,7 +1123,7 @@ name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1158,7 +1131,7 @@ name = "memchr" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1171,8 +1144,8 @@ name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1181,7 +1154,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1191,7 +1164,7 @@ name = "miow" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1203,7 +1176,7 @@ dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1212,14 +1185,12 @@ version = "0.1.0" [[package]] name = "net2" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1234,7 +1205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1245,68 +1216,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "num-rational" -version = "0.1.40" +name = "num-traits" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.41" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1314,7 +1259,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1324,14 +1269,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.9.23" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1341,11 +1286,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.24" +version = "0.9.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1401,8 +1346,8 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1444,7 +1389,7 @@ dependencies = [ name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1514,11 +1459,22 @@ dependencies = [ [[package]] name = "rand" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1537,9 +1493,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1577,12 +1533,12 @@ dependencies = [ [[package]] name = "regex" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1597,6 +1553,14 @@ name = "regex-syntax" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex-syntax" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "remote-test-client" version = "0.1.0" @@ -1605,14 +1569,23 @@ version = "0.1.0" name = "remote-test-server" version = "0.1.0" +[[package]] +name = "remove_dir_all" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rls" version = "0.126.0" dependencies = [ - "cargo 0.26.0", + "cargo 0.27.0", "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1629,10 +1602,10 @@ dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustfmt-nightly 0.3.8", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1660,8 +1633,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1675,8 +1648,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1789,7 +1762,7 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1839,7 +1812,7 @@ name = "rustc_back" version = "0.0.0" dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -1893,7 +1866,7 @@ version = "0.0.0" dependencies = [ "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "arena 0.0.0", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", @@ -1927,7 +1900,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", - "termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1937,7 +1910,7 @@ version = "0.0.0" dependencies = [ "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -1962,8 +1935,8 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -2100,15 +2073,15 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_back 0.0.0", @@ -2123,7 +2096,7 @@ dependencies = [ "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2174,7 +2147,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2199,14 +2172,14 @@ dependencies = [ "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2223,7 +2196,7 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2232,7 +2205,7 @@ dependencies = [ [[package]] name = "scoped-tls" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2259,7 +2232,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2268,7 +2241,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2278,26 +2251,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2305,18 +2279,18 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2329,7 +2303,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2350,11 +2324,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "socket2" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2377,7 +2351,7 @@ dependencies = [ "panic_abort 0.0.0", "panic_unwind 0.0.0", "profiler_builtins 0.0.0", - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", "rustc_msan 0.0.0", @@ -2410,7 +2384,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.12.13" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2474,7 +2448,7 @@ name = "syntex_errors" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2496,7 +2470,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2511,17 +2485,18 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempdir" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2539,10 +2514,10 @@ dependencies = [ [[package]] name = "termcolor" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2550,7 +2525,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2577,7 +2552,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2601,9 +2576,9 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2611,7 +2586,7 @@ name = "time" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2629,7 +2604,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2640,10 +2615,15 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -2707,7 +2687,7 @@ dependencies = [ [[package]] name = "url" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2720,8 +2700,8 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2760,10 +2740,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "walkdir" -version = "2.0.1" +version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2797,11 +2778,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wincolor" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2822,7 +2802,7 @@ name = "xattr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2855,7 +2835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" "checksum cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d6fb2b5574726329c85cdba0df0347fddfec3cf9c8b588f9931708280f5643" -"checksum cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0" +"checksum cc 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fedf677519ac9e865c4ff43ef8f930773b37ed6e6ea61b6b83b400a7b5787f49" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9" "checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f" @@ -2864,14 +2844,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" "checksum compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6c5aafb5d4a77c6b5fa384fe93c7a9a3561bd88c4b8b8e45187cf5e779b1badc" -"checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e" -"checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5" -"checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" +"checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" +"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "59796cc6cbbdc6bb319161349db0c3250ec73ec7fcb763a51065ec4e2e158552" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crypto-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34903878eec1694faf53cae8473a088df333181de421d4d3d48061d6559fe602" +"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" "checksum curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b70fd6394677d3c0e239ff4be6f2b3176e171ffd1c23ffdc541e78dea2b8bb5e" "checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961" "checksum derive-new 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "92f8b8e1d6c8a5f5ea0849a0e4c55941576115c62d3fc425e96918bbbeb3d3c2" @@ -2885,7 +2864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum env_logger 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f3cc21490995c841d68e00276eba02071ebb269ec24011d5728bd00eabd39e31" +"checksum env_logger 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0628f04f7c26ebccf40d7fc2c1cf92236c05ec88cf2132641cc956812312f0f" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" @@ -2900,19 +2879,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "118b49cac82e04121117cbd3121ede3147e885627d82c4546b87c702debb90c1" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" -"checksum git2 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5b4bb7cd2a44e6e5ee3a26ba6a9ca10d4ce2771cdc3839bbc54b47b7d1be84" -"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" +"checksum git2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4813cd7ad02e53275e6e51aaaf21c30f9ef500b579ad7a54a92f6091a7ac296" +"checksum git2-curl 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27245f4c3a65ab19fd1ab5b52659bd60ed0ce8d0d129202c4737044d1d21db29" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "464627f948c3190ae3d04b1bc6d7dca2f785bda0ac01278e6db129ad383dbeb6" -"checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" +"checksum globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96ab92362c06811385ae9a34d2698e8a1160745e0c78fbb434a44c8de3fabc" "checksum handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc" -"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "459d3cf58137bb02ad4adeef5036377ff59f066dbb82517b7192e3a5462a2abc" "checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" -"checksum ignore 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb2f0238094bd1b41800fb6eb9b16fdd5e9832ed6053ed91409f0cd5bf28dcfd" +"checksum ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "245bea0ba52531a3739cb8ba99f8689eda13d7faf8c36b6a73ce4421aab42588" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" "checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21" "checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394" @@ -2925,8 +2902,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" -"checksum libgit2-sys 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6eeae66e7b1c995de45cb4e65c5ab438a96a7b4077e448645d4048dc753ad357" +"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" +"checksum libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1ecbd6428006c321c29b6c8a895f0d90152f1cf4fd8faab69fc436a3d9594f63" "checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75" "checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" @@ -2941,22 +2919,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" -"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" +"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nibble_vec 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "62e678237a4c70c5f2b917cefd7d080dfbf800421f06e8a59d4e28ef5130fd9e" "checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" -"checksum num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "bdc1494b5912f088f260b775799468d9b9209ac60885d8186a547a0476289e23" -"checksum num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "58de7b4bf7cf5dbecb635a5797d489864eadd03b107930cbccf9e0fd7428b47c" -"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" -"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-rational 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "0c7cb72a95250d8a370105c828f388932373e0e94414919891a0f945222310fe" -"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" +"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" +"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3c2bd9b9d21e48e956b763c9f37134dc62d9e95da6edb3f672cacb6caf3cd3" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum openssl 0.9.23 (registry+https://github.com/rust-lang/crates.io-index)" = "169a4b9160baf9b9b1ab975418c673686638995ba921683a7f1e01470dcb8854" +"checksum openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1636c9f1d78af9cbcc50e523bfff4a30274108aad5e86761afd4d31e4e184fa7" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "14ba54ac7d5a4eabd1d5f2c1fdeb7e7c14debfa669d94b983d01b465e767ba9e" +"checksum openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdc5c4a02e69ce65046f1763a0181107038e02176233acb0b3351d7cc588f9" "checksum os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "998bfbb3042e715190fe2a41abfa047d7e8cb81374d2977d7f100eacd8619cb1" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412" @@ -2973,15 +2949,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "034f1c4528581c40a60e96875467c03315868084e08ff4ceb46a00f7be3b16b4" "checksum radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "211c49b6a9995cac0fd1dd9ca60b42cf3a51e151a12eb954b3a9e75513426ee8" -"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1" +"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" +"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "485541959c8ecc49865526fe6c4de9653dd6e60d829d6edf0be228167b60372d" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" -"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" +"checksum regex 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a62bf8bb734ab90b7f234b681b01af396e5d39b028906c210dc04fa1d5e9e5b3" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" +"checksum regex-syntax 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48d7391e7e90e06eaf3aefbe4652464153ecfec64806f3bf77ffc59638a63e77" +"checksum remove_dir_all 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d2f806b0fcdabd98acd380dc8daef485e22bcb7cddc811d1337967f2528cf5" "checksum rls-analysis 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39461c31c9ec26c2f15821d6aaa349216bf71e24e69550d9f8eeded78dc435e1" "checksum rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56fb7b8e4850b988fbcf277fbdb1eff36879070d02fc1ca243b559273866973d" "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" @@ -2994,40 +2973,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b" "checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d" "checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" -"checksum schannel 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "acece75e0f987c48863a6c792ec8b7d6c4177d4a027f8ccc72f849794f437016" -"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" +"checksum schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fbaffce35eb61c5b00846e73128b0cd62717e7c0ec46abbec132370d013975b4" +"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4" "checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526" -"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0" -"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5" +"checksum serde 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "4763b773978e495252615e814d2ad04773b2c1f85421c7913869a537f35cb406" +"checksum serde_derive 1.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8ab31f00ae5574bb643c196d5e302961c122da1c768604c6d16a35c5d551948a" +"checksum serde_derive_internals 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc848d073be32cd982380c06587ea1d433bc1a4c4a111de07ec2286a3ddade8" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" -"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb" +"checksum serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57781ed845b8e742fc2bf306aba8e3b408fe8c366b900e3769fbc39f49eb8b39" "checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc" "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" -"checksum socket2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf5d5aa364bf61a0d744a293da20381617b6445b89eb524800fab857c5aed2d8" +"checksum socket2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78e4c1cde1adbc6bc4c394da2e7727c916b9b7d0b53d6984c890c65c1f4e6437" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)" = "517f6da31bc53bf080b9a77b29fbd0ff8da2f5a2ebd24c73c2238274a94ac7cb" +"checksum syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5bc2d6ff27891209efa5f63e9de78648d7801f085e4653701a692ce938d6fd" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b" "checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac" "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" "checksum tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1605d3388ceb50252952ffebab4b5dc43017ead7e4481b175961c283bb951195" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" +"checksum tempdir 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f73eebdb68c14bcb24aef74ea96079830e7fa7b31a6106e42ea7ee887c1e134e" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" -"checksum termcolor 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9065bced9c3e43453aa3d56f1e98590b8455b341d2fa191a1090c0dd0b242c75" +"checksum termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "56c456352e44f9f91f774ddeeed27c1ec60a2455ed66d692059acfb1d731bda1" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" @@ -3037,6 +3016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" @@ -3045,7 +3025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2" +"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" "checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3" "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" @@ -3053,13 +3033,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b6d201f4f8998a837196b6de9c73e35af14c992cbb92c4ab641d2c2dce52de" +"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a39ee4464208f6430992ff20154216ab2357772ac871d994c51628d60e58b8b0" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" "checksum xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df591c3504d014dd791d998123ed00a476c7e26dc6b2e873cb55c6ac9e59fa" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 22656e5a9da..586216b9a58 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -775,7 +775,9 @@ impl<'a> Builder<'a> { // be resolved because MinGW has the import library. The downside is we // don't get newer functions from Windows, but we don't use any of them // anyway. - cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); + if mode != Mode::Tool { + cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); + } if self.is_very_verbose() { cargo.arg("-v"); diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 0a265ee1376..3bf919b0c00 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -12,7 +12,7 @@ core = { path = "../libcore" } std_unicode = { path = "../libstd_unicode" } [dev-dependencies] -rand = "0.3" +rand = "0.4" [[test]] name = "collectionstests" diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 06d585f8ea8..5c979d82e55 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::panic; +use std::cmp; use std::collections::BinaryHeap; use std::collections::binary_heap::{Drain, PeekMut}; +use std::panic::{self, AssertUnwindSafe}; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +use rand::{thread_rng, Rng}; #[test] fn test_iterator() { @@ -300,3 +304,80 @@ fn assert_covariance() { d } } + +// old binaryheap failed this test +// +// Integrity means that all elements are present after a comparison panics, +// even if the order may not be correct. +// +// Destructors must be called exactly once per element. +#[test] +fn panic_safe() { + static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + + #[derive(Eq, PartialEq, Ord, Clone, Debug)] + struct PanicOrd(T, bool); + + impl Drop for PanicOrd { + fn drop(&mut self) { + // update global drop count + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + impl PartialOrd for PanicOrd { + fn partial_cmp(&self, other: &Self) -> Option { + if self.1 || other.1 { + panic!("Panicking comparison"); + } + self.0.partial_cmp(&other.0) + } + } + let mut rng = thread_rng(); + const DATASZ: usize = 32; + const NTEST: usize = 10; + + // don't use 0 in the data -- we want to catch the zeroed-out case. + let data = (1..DATASZ + 1).collect::>(); + + // since it's a fuzzy test, run several tries. + for _ in 0..NTEST { + for i in 1..DATASZ + 1 { + DROP_COUNTER.store(0, Ordering::SeqCst); + + let mut panic_ords: Vec<_> = data.iter() + .filter(|&&x| x != i) + .map(|&x| PanicOrd(x, false)) + .collect(); + let panic_item = PanicOrd(i, true); + + // heapify the sane items + rng.shuffle(&mut panic_ords); + let mut heap = BinaryHeap::from(panic_ords); + let inner_data; + + { + // push the panicking item to the heap and catch the panic + let thread_result = { + let mut heap_ref = AssertUnwindSafe(&mut heap); + panic::catch_unwind(move || { + heap_ref.push(panic_item); + }) + }; + assert!(thread_result.is_err()); + + // Assert no elements were dropped + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert!(drops == 0, "Must not drop items. drops={}", drops); + inner_data = heap.clone().into_vec(); + drop(heap); + } + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert_eq!(drops, DATASZ); + + let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); + data_sorted.sort(); + assert_eq!(data_sorted, data); + } + } +} diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 1a9d26fd1a2..d9e9d91cea8 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -8,9 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::cell::Cell; use std::cmp::Ordering::{Equal, Greater, Less}; +use std::cmp::Ordering; use std::mem; +use std::panic; use std::rc::Rc; +use std::sync::atomic::Ordering::Relaxed; +use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize}; +use std::thread; use rand::{Rng, thread_rng}; @@ -1341,3 +1347,162 @@ fn test_copy_from_slice_dst_shorter() { let mut dst = [0; 3]; dst.copy_from_slice(&src); } + +const MAX_LEN: usize = 80; + +static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [ + // FIXME #5244: AtomicUsize is not Copy. + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), + AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), +]; + +static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT; + +#[derive(Clone, Eq)] +struct DropCounter { + x: u32, + id: usize, + version: Cell, +} + +impl PartialEq for DropCounter { + fn eq(&self, other: &Self) -> bool { + self.partial_cmp(other) == Some(Ordering::Equal) + } +} + +impl PartialOrd for DropCounter { + fn partial_cmp(&self, other: &Self) -> Option { + self.version.set(self.version.get() + 1); + other.version.set(other.version.get() + 1); + VERSIONS.fetch_add(2, Relaxed); + self.x.partial_cmp(&other.x) + } +} + +impl Ord for DropCounter { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).unwrap() + } +} + +impl Drop for DropCounter { + fn drop(&mut self) { + DROP_COUNTS[self.id].fetch_add(1, Relaxed); + VERSIONS.fetch_sub(self.version.get(), Relaxed); + } +} + +macro_rules! test { + ($input:ident, $func:ident) => { + let len = $input.len(); + + // Work out the total number of comparisons required to sort + // this array... + let mut count = 0usize; + $input.to_owned().$func(|a, b| { count += 1; a.cmp(b) }); + + // ... and then panic on each and every single one. + for panic_countdown in 0..count { + // Refresh the counters. + VERSIONS.store(0, Relaxed); + for i in 0..len { + DROP_COUNTS[i].store(0, Relaxed); + } + + let v = $input.to_owned(); + let _ = thread::spawn(move || { + let mut v = v; + let mut panic_countdown = panic_countdown; + v.$func(|a, b| { + if panic_countdown == 0 { + SILENCE_PANIC.with(|s| s.set(true)); + panic!(); + } + panic_countdown -= 1; + a.cmp(b) + }) + }).join(); + + // Check that the number of things dropped is exactly + // what we expect (i.e. the contents of `v`). + for (i, c) in DROP_COUNTS.iter().enumerate().take(len) { + let count = c.load(Relaxed); + assert!(count == 1, + "found drop count == {} for i == {}, len == {}", + count, i, len); + } + + // Check that the most recent versions of values were dropped. + assert_eq!(VERSIONS.load(Relaxed), 0); + } + } +} + +thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] // no threads +fn panic_safe() { + let prev = panic::take_hook(); + panic::set_hook(Box::new(move |info| { + if !SILENCE_PANIC.with(|s| s.get()) { + prev(info); + } + })); + + let mut rng = thread_rng(); + + for len in (1..20).chain(70..MAX_LEN) { + for &modulus in &[5, 20, 50] { + for &has_runs in &[false, true] { + let mut input = (0..len) + .map(|id| { + DropCounter { + x: rng.next_u32() % modulus, + id: id, + version: Cell::new(0), + } + }) + .collect::>(); + + if has_runs { + for c in &mut input { + c.x = c.id as u32; + } + + for _ in 0..5 { + let a = rng.gen::() % len; + let b = rng.gen::() % len; + if a < b { + input[a..b].reverse(); + } else { + input.swap(a, b); + } + } + } + + test!(input, sort_by); + test!(input, sort_unstable_by); + } + } + } +} diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 5af63aa970f..24529f7a9d8 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -16,3 +16,6 @@ path = "../libcore/tests/lib.rs" [[bench]] name = "corebenches" path = "../libcore/benches/lib.rs" + +[dev-dependencies] +rand = "0.4" diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index a9c5683e0ef..d08d6b3215d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -50,6 +50,7 @@ extern crate core; extern crate test; +extern crate rand; mod any; mod array; diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index ef0178815f9..04567e25e25 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -23,6 +23,7 @@ mod strategy { mod dragon; mod grisu; } +mod random; pub fn decode_finite(v: T) -> Decoded { match decode(v).1 { diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs new file mode 100644 index 00000000000..315ac4d7d99 --- /dev/null +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -0,0 +1,160 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(not(target_arch = "wasm32"))] + +use std::i16; +use std::mem; +use std::str; + +use core::num::flt2dec::MAX_SIG_DIGITS; +use core::num::flt2dec::strategy::grisu::format_exact_opt; +use core::num::flt2dec::strategy::grisu::format_shortest_opt; +use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; + +use rand::{self, Rand, XorShiftRng}; +use rand::distributions::{IndependentSample, Range}; + +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {:?} instead", full_decoded) + } +} + + +fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + V: FnMut(usize) -> Decoded { + assert!(k <= 1024); + + let mut npassed = 0; // f(x) = Some(g(x)) + let mut nignored = 0; // f(x) = None + + for i in 0..n { + if (i & 0xfffff) == 0 { + println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", + i, n, nignored, npassed, i - nignored - npassed); + } + + let decoded = v(i); + let mut buf1 = [0; 1024]; + if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { + let mut buf2 = [0; 1024]; + let (len2, e2) = g(&decoded, &mut buf2[..k]); + if e1 == e2 && &buf1[..len1] == &buf2[..len2] { + npassed += 1; + } else { + println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", + i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, + str::from_utf8(&buf2[..len2]).unwrap(), e2); + } + } else { + nignored += 1; + } + } + println!("{}({}): done, ignored={} passed={} failed={}", + func, k, nignored, npassed, n - nignored - npassed); + assert!(nignored + npassed == n, + "{}({}): {} out of {} values returns an incorrect value!", + func, k, n - nignored - npassed, n); + (npassed, nignored) +} + +pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); + iterate("f32_random_equivalence_test", k, n, f, g, |_| { + let i: u32 = f32_range.ind_sample(&mut rng); + let x: f32 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); + iterate("f64_random_equivalence_test", k, n, f, g, |_| { + let i: u64 = f64_range.ind_sample(&mut rng); + let x: f64 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, + // so why not simply testing all of them? + // + // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), + // but with `-C opt-level=3 -C lto` this only takes about an hour or so. + + // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges + let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", + k, 0x7f7f_ffff, f, g, |i: usize| { + let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; + decode_finite(x) + }); + assert_eq!((npassed, nignored), (2121451881, 17643158)); +} + +#[test] +fn shortest_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f32_exhaustive_equivalence_test() { + // it is hard to directly test the optimality of the output, but we can at least test if + // two different algorithms agree to each other. + // + // this reports the progress and the number of f32 values returned `None`. + // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: + // `done, ignored=17643158 passed=2121451881 failed=0`. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f64_hard_random_equivalence_test() { + // this again probably has to use appropriate rustc flags. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, + MAX_SIG_DIGITS, 100_000_000); +} + +#[test] +fn exact_f32_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} + +#[test] +fn exact_f64_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} + diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 13740b95802..53fdfa06827 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -10,7 +10,6 @@ use core::result::Result::{Ok, Err}; - #[test] fn test_position() { let b = [1, 2, 3, 5, 5]; @@ -481,3 +480,73 @@ fn test_rotate_right() { assert_eq!(a[(i + 42) % N], i); } } + +#[test] +#[cfg(not(target_arch = "wasm32"))] +fn sort_unstable() { + use core::cmp::Ordering::{Equal, Greater, Less}; + use core::slice::heapsort; + use rand::{Rng, XorShiftRng}; + + let mut v = [0; 600]; + let mut tmp = [0; 600]; + let mut rng = XorShiftRng::new_unseeded(); + + for len in (2..25).chain(500..510) { + let v = &mut v[0..len]; + let tmp = &mut tmp[0..len]; + + for &modulus in &[5, 10, 100, 1000] { + for _ in 0..100 { + for i in 0..len { + v[i] = rng.gen::() % modulus; + } + + // Sort in default order. + tmp.copy_from_slice(v); + tmp.sort_unstable(); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in ascending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| a.cmp(b)); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Sort in descending order. + tmp.copy_from_slice(v); + tmp.sort_unstable_by(|a, b| b.cmp(a)); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); + + // Test heapsort using `<` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a < b); + assert!(tmp.windows(2).all(|w| w[0] <= w[1])); + + // Test heapsort using `>` operator. + tmp.copy_from_slice(v); + heapsort(tmp, |a, b| a > b); + assert!(tmp.windows(2).all(|w| w[0] >= w[1])); + } + } + } + + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort_unstable(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + + // Should not panic. + [0i32; 0].sort_unstable(); + [(); 10].sort_unstable(); + [(); 100].sort_unstable(); + + let mut v = [0xDEADBEEFu64]; + v.sort_unstable(); + assert!(v == [0xDEADBEEF]); +} diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index c1fe4a89d6a..12017598853 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -26,7 +26,7 @@ std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } [dev-dependencies] -rand = "0.3" +rand = "0.4" [target.x86_64-apple-darwin.dependencies] rustc_asan = { path = "../librustc_asan" } diff --git a/src/libstd/tests/env.rs b/src/libstd/tests/env.rs new file mode 100644 index 00000000000..d4376523691 --- /dev/null +++ b/src/libstd/tests/env.rs @@ -0,0 +1,95 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate rand; + +use std::env::*; +use std::iter::repeat; +use std::ffi::{OsString, OsStr}; + +use rand::Rng; + +fn make_rand_name() -> OsString { + let mut rng = rand::thread_rng(); + let n = format!("TEST{}", rng.gen_ascii_chars().take(10) + .collect::()); + let n = OsString::from(n); + assert!(var_os(&n).is_none()); + n +} + +fn eq(a: Option, b: Option<&str>) { + assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); +} + +#[test] +fn test_set_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + eq(var_os(&n), Some("VALUE")); +} + +#[test] +fn test_remove_var() { + let n = make_rand_name(); + set_var(&n, "VALUE"); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_set_var_overwrite() { + let n = make_rand_name(); + set_var(&n, "1"); + set_var(&n, "2"); + eq(var_os(&n), Some("2")); + set_var(&n, ""); + eq(var_os(&n), Some("")); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_var_big() { + let mut s = "".to_string(); + let mut i = 0; + while i < 100 { + s.push_str("aaaaaaaaaa"); + i += 1; + } + let n = make_rand_name(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_env_set_get_huge() { + let n = make_rand_name(); + let s = repeat("x").take(10000).collect::(); + set_var(&n, &s); + eq(var_os(&n), Some(&s)); + remove_var(&n); + eq(var_os(&n), None); +} + +#[test] +fn test_env_set_var() { + let n = make_rand_name(); + + let mut e = vars_os(); + set_var(&n, "VALUE"); + assert!(!e.any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); + + assert!(vars_os().any(|(k, v)| { + &*k == &*n && &*v == "VALUE" + })); +} diff --git a/src/test/run-pass-fulldeps/binary-heap-panic-safe.rs b/src/test/run-pass-fulldeps/binary-heap-panic-safe.rs deleted file mode 100644 index 6139a7d3201..00000000000 --- a/src/test/run-pass-fulldeps/binary-heap-panic-safe.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private, std_panic)] - -extern crate rand; - -use rand::{thread_rng, Rng}; -use std::panic::{self, AssertUnwindSafe}; - -use std::collections::BinaryHeap; -use std::cmp; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; - -// old binaryheap failed this test -// -// Integrity means that all elements are present after a comparison panics, -// even if the order may not be correct. -// -// Destructors must be called exactly once per element. -fn test_integrity() { - #[derive(Eq, PartialEq, Ord, Clone, Debug)] - struct PanicOrd(T, bool); - - impl Drop for PanicOrd { - fn drop(&mut self) { - // update global drop count - DROP_COUNTER.fetch_add(1, Ordering::SeqCst); - } - } - - impl PartialOrd for PanicOrd { - fn partial_cmp(&self, other: &Self) -> Option { - if self.1 || other.1 { - panic!("Panicking comparison"); - } - self.0.partial_cmp(&other.0) - } - } - let mut rng = thread_rng(); - const DATASZ: usize = 32; - const NTEST: usize = 10; - - // don't use 0 in the data -- we want to catch the zeroed-out case. - let data = (1..DATASZ + 1).collect::>(); - - // since it's a fuzzy test, run several tries. - for _ in 0..NTEST { - for i in 1..DATASZ + 1 { - DROP_COUNTER.store(0, Ordering::SeqCst); - - let mut panic_ords: Vec<_> = data.iter() - .filter(|&&x| x != i) - .map(|&x| PanicOrd(x, false)) - .collect(); - let panic_item = PanicOrd(i, true); - - // heapify the sane items - rng.shuffle(&mut panic_ords); - let mut heap = BinaryHeap::from(panic_ords); - let inner_data; - - { - // push the panicking item to the heap and catch the panic - let thread_result = { - let mut heap_ref = AssertUnwindSafe(&mut heap); - panic::catch_unwind(move || { - heap_ref.push(panic_item); - }) - }; - assert!(thread_result.is_err()); - - // Assert no elements were dropped - let drops = DROP_COUNTER.load(Ordering::SeqCst); - assert!(drops == 0, "Must not drop items. drops={}", drops); - inner_data = heap.clone().into_vec(); - drop(heap); - } - let drops = DROP_COUNTER.load(Ordering::SeqCst); - assert_eq!(drops, DATASZ); - - let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); - data_sorted.sort(); - assert_eq!(data_sorted, data); - } - } -} - -fn main() { - test_integrity(); -} - diff --git a/src/test/run-pass-fulldeps/env.rs b/src/test/run-pass-fulldeps/env.rs deleted file mode 100644 index cf2ea732ee1..00000000000 --- a/src/test/run-pass-fulldeps/env.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags: --test - -#![feature(rustc_private, std_panic)] - -extern crate rand; - -use std::env::*; -use std::iter::repeat; -use std::ffi::{OsString, OsStr}; - -use rand::Rng; - -fn make_rand_name() -> OsString { - let mut rng = rand::thread_rng(); - let n = format!("TEST{}", rng.gen_ascii_chars().take(10) - .collect::()); - let n = OsString::from(n); - assert!(var_os(&n).is_none()); - n -} - -fn eq(a: Option, b: Option<&str>) { - assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); -} - -#[test] -fn test_set_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - eq(var_os(&n), Some("VALUE")); -} - -#[test] -fn test_remove_var() { - let n = make_rand_name(); - set_var(&n, "VALUE"); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_set_var_overwrite() { - let n = make_rand_name(); - set_var(&n, "1"); - set_var(&n, "2"); - eq(var_os(&n), Some("2")); - set_var(&n, ""); - eq(var_os(&n), Some("")); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_var_big() { - let mut s = "".to_string(); - let mut i = 0; - while i < 100 { - s.push_str("aaaaaaaaaa"); - i += 1; - } - let n = make_rand_name(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); -} - -#[test] -#[cfg_attr(target_os = "emscripten", ignore)] -fn test_env_set_get_huge() { - let n = make_rand_name(); - let s = repeat("x").take(10000).collect::(); - set_var(&n, &s); - eq(var_os(&n), Some(&s)); - remove_var(&n); - eq(var_os(&n), None); -} - -#[test] -fn test_env_set_var() { - let n = make_rand_name(); - - let mut e = vars_os(); - set_var(&n, "VALUE"); - assert!(!e.any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); - - assert!(vars_os().any(|(k, v)| { - &*k == &*n && &*v == "VALUE" - })); -} diff --git a/src/test/run-pass-fulldeps/flt2dec.rs b/src/test/run-pass-fulldeps/flt2dec.rs deleted file mode 100644 index 3db0644d1ef..00000000000 --- a/src/test/run-pass-fulldeps/flt2dec.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// compile-flags:--test - -#![feature(rustc_private, flt2dec)] - -extern crate core; -extern crate rand; - -use std::i16; -use std::mem; -use std::str; - -use core::num::flt2dec::MAX_SIG_DIGITS; -use core::num::flt2dec::strategy::grisu::format_exact_opt; -use core::num::flt2dec::strategy::grisu::format_shortest_opt; -use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; - -use rand::{Rand, XorShiftRng}; -use rand::distributions::{IndependentSample, Range}; -pub fn decode_finite(v: T) -> Decoded { - match decode(v).1 { - FullDecoded::Finite(decoded) => decoded, - full_decoded => panic!("expected finite, got {:?} instead", full_decoded) - } -} - - -fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), - V: FnMut(usize) -> Decoded { - assert!(k <= 1024); - - let mut npassed = 0; // f(x) = Some(g(x)) - let mut nignored = 0; // f(x) = None - - for i in 0..n { - if (i & 0xfffff) == 0 { - println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", - i, n, nignored, npassed, i - nignored - npassed); - } - - let decoded = v(i); - let mut buf1 = [0; 1024]; - if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { - let mut buf2 = [0; 1024]; - let (len2, e2) = g(&decoded, &mut buf2[..k]); - if e1 == e2 && &buf1[..len1] == &buf2[..len2] { - npassed += 1; - } else { - println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", - i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, - str::from_utf8(&buf2[..len2]).unwrap(), e2); - } - } else { - nignored += 1; - } - } - println!("{}({}): done, ignored={} passed={} failed={}", - func, k, nignored, npassed, n - nignored - npassed); - assert!(nignored + npassed == n, - "{}({}): {} out of {} values returns an incorrect value!", - func, k, n - nignored - npassed, n); - (npassed, nignored) -} - -pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); - let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); - iterate("f32_random_equivalence_test", k, n, f, g, |_| { - let i: u32 = f32_range.ind_sample(&mut rng); - let x: f32 = unsafe {mem::transmute(i)}; - decode_finite(x) - }); -} - -pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); - let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); - iterate("f64_random_equivalence_test", k, n, f, g, |_| { - let i: u64 = f64_range.ind_sample(&mut rng); - let x: f64 = unsafe {mem::transmute(i)}; - decode_finite(x) - }); -} - -pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) - where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { - // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, - // so why not simply testing all of them? - // - // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), - // but with `-C opt-level=3 -C lto` this only takes about an hour or so. - - // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges - let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", - k, 0x7f7f_ffff, f, g, |i: usize| { - let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; - decode_finite(x) - }); - assert_eq!((npassed, nignored), (2121451881, 17643158)); -} - -#[test] -fn shortest_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); - f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); -} - -#[test] #[ignore] // it is too expensive -fn shortest_f32_exhaustive_equivalence_test() { - // it is hard to directly test the optimality of the output, but we can at least test if - // two different algorithms agree to each other. - // - // this reports the progress and the number of f32 values returned `None`. - // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: - // `done, ignored=17643158 passed=2121451881 failed=0`. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); -} - -#[test] #[ignore] // it is too expensive -fn shortest_f64_hard_random_equivalence_test() { - // this again probably has to use appropriate rustc flags. - - use core::num::flt2dec::strategy::dragon::format_shortest as fallback; - f64_random_equivalence_test(format_shortest_opt, fallback, - MAX_SIG_DIGITS, 100_000_000); -} - -#[test] -fn exact_f32_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - for k in 1..21 { - f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); - } -} - -#[test] -fn exact_f64_random_equivalence_test() { - use core::num::flt2dec::strategy::dragon::format_exact as fallback; - for k in 1..21 { - f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), - |d, buf| fallback(d, buf, i16::MIN), k, 1_000); - } -} diff --git a/src/test/run-pass-fulldeps/sort-unstable.rs b/src/test/run-pass-fulldeps/sort-unstable.rs deleted file mode 100644 index af8a691aa3e..00000000000 --- a/src/test/run-pass-fulldeps/sort-unstable.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private, sort_internals)] - -extern crate core; -extern crate rand; - -use std::cmp::Ordering::{Equal, Greater, Less}; -use core::slice::heapsort; - -use rand::{Rng, XorShiftRng}; - -fn main() { - let mut v = [0; 600]; - let mut tmp = [0; 600]; - let mut rng = XorShiftRng::new_unseeded(); - - for len in (2..25).chain(500..510) { - let v = &mut v[0..len]; - let tmp = &mut tmp[0..len]; - - for &modulus in &[5, 10, 100, 1000] { - for _ in 0..100 { - for i in 0..len { - v[i] = rng.gen::() % modulus; - } - - // Sort in default order. - tmp.copy_from_slice(v); - tmp.sort_unstable(); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in ascending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| a.cmp(b)); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Sort in descending order. - tmp.copy_from_slice(v); - tmp.sort_unstable_by(|a, b| b.cmp(a)); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - - // Test heapsort using `<` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a < b); - assert!(tmp.windows(2).all(|w| w[0] <= w[1])); - - // Test heapsort using `>` operator. - tmp.copy_from_slice(v); - heapsort(tmp, |a, b| a > b); - assert!(tmp.windows(2).all(|w| w[0] >= w[1])); - } - } - } - - // Sort using a completely random comparison function. - // This will reorder the elements *somehow*, but won't panic. - for i in 0..v.len() { - v[i] = i as i32; - } - v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); - v.sort_unstable(); - for i in 0..v.len() { - assert_eq!(v[i], i as i32); - } - - // Should not panic. - [0i32; 0].sort_unstable(); - [(); 10].sort_unstable(); - [(); 100].sort_unstable(); - - let mut v = [0xDEADBEEFu64]; - v.sort_unstable(); - assert!(v == [0xDEADBEEF]); -} diff --git a/src/test/run-pass-fulldeps/vector-sort-panic-safe.rs b/src/test/run-pass-fulldeps/vector-sort-panic-safe.rs deleted file mode 100644 index adc72aa0ea2..00000000000 --- a/src/test/run-pass-fulldeps/vector-sort-panic-safe.rs +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-emscripten no threads support - -#![feature(rustc_private)] -#![feature(sort_unstable)] - -extern crate rand; - -use rand::{thread_rng, Rng}; -use std::cell::Cell; -use std::cmp::Ordering; -use std::panic; -use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize}; -use std::sync::atomic::Ordering::Relaxed; -use std::thread; - -const MAX_LEN: usize = 80; - -static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [ - // FIXME #5244: AtomicUsize is not Copy. - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), -]; - -static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT; - -#[derive(Clone, Eq)] -struct DropCounter { - x: u32, - id: usize, - version: Cell, -} - -impl PartialEq for DropCounter { - fn eq(&self, other: &Self) -> bool { - self.partial_cmp(other) == Some(Ordering::Equal) - } -} - -impl PartialOrd for DropCounter { - fn partial_cmp(&self, other: &Self) -> Option { - self.version.set(self.version.get() + 1); - other.version.set(other.version.get() + 1); - VERSIONS.fetch_add(2, Relaxed); - self.x.partial_cmp(&other.x) - } -} - -impl Ord for DropCounter { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).unwrap() - } -} - -impl Drop for DropCounter { - fn drop(&mut self) { - DROP_COUNTS[self.id].fetch_add(1, Relaxed); - VERSIONS.fetch_sub(self.version.get(), Relaxed); - } -} - -macro_rules! test { - ($input:ident, $func:ident) => { - let len = $input.len(); - - // Work out the total number of comparisons required to sort - // this array... - let mut count = 0usize; - $input.to_owned().$func(|a, b| { count += 1; a.cmp(b) }); - - // ... and then panic on each and every single one. - for panic_countdown in 0..count { - // Refresh the counters. - VERSIONS.store(0, Relaxed); - for i in 0..len { - DROP_COUNTS[i].store(0, Relaxed); - } - - let v = $input.to_owned(); - let _ = thread::spawn(move || { - let mut v = v; - let mut panic_countdown = panic_countdown; - v.$func(|a, b| { - if panic_countdown == 0 { - SILENCE_PANIC.with(|s| s.set(true)); - panic!(); - } - panic_countdown -= 1; - a.cmp(b) - }) - }).join(); - - // Check that the number of things dropped is exactly - // what we expect (i.e. the contents of `v`). - for (i, c) in DROP_COUNTS.iter().enumerate().take(len) { - let count = c.load(Relaxed); - assert!(count == 1, - "found drop count == {} for i == {}, len == {}", - count, i, len); - } - - // Check that the most recent versions of values were dropped. - assert_eq!(VERSIONS.load(Relaxed), 0); - } - } -} - -thread_local!(static SILENCE_PANIC: Cell = Cell::new(false)); - -fn main() { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - if !SILENCE_PANIC.with(|s| s.get()) { - prev(info); - } - })); - - let mut rng = thread_rng(); - - for len in (1..20).chain(70..MAX_LEN) { - for &modulus in &[5, 20, 50] { - for &has_runs in &[false, true] { - let mut input = (0..len) - .map(|id| { - DropCounter { - x: rng.next_u32() % modulus, - id: id, - version: Cell::new(0), - } - }) - .collect::>(); - - if has_runs { - for c in &mut input { - c.x = c.id as u32; - } - - for _ in 0..5 { - let a = rng.gen::() % len; - let b = rng.gen::() % len; - if a < b { - input[a..b].reverse(); - } else { - input.swap(a, b); - } - } - } - - test!(input, sort_by); - test!(input, sort_unstable_by); - } - } - } -} diff --git a/src/tools/cargo b/src/tools/cargo index 1d6dfea44f9..5f83bb4044f 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 1d6dfea44f97199d5d5c177c7dadcde393eaff9a +Subproject commit 5f83bb4044f32b60d06717c609610f67411fc671 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 72414c2a53e..22c6af28cea 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -91,6 +91,7 @@ static WHITELIST: &'static [Crate] = &[ Crate("redox_termios"), Crate("regex"), Crate("regex-syntax"), + Crate("remove_dir_all"), Crate("rustc-demangle"), Crate("smallvec"), Crate("stable_deref_trait"), @@ -99,6 +100,7 @@ static WHITELIST: &'static [Crate] = &[ Crate("terminon"), Crate("termion"), Crate("thread_local"), + Crate("ucd-util"), Crate("unicode-width"), Crate("unreachable"), Crate("utf8-ranges"), -- cgit 1.4.1-3-g733a5 From e63b1a0e368e2f7d3bf5eadd1262dc530a38394b Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sun, 11 Mar 2018 17:17:18 -0400 Subject: Remove "and may change between Rust releases" --- src/libstd/io/stdio.rs | 6 +++--- src/libstd/net/addr.rs | 6 +++--- src/libstd/net/ip.rs | 6 +++--- src/libstd/time.rs | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 4565b7fa0d6..9a4cde7e162 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -32,7 +32,7 @@ thread_local! { /// the `std::io::stdio::stdin_raw` function. /// /// The size of a StdinRaw struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. struct StdinRaw(stdio::Stdin); /// A handle to a raw instance of the standard output stream of this process. @@ -41,7 +41,7 @@ struct StdinRaw(stdio::Stdin); /// the `std::io::stdio::stdout_raw` function. /// /// The size of a StdoutRaw struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. struct StdoutRaw(stdio::Stdout); /// A handle to a raw instance of the standard output stream of this process. @@ -50,7 +50,7 @@ struct StdoutRaw(stdio::Stdout); /// the `std::io::stdio::stderr_raw` function. /// /// The size of a StderrRaw struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. struct StderrRaw(stdio::Stderr); /// Constructs a new raw handle to the standard input of this process. diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 75b05063839..f985c1f2bc8 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -29,7 +29,7 @@ use slice; /// [`SocketAddrV6`]'s respective documentation for more details. /// /// The size of a SocketAddr instance may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// [IP address]: ../../std/net/enum.IpAddr.html /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html @@ -65,7 +65,7 @@ pub enum SocketAddr { /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// /// The size of a SocketAddrV4 struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [IPv4 address]: ../../std/net/struct.Ipv4Addr.html @@ -95,7 +95,7 @@ pub struct SocketAddrV4 { inner: c::sockaddr_in } /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// /// The size of a SocketAddrV6 struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [IPv6 address]: ../../std/net/struct.Ipv6Addr.html diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 36a34e147d5..67b9e7a2f9d 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -27,7 +27,7 @@ use sys_common::{AsInner, FromInner}; /// respective documentation for more details. /// /// The size of an IpAddr instance may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html /// [`Ipv6Addr`]: ../../std/net/struct.Ipv6Addr.html @@ -65,7 +65,7 @@ pub enum IpAddr { /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// /// The size of an Ipv4Addr struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// [IETF RFC 791]: https://tools.ietf.org/html/rfc791 /// [`IpAddr`]: ../../std/net/enum.IpAddr.html @@ -100,7 +100,7 @@ pub struct Ipv4Addr { /// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses. /// /// The size of an Ipv6Addr struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [`IpAddr`]: ../../std/net/enum.IpAddr.html diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 054450a5186..4e08301fe05 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -50,7 +50,7 @@ pub use core::time::Duration; /// instants). /// /// The size of an Instant struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// Example: /// @@ -92,7 +92,7 @@ pub struct Instant(time::Instant); /// or perhaps some other string representation. /// /// The size of a SystemTime struct may vary depending on the target operating -/// system, and may change between Rust releases. +/// system. /// /// [`Instant`]: ../../std/time/struct.Instant.html /// [`Result`]: ../../std/result/enum.Result.html -- cgit 1.4.1-3-g733a5 From 1999a3fb4154961329ecfff7d70a6303471b996a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Mar 2018 13:35:46 -0700 Subject: rustbuild: Tweak CFLAGS to various libstd pieces * Pass `opt_level(2)` when calculating CFLAGS to get the right flags on iOS * Unconditionally pass `-O2` when compiling libbacktrace This should... Close #48903 Close #48906 --- src/bootstrap/cc_detect.rs | 4 ++-- src/libstd/build.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 9e1b1f7db2f..8f393a4c573 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -77,7 +77,7 @@ pub fn find(build: &mut Build) { .collect::>(); for target in targets.into_iter() { let mut cfg = cc::Build::new(); - cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false) + cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false) .target(&target).host(&build.build); if target.contains("msvc") { cfg.static_crt(true); @@ -109,7 +109,7 @@ pub fn find(build: &mut Build) { let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::>(); for host in hosts.into_iter() { let mut cfg = cc::Build::new(); - cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true) + cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false).cpp(true) .target(&host).host(&build.build); let config = build.config.target_config.get(&host); if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { diff --git a/src/libstd/build.rs b/src/libstd/build.rs index a41c155f3fb..b3c71f4d81b 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -98,7 +98,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { .arg("--disable-host-shared") .arg(format!("--host={}", build_helper::gnu_target(target))) .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden")); + .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden -O2")); run(Command::new(build_helper::make(host)) .current_dir(&native.out_dir) -- cgit 1.4.1-3-g733a5 From 0e0f74bcf93341ff3b1d8b59f3639416a159a140 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 9 Mar 2018 07:25:54 -0800 Subject: rustc: Embed LLVM bitcode by default on iOS This commit updates rustc to embed bitcode in each object file generated by default when compiling for iOS. This was determined in #35968 as a step towards better compatibility with the iOS toolchain, so let's give it a spin and see how it turns out! Note that this also updates the `cc` dependency which should propagate this change of embedding bitcode for C dependencies as well. --- src/librustc/session/config.rs | 2 ++ src/librustc_back/target/mod.rs | 6 ++++ src/librustc_trans/back/write.rs | 78 +++++++++++++++++++++++++++++++++++++++- src/libstd/build.rs | 3 +- 4 files changed, 87 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 1c5cfa87ef4..3e894abd17c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1288,6 +1288,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "run `dsymutil` and delete intermediate object files"), ui_testing: bool = (false, parse_bool, [UNTRACKED], "format compiler diagnostics in a way that's better suitable for UI testing"), + embed_bitcode: bool = (false, parse_bool, [TRACKED], + "embed LLVM bitcode in object files"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 250d85d4520..f53eeb86a9c 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -473,6 +473,9 @@ pub struct TargetOptions { /// The default visibility for symbols in this target should be "hidden" /// rather than "default" pub default_hidden_visibility: bool, + + /// Whether or not bitcode is embedded in object files + pub embed_bitcode: bool, } impl Default for TargetOptions { @@ -544,6 +547,7 @@ impl Default for TargetOptions { i128_lowering: false, codegen_backend: "llvm".to_string(), default_hidden_visibility: false, + embed_bitcode: false, } } } @@ -792,6 +796,7 @@ impl Target { key!(no_builtins, bool); key!(codegen_backend); key!(default_hidden_visibility, bool); + key!(embed_bitcode, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -990,6 +995,7 @@ impl ToJson for Target { target_option_val!(no_builtins); target_option_val!(codegen_backend); target_option_val!(default_hidden_visibility); + target_option_val!(embed_bitcode); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 7651a8e748e..3e7422557e9 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -42,6 +42,7 @@ use syntax_pos::MultiSpan; use syntax_pos::symbol::Symbol; use type_::Type; use context::{is_pie_binary, get_reloc_model}; +use common::{C_bytes_in_context, val_ty}; use jobserver::{Client, Acquired}; use rustc_demangle; @@ -262,6 +263,8 @@ pub struct ModuleConfig { // emscripten's ecc compiler, when used as the linker. obj_is_bitcode: bool, no_integrated_as: bool, + embed_bitcode: bool, + embed_bitcode_marker: bool, } impl ModuleConfig { @@ -279,6 +282,8 @@ impl ModuleConfig { emit_asm: false, emit_obj: false, obj_is_bitcode: false, + embed_bitcode: false, + embed_bitcode_marker: false, no_integrated_as: false, no_verify: false, @@ -299,6 +304,17 @@ impl ModuleConfig { self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; + let embed_bitcode = sess.target.target.options.embed_bitcode || + sess.opts.debugging_opts.embed_bitcode; + if embed_bitcode { + match sess.opts.optimize { + config::OptLevel::No | + config::OptLevel::Less => { + self.embed_bitcode_marker = embed_bitcode; + } + _ => self.embed_bitcode = embed_bitcode, + } + } // Copy what clang does by turning on loop vectorization at O2 and // slp vectorization at O3. Otherwise configure other optimization aspects @@ -662,7 +678,7 @@ unsafe fn codegen(cgcx: &CodegenContext, let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); - if write_bc || config.emit_bc_compressed { + if write_bc || config.emit_bc_compressed || config.embed_bitcode { let thin; let old; let data = if llvm::LLVMRustThinLTOAvailable() { @@ -681,6 +697,11 @@ unsafe fn codegen(cgcx: &CodegenContext, timeline.record("write-bc"); } + if config.embed_bitcode { + embed_bitcode(cgcx, llcx, llmod, Some(data)); + timeline.record("embed-bc"); + } + if config.emit_bc_compressed { let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); let data = bytecode::encode(&mtrans.llmod_id, data); @@ -689,6 +710,8 @@ unsafe fn codegen(cgcx: &CodegenContext, } timeline.record("compress-bc"); } + } else if config.embed_bitcode_marker { + embed_bitcode(cgcx, llcx, llmod, None); } time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), @@ -796,6 +819,59 @@ unsafe fn codegen(cgcx: &CodegenContext, &cgcx.output_filenames)) } +/// Embed the bitcode of an LLVM module in the LLVM module itself. +/// +/// This is done primarily for iOS where it appears to be standard to compile C +/// code at least with `-fembed-bitcode` which creates two sections in the +/// executable: +/// +/// * __LLVM,__bitcode +/// * __LLVM,__cmdline +/// +/// It appears *both* of these sections are necessary to get the linker to +/// recognize what's going on. For us though we just always throw in an empty +/// cmdline section. +/// +/// Furthermore debug/O1 builds don't actually embed bitcode but rather just +/// embed an empty section. +/// +/// Basically all of this is us attempting to follow in the footsteps of clang +/// on iOS. See #35968 for lots more info. +unsafe fn embed_bitcode(cgcx: &CodegenContext, + llcx: ContextRef, + llmod: ModuleRef, + bitcode: Option<&[u8]>) { + let llconst = C_bytes_in_context(llcx, bitcode.unwrap_or(&[])); + let llglobal = llvm::LLVMAddGlobal( + llmod, + val_ty(llconst).to_ref(), + "rustc.embedded.module\0".as_ptr() as *const _, + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if cgcx.opts.target_triple.contains("-ios") { + "__LLVM,__bitcode\0" + } else { + ".llvmbc\0" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + + let llconst = C_bytes_in_context(llcx, &[]); + let llglobal = llvm::LLVMAddGlobal( + llmod, + val_ty(llconst).to_ref(), + "rustc.embedded.cmdline\0".as_ptr() as *const _, + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if cgcx.opts.target_triple.contains("-ios") { + "__LLVM,__cmdline\0" + } else { + ".llvmcmd\0" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); +} + pub(crate) struct CompiledModules { pub modules: Vec, pub metadata_module: CompiledModule, diff --git a/src/libstd/build.rs b/src/libstd/build.rs index b3c71f4d81b..6652ff98201 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -86,6 +86,7 @@ fn main() { fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?; + let cflags = env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden -O2"; run(Command::new("sh") .current_dir(&native.out_dir) @@ -98,7 +99,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { .arg("--disable-host-shared") .arg(format!("--host={}", build_helper::gnu_target(target))) .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden -O2")); + .env("CFLAGS", cflags)); run(Command::new(build_helper::make(host)) .current_dir(&native.out_dir) -- cgit 1.4.1-3-g733a5 From a9fc3901b07d0494bd3eb9c37b10e63b429714b0 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 21 Jan 2018 16:44:41 +0800 Subject: stabilise feature(never_type) Replace feature(never_type) with feature(exhaustive_patterns). feature(exhaustive_patterns) only covers the pattern-exhaustives checks that used to be covered by feature(never_type) --- src/libcore/cmp.rs | 8 +++---- src/libcore/fmt/mod.rs | 4 ++-- src/libcore/lib.rs | 3 ++- src/librustc/lib.rs | 2 +- src/librustc_lint/lib.rs | 1 + src/librustc_mir/build/matches/simplify.rs | 2 +- src/librustc_mir/hair/pattern/_match.rs | 6 ++--- src/librustc_mir/hair/pattern/check_match.rs | 2 +- src/librustc_mir/lib.rs | 3 ++- src/librustc_typeck/lib.rs | 3 ++- src/libstd/error.rs | 2 +- src/libstd/lib.rs | 3 ++- src/libstd/primitive_docs.rs | 11 ++++----- src/libsyntax/feature_gate.rs | 8 ++----- .../compile-fail/call-fn-never-arg-wrong-type.rs | 2 -- src/test/compile-fail/coerce-to-bang-cast.rs | 2 -- src/test/compile-fail/coerce-to-bang.rs | 1 - .../compile-fail/inhabitedness-infinite-loop.rs | 2 +- src/test/compile-fail/loop-break-value.rs | 2 -- src/test/compile-fail/match-privately-empty.rs | 2 +- src/test/compile-fail/never-assign-dead-code.rs | 2 +- src/test/compile-fail/never-assign-wrong-type.rs | 1 - .../recursive-types-are-not-uninhabited.rs | 2 -- src/test/compile-fail/uninhabited-irrefutable.rs | 2 +- src/test/compile-fail/uninhabited-patterns.rs | 2 +- src/test/compile-fail/unreachable-loop-patterns.rs | 2 +- src/test/compile-fail/unreachable-try-pattern.rs | 2 +- src/test/run-fail/adjust_never.rs | 2 -- src/test/run-fail/call-fn-never-arg.rs | 1 - src/test/run-fail/cast-never.rs | 2 -- src/test/run-fail/never-associated-type.rs | 2 -- src/test/run-fail/never-type-arg.rs | 2 -- .../run-pass/diverging-fallback-control-flow.rs | 2 -- src/test/run-pass/empty-types-in-patterns.rs | 2 +- src/test/run-pass/impl-for-never.rs | 2 -- src/test/run-pass/issue-38972.rs | 25 ------------------- src/test/run-pass/issue-44402.rs | 2 +- src/test/run-pass/loop-break-value.rs | 2 -- src/test/run-pass/mir_calls_to_shims.rs | 1 - src/test/run-pass/never-result.rs | 2 -- src/test/ui/feature-gate-exhaustive-patterns.rs | 18 ++++++++++++++ .../ui/feature-gate-exhaustive-patterns.stderr | 8 +++++++ src/test/ui/feature-gate-never_type.rs | 28 ---------------------- src/test/ui/print_type_sizes/uninhabited.rs | 1 - src/test/ui/reachable/expr_add.rs | 1 - src/test/ui/reachable/expr_add.stderr | 4 ++-- src/test/ui/reachable/expr_array.rs | 3 +-- src/test/ui/reachable/expr_array.stderr | 4 ++-- src/test/ui/reachable/expr_assign.rs | 1 - src/test/ui/reachable/expr_assign.stderr | 6 ++--- src/test/ui/reachable/expr_block.rs | 1 - src/test/ui/reachable/expr_block.stderr | 4 ++-- src/test/ui/reachable/expr_call.rs | 1 - src/test/ui/reachable/expr_call.stderr | 4 ++-- src/test/ui/reachable/expr_cast.rs | 1 - src/test/ui/reachable/expr_cast.stderr | 2 +- src/test/ui/reachable/expr_if.rs | 1 - src/test/ui/reachable/expr_if.stderr | 2 +- src/test/ui/reachable/expr_loop.rs | 1 - src/test/ui/reachable/expr_loop.stderr | 6 ++--- src/test/ui/reachable/expr_match.rs | 1 - src/test/ui/reachable/expr_match.stderr | 6 ++--- src/test/ui/reachable/expr_method.rs | 1 - src/test/ui/reachable/expr_method.stderr | 4 ++-- src/test/ui/reachable/expr_repeat.rs | 1 - src/test/ui/reachable/expr_repeat.stderr | 2 +- src/test/ui/reachable/expr_return.rs | 1 - src/test/ui/reachable/expr_return.stderr | 2 +- src/test/ui/reachable/expr_struct.rs | 1 - src/test/ui/reachable/expr_struct.stderr | 8 +++---- src/test/ui/reachable/expr_tup.rs | 1 - src/test/ui/reachable/expr_tup.stderr | 4 ++-- src/test/ui/reachable/expr_type.rs | 1 - src/test/ui/reachable/expr_type.stderr | 2 +- src/test/ui/reachable/expr_unary.rs | 1 - src/test/ui/reachable/expr_unary.stderr | 6 ++--- src/test/ui/reachable/expr_while.rs | 1 - src/test/ui/reachable/expr_while.stderr | 6 ++--- 78 files changed, 101 insertions(+), 174 deletions(-) delete mode 100644 src/test/run-pass/issue-38972.rs create mode 100644 src/test/ui/feature-gate-exhaustive-patterns.rs create mode 100644 src/test/ui/feature-gate-exhaustive-patterns.stderr delete mode 100644 src/test/ui/feature-gate-never_type.rs (limited to 'src/libstd') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 6602643dc51..fdb9946469b 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -882,24 +882,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl Eq for ! {} - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[stable(feature = "never_type", since = "1.24.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 213b317f632..3706da7c521 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1579,14 +1579,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.24.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.24.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index cefcc5ff03f..a947c9f0b7c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -85,7 +85,7 @@ #![feature(iterator_repeat_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(no_core)] #![feature(on_unimplemented)] #![feature(optin_builtin_traits)] @@ -103,6 +103,7 @@ #![feature(unwind_attributes)] #![cfg_attr(stage0, allow(unused_attributes))] +#![cfg_attr(stage0, feature(never_type))] #[prelude_import] #[allow(unused)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 77b3a87c0ed..51882385b2e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -60,7 +60,7 @@ #![feature(match_default_bindings)] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(non_exhaustive)] #![feature(nonzero)] #![feature(proc_macro_internals)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 235d733b253..cbc1d7c38d6 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -32,6 +32,7 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate syntax; diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index abea5583546..4e95ee6444d 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { - self.hir.tcx().features().never_type && + self.hir.tcx().features().exhaustive_patterns && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } }); diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 58aa9b06c64..6f8b1f8e799 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -219,7 +219,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { - if self.tcx.features().never_type { + if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(self.module, ty) } else { false @@ -245,7 +245,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { substs: &'tcx ty::subst::Substs<'tcx>) -> bool { - if self.tcx.features().never_type { + if self.tcx.features().exhaustive_patterns { self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs) } else { false @@ -694,7 +694,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, // test for details. // // FIXME: currently the only way I know of something can - // be a privately-empty enum is when the never_type + // be a privately-empty enum is when the exhaustive_patterns // feature flag is not present, so this is only // needed for that case. diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 69ed4e6064f..d924baaf005 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let pat_ty = self.tables.node_id_to_type(scrut.hir_id); let module = self.tcx.hir.get_module_parent(scrut.id); if inlined_arms.is_empty() { - let scrutinee_is_uninhabited = if self.tcx.features().never_type { + let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(module, pat_ty) } else { self.conservative_is_uninhabited(pat_ty) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index c31e95fd826..5510e219780 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -32,13 +32,14 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(inclusive_range)] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(placement_in_syntax)] #![feature(collection_placement)] #![feature(nonzero)] #![feature(underscore_lifetimes)] +#![cfg_attr(stage0, feature(never_type))] extern crate arena; #[macro_use] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index ea90c35cb8f..a97c6e84eab 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -80,13 +80,14 @@ This API is completely unstable and subject to change. #![feature(crate_visibility_modifier)] #![feature(from_ref)] #![feature(match_default_bindings)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(option_filter)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] #![feature(i128_type)] +#![cfg_attr(stage0, feature(never_type))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index eb5022ad577..347b8224410 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -234,7 +234,7 @@ impl<'a> From> for Box { } } -#[unstable(feature = "never_type", issue = "35121")] +#[stable(feature = "never_type", since = "1.24.0")] impl Error for ! { fn description(&self) -> &str { *self } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index da15941374d..eea0e6b6752 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -282,7 +282,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] @@ -324,6 +324,7 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] +#![cfg_attr(stage0, feature(never_type))] #![default_lib_allocator] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 358aa2c37df..e6e6be2e453 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -79,7 +79,6 @@ mod prim_bool { } /// write: /// /// ``` -/// #![feature(never_type)] /// # fn foo() -> u32 { /// let x: ! = { /// return 123 @@ -131,13 +130,15 @@ mod prim_bool { } /// [`Result`] which we can unpack like this: /// /// ```ignore (string-from-str-error-type-is-not-never-yet) +/// #[feature(exhaustive_patterns)] /// // NOTE: This does not work today! /// let Ok(s) = String::from_str("hello"); /// ``` /// -/// Since the [`Err`] variant contains a `!`, it can never occur. So we can exhaustively match on -/// [`Result`] by just taking the [`Ok`] variant. This illustrates another behaviour of `!` - -/// it can be used to "delete" certain enum variants from generic types like `Result`. +/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` +/// feature is present this means we can exhaustively match on [`Result`] by just taking the +/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain +/// enum variants from generic types like `Result`. /// /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str /// [`Result`]: result/enum.Result.html @@ -154,7 +155,6 @@ mod prim_bool { } /// for example: /// /// ``` -/// # #![feature(never_type)] /// # use std::fmt; /// # trait Debug { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; @@ -192,7 +192,6 @@ mod prim_bool { } /// [`Default`]: default/trait.Default.html /// [`default()`]: default/trait.Default.html#tymethod.default /// -#[unstable(feature = "never_type", issue = "35121")] mod prim_never { } #[doc(primitive = "char")] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ec9a15d9f2b..91364fe6ed4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -286,8 +286,8 @@ declare_features! ( // Allows `impl Trait` in function arguments. (active, universal_impl_trait, "1.23.0", Some(34511), None), - // The `!` type - (active, never_type, "1.13.0", Some(35121), None), + // Allows exhaustive pattern matching on types that contain uninhabited types. + (active, exhaustive_patterns, "1.13.0", None, None), // Allows all literals in attribute lists and values of key-value pairs. (active, attr_literals, "1.13.0", Some(34981), None), @@ -1566,10 +1566,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_abi(bare_fn_ty.abi, ty.span); } - ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, - "The `!` type is experimental"); - }, ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { gate_feature_post!(&self, dyn_trait, ty.span, "`dyn Trait` syntax is unstable"); diff --git a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs index 583befed1e8..c2f157cd35c 100644 --- a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs +++ b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs @@ -10,8 +10,6 @@ // Test that we can't pass other types for ! -#![feature(never_type)] - fn foo(x: !) -> ! { x } diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs index 0d5bf6cd68c..8b3a9ed092d 100644 --- a/src/test/compile-fail/coerce-to-bang-cast.rs +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] - fn foo(x: usize, y: !, z: usize) { } #[deny(coerce_never)] diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index b804bb2981b..b365f142a9b 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] #![deny(coerce_never)] fn foo(x: usize, y: !, z: usize) { } diff --git a/src/test/compile-fail/inhabitedness-infinite-loop.rs b/src/test/compile-fail/inhabitedness-infinite-loop.rs index 91b85d7510a..b9741e0add6 100644 --- a/src/test/compile-fail/inhabitedness-infinite-loop.rs +++ b/src/test/compile-fail/inhabitedness-infinite-loop.rs @@ -10,7 +10,7 @@ // error-pattern:reached recursion limit -#![feature(never_type)] +#![feature(exhaustive_patterns)] struct Foo<'a, T: 'a> { ph: std::marker::PhantomData, diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index 938f7fba2a0..5ef46bb27fd 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] - fn main() { let val: ! = loop { break break; }; //~^ ERROR mismatched types diff --git a/src/test/compile-fail/match-privately-empty.rs b/src/test/compile-fail/match-privately-empty.rs index 3affb1c03e9..e18c7d77ce3 100644 --- a/src/test/compile-fail/match-privately-empty.rs +++ b/src/test/compile-fail/match-privately-empty.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] mod private { pub struct Private { diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 1e0cc0f5357..4e987d1ddce 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -10,7 +10,7 @@ // Test that an assignment of type ! makes the rest of the block dead code. -#![feature(never_type, rustc_attrs)] +#![feature(rustc_attrs)] #![warn(unused)] #[rustc_error] diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index c0dd2cab749..8c2de7d68d3 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -10,7 +10,6 @@ // Test that we can't use another type in place of ! -#![feature(never_type)] #![deny(warnings)] fn main() { diff --git a/src/test/compile-fail/recursive-types-are-not-uninhabited.rs b/src/test/compile-fail/recursive-types-are-not-uninhabited.rs index f8d6c3de2ab..fa936697072 100644 --- a/src/test/compile-fail/recursive-types-are-not-uninhabited.rs +++ b/src/test/compile-fail/recursive-types-are-not-uninhabited.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//#![feature(never_type)] - struct R<'a> { r: &'a R<'a>, } diff --git a/src/test/compile-fail/uninhabited-irrefutable.rs b/src/test/compile-fail/uninhabited-irrefutable.rs index 4755fdd4fd5..72b0afa6bd3 100644 --- a/src/test/compile-fail/uninhabited-irrefutable.rs +++ b/src/test/compile-fail/uninhabited-irrefutable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] mod foo { pub struct SecretlyEmpty { diff --git a/src/test/compile-fail/uninhabited-patterns.rs b/src/test/compile-fail/uninhabited-patterns.rs index 4c894b0bdd3..9f943f08232 100644 --- a/src/test/compile-fail/uninhabited-patterns.rs +++ b/src/test/compile-fail/uninhabited-patterns.rs @@ -11,7 +11,7 @@ #![feature(box_patterns)] #![feature(slice_patterns)] #![feature(box_syntax)] -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] mod foo { diff --git a/src/test/compile-fail/unreachable-loop-patterns.rs b/src/test/compile-fail/unreachable-loop-patterns.rs index 6147692658f..dca79bdfb87 100644 --- a/src/test/compile-fail/unreachable-loop-patterns.rs +++ b/src/test/compile-fail/unreachable-loop-patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] fn main() { diff --git a/src/test/compile-fail/unreachable-try-pattern.rs b/src/test/compile-fail/unreachable-try-pattern.rs index 46ea4a06a3b..0caf7d51234 100644 --- a/src/test/compile-fail/unreachable-try-pattern.rs +++ b/src/test/compile-fail/unreachable-try-pattern.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type, rustc_attrs)] +#![feature(exhaustive_patterns, rustc_attrs)] #![warn(unreachable_code)] #![warn(unreachable_patterns)] diff --git a/src/test/run-fail/adjust_never.rs b/src/test/run-fail/adjust_never.rs index ccdb1ca15bb..7a4b5e59eeb 100644 --- a/src/test/run-fail/adjust_never.rs +++ b/src/test/run-fail/adjust_never.rs @@ -10,8 +10,6 @@ // Test that a variable of type ! can coerce to another type. -#![feature(never_type)] - // error-pattern:explicit fn main() { let x: ! = panic!(); diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/run-fail/call-fn-never-arg.rs index 95101e70db9..56454586bb9 100644 --- a/src/test/run-fail/call-fn-never-arg.rs +++ b/src/test/run-fail/call-fn-never-arg.rs @@ -12,7 +12,6 @@ // error-pattern:wowzers! -#![feature(never_type)] #![allow(unreachable_code)] fn foo(x: !) -> ! { diff --git a/src/test/run-fail/cast-never.rs b/src/test/run-fail/cast-never.rs index acd002494f4..0155332c51d 100644 --- a/src/test/run-fail/cast-never.rs +++ b/src/test/run-fail/cast-never.rs @@ -10,8 +10,6 @@ // Test that we can explicitly cast ! to another type -#![feature(never_type)] - // error-pattern:explicit fn main() { let x: ! = panic!(); diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/run-fail/never-associated-type.rs index 345674f3f52..d9b8461a1d0 100644 --- a/src/test/run-fail/never-associated-type.rs +++ b/src/test/run-fail/never-associated-type.rs @@ -10,8 +10,6 @@ // Test that we can use ! as an associated type. -#![feature(never_type)] - // error-pattern:kapow! trait Foo { diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/run-fail/never-type-arg.rs index 826ca3a08c0..0fe10d43910 100644 --- a/src/test/run-fail/never-type-arg.rs +++ b/src/test/run-fail/never-type-arg.rs @@ -12,8 +12,6 @@ // error-pattern:oh no! -#![feature(never_type)] - struct Wub; impl PartialEq for Wub { diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs index 723a98bcdfa..a96f98b9efd 100644 --- a/src/test/run-pass/diverging-fallback-control-flow.rs +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -14,8 +14,6 @@ // These represent current behavior, but are pretty dubious. I would // like to revisit these and potentially change them. --nmatsakis -#![feature(never_type)] - trait BadDefault { fn default() -> Self; } diff --git a/src/test/run-pass/empty-types-in-patterns.rs b/src/test/run-pass/empty-types-in-patterns.rs index 033b185a0ef..87db4401929 100644 --- a/src/test/run-pass/empty-types-in-patterns.rs +++ b/src/test/run-pass/empty-types-in-patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![allow(unreachable_patterns)] #![allow(unreachable_code)] diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs index 794f5969bff..cf54e1c3bd5 100644 --- a/src/test/run-pass/impl-for-never.rs +++ b/src/test/run-pass/impl-for-never.rs @@ -10,8 +10,6 @@ // Test that we can call static methods on ! both directly and when it appears in a generic -#![feature(never_type)] - trait StringifyType { fn stringify_type() -> &'static str; } diff --git a/src/test/run-pass/issue-38972.rs b/src/test/run-pass/issue-38972.rs deleted file mode 100644 index d5df84e0fb0..00000000000 --- a/src/test/run-pass/issue-38972.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This issue tracks a regression (a new warning) without -// feature(never_type). When we make that the default, please -// remove this test. - -enum Foo { } - -fn make_foo() -> Option { None } - -#[deny(warnings)] -fn main() { - match make_foo() { - None => {}, - Some(_) => {} - } -} diff --git a/src/test/run-pass/issue-44402.rs b/src/test/run-pass/issue-44402.rs index 244aa65a3d5..a5a0a5a5794 100644 --- a/src/test/run-pass/issue-44402.rs +++ b/src/test/run-pass/issue-44402.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] +#![feature(exhaustive_patterns)] // Regression test for inhabitedness check. The old // cache used to cause us to incorrectly decide diff --git a/src/test/run-pass/loop-break-value.rs b/src/test/run-pass/loop-break-value.rs index 39053769b24..ffdd99ebf6e 100644 --- a/src/test/run-pass/loop-break-value.rs +++ b/src/test/run-pass/loop-break-value.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] - #[allow(unused)] fn never_returns() { loop { diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs index 9641ed28293..dda7a46f325 100644 --- a/src/test/run-pass/mir_calls_to_shims.rs +++ b/src/test/run-pass/mir_calls_to_shims.rs @@ -11,7 +11,6 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] -#![feature(never_type)] use std::panic; diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs index 5c0af392f44..8aa2a13ed8c 100644 --- a/src/test/run-pass/never-result.rs +++ b/src/test/run-pass/never-result.rs @@ -10,8 +10,6 @@ // Test that we can extract a ! through pattern matching then use it as several different types. -#![feature(never_type)] - fn main() { let x: Result = Ok(123); match x { diff --git a/src/test/ui/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gate-exhaustive-patterns.rs new file mode 100644 index 00000000000..477dd1b38eb --- /dev/null +++ b/src/test/ui/feature-gate-exhaustive-patterns.rs @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> Result { + Ok(123) +} + +fn main() { + let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding +} + diff --git a/src/test/ui/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gate-exhaustive-patterns.stderr new file mode 100644 index 00000000000..43a4adf9373 --- /dev/null +++ b/src/test/ui/feature-gate-exhaustive-patterns.stderr @@ -0,0 +1,8 @@ +error[E0005]: refutable pattern in local binding: `Err(_)` not covered + --> $DIR/feature-gate-exhaustive-patterns.rs:16:9 + | +16 | let Ok(_x) = foo(); //~ ERROR refutable pattern in local binding + | ^^^^^^ pattern `Err(_)` not covered + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gate-never_type.rs b/src/test/ui/feature-gate-never_type.rs deleted file mode 100644 index 11b9f412957..00000000000 --- a/src/test/ui/feature-gate-never_type.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that ! errors when used in illegal positions with feature(never_type) disabled - -trait Foo { - type Wub; -} - -type Ma = (u32, !, i32); //~ ERROR type is experimental -type Meeshka = Vec; //~ ERROR type is experimental -type Mow = &fn(!) -> !; //~ ERROR type is experimental -type Skwoz = &mut !; //~ ERROR type is experimental - -impl Foo for Meeshka { - type Wub = !; //~ ERROR type is experimental -} - -fn main() { -} - diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index 4d0396903e5..7e8eff02c20 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -11,7 +11,6 @@ // compile-flags: -Z print-type-sizes // must-compile-successfully -#![feature(never_type)] #![feature(start)] #[start] diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs index dd43c58de6d..3e39b75d8c0 100644 --- a/src/test/ui/reachable/expr_add.rs +++ b/src/test/ui/reachable/expr_add.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] #![allow(unused_variables)] #![deny(unreachable_code)] diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr index d3e1da0e718..f49a781ce33 100644 --- a/src/test/ui/reachable/expr_add.stderr +++ b/src/test/ui/reachable/expr_add.stderr @@ -1,11 +1,11 @@ error: unreachable expression - --> $DIR/expr_add.rs:27:13 + --> $DIR/expr_add.rs:26:13 | LL | let x = Foo + return; //~ ERROR unreachable | ^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/expr_add.rs:13:9 + --> $DIR/expr_add.rs:12:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_array.rs b/src/test/ui/reachable/expr_array.rs index 31229668796..323a5752e22 100644 --- a/src/test/ui/reachable/expr_array.rs +++ b/src/test/ui/reachable/expr_array.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { @@ -21,7 +20,7 @@ fn a() { } fn b() { - // the `array is unreachable: + // the array is unreachable: let x: [usize; 2] = [22, return]; //~ ERROR unreachable } diff --git a/src/test/ui/reachable/expr_array.stderr b/src/test/ui/reachable/expr_array.stderr index 3257514ea50..78ac76a6137 100644 --- a/src/test/ui/reachable/expr_array.stderr +++ b/src/test/ui/reachable/expr_array.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_array.rs:20:34 + --> $DIR/expr_array.rs:19:34 | LL | let x: [usize; 2] = [return, 22]; //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_array.rs:25:25 + --> $DIR/expr_array.rs:24:25 | LL | let x: [usize; 2] = [22, return]; //~ ERROR unreachable | ^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs index e6fb46a5bac..73083af34d9 100644 --- a/src/test/ui/reachable/expr_assign.rs +++ b/src/test/ui/reachable/expr_assign.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo() { // No error here. diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr index 15dcf2c2401..628bfbf6217 100644 --- a/src/test/ui/reachable/expr_assign.stderr +++ b/src/test/ui/reachable/expr_assign.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_assign.rs:20:5 + --> $DIR/expr_assign.rs:19:5 | LL | x = return; //~ ERROR unreachable | ^^^^^^^^^^ @@ -11,13 +11,13 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_assign.rs:30:14 + --> $DIR/expr_assign.rs:29:14 | LL | *p = return; //~ ERROR unreachable | ^^^^^^ error: unreachable expression - --> $DIR/expr_assign.rs:36:15 + --> $DIR/expr_assign.rs:35:15 | LL | *{return; &mut i} = 22; //~ ERROR unreachable | ^^^^^^ diff --git a/src/test/ui/reachable/expr_block.rs b/src/test/ui/reachable/expr_block.rs index 57b5d3cabce..93bce43f76d 100644 --- a/src/test/ui/reachable/expr_block.rs +++ b/src/test/ui/reachable/expr_block.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn a() { // Here the tail expression is considered unreachable: diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr index a0cef6449f7..5f5696aadb3 100644 --- a/src/test/ui/reachable/expr_block.stderr +++ b/src/test/ui/reachable/expr_block.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_block.rs:21:9 + --> $DIR/expr_block.rs:20:9 | LL | 22 //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable statement - --> $DIR/expr_block.rs:36:9 + --> $DIR/expr_block.rs:35:9 | LL | println!("foo"); | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs index 86b95aad9c2..2772dd429d1 100644 --- a/src/test/ui/reachable/expr_call.rs +++ b/src/test/ui/reachable/expr_call.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo(x: !, y: usize) { } diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr index 455e5ab3653..414d29ec2a7 100644 --- a/src/test/ui/reachable/expr_call.stderr +++ b/src/test/ui/reachable/expr_call.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_call.rs:23:17 + --> $DIR/expr_call.rs:22:17 | LL | foo(return, 22); //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_call.rs:28:5 + --> $DIR/expr_call.rs:27:5 | LL | bar(return); //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs index 76b00c00ad9..88846b63841 100644 --- a/src/test/ui/reachable/expr_cast.rs +++ b/src/test/ui/reachable/expr_cast.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_cast.stderr b/src/test/ui/reachable/expr_cast.stderr index 8c37759aa46..458334e2af9 100644 --- a/src/test/ui/reachable/expr_cast.stderr +++ b/src/test/ui/reachable/expr_cast.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_cast.rs:20:13 + --> $DIR/expr_cast.rs:19:13 | LL | let x = {return} as !; //~ ERROR unreachable | ^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs index 2a265e772f3..d2fb1044e48 100644 --- a/src/test/ui/reachable/expr_if.rs +++ b/src/test/ui/reachable/expr_if.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo() { if {return} { diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr index c14cdbfc2bc..6e8afd1c5be 100644 --- a/src/test/ui/reachable/expr_if.stderr +++ b/src/test/ui/reachable/expr_if.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/expr_if.rs:38:5 + --> $DIR/expr_if.rs:37:5 | LL | println!("But I am."); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_loop.rs b/src/test/ui/reachable/expr_loop.rs index 3ed4b2dcf0c..533cdac0968 100644 --- a/src/test/ui/reachable/expr_loop.rs +++ b/src/test/ui/reachable/expr_loop.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn a() { loop { return; } diff --git a/src/test/ui/reachable/expr_loop.stderr b/src/test/ui/reachable/expr_loop.stderr index 7f834567de3..a51ef293acf 100644 --- a/src/test/ui/reachable/expr_loop.stderr +++ b/src/test/ui/reachable/expr_loop.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/expr_loop.rs:19:5 + --> $DIR/expr_loop.rs:18:5 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(unreachable_code)] = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_loop.rs:31:5 + --> $DIR/expr_loop.rs:30:5 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | println!("I am dead."); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_loop.rs:41:5 + --> $DIR/expr_loop.rs:40:5 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_match.rs b/src/test/ui/reachable/expr_match.rs index d2b96e51a95..193edd77435 100644 --- a/src/test/ui/reachable/expr_match.rs +++ b/src/test/ui/reachable/expr_match.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn a() { // The match is considered unreachable here, because the `return` diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr index d4cf21cef28..dfc1417f3d2 100644 --- a/src/test/ui/reachable/expr_match.stderr +++ b/src/test/ui/reachable/expr_match.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_match.rs:20:5 + --> $DIR/expr_match.rs:19:5 | LL | match {return} { } //~ ERROR unreachable | ^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable statement - --> $DIR/expr_match.rs:25:5 + --> $DIR/expr_match.rs:24:5 | LL | println!("I am dead"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | println!("I am dead"); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_match.rs:35:5 + --> $DIR/expr_match.rs:34:5 | LL | println!("I am dead"); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs index 8be71e464b2..7dabb307097 100644 --- a/src/test/ui/reachable/expr_method.rs +++ b/src/test/ui/reachable/expr_method.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] struct Foo; diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr index b9348b5d481..6d67bfcd54a 100644 --- a/src/test/ui/reachable/expr_method.stderr +++ b/src/test/ui/reachable/expr_method.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_method.rs:26:21 + --> $DIR/expr_method.rs:25:21 | LL | Foo.foo(return, 22); //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_method.rs:31:5 + --> $DIR/expr_method.rs:30:5 | LL | Foo.bar(return); //~ ERROR unreachable | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_repeat.rs b/src/test/ui/reachable/expr_repeat.rs index 47ee2ba62b8..fd9fca413a7 100644 --- a/src/test/ui/reachable/expr_repeat.rs +++ b/src/test/ui/reachable/expr_repeat.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_repeat.stderr b/src/test/ui/reachable/expr_repeat.stderr index 90cc3183c72..36393de90b7 100644 --- a/src/test/ui/reachable/expr_repeat.stderr +++ b/src/test/ui/reachable/expr_repeat.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_repeat.rs:20:25 + --> $DIR/expr_repeat.rs:19:25 | LL | let x: [usize; 2] = [return; 2]; //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_return.rs b/src/test/ui/reachable/expr_return.rs index fac1116dc68..9bbbe6f9099 100644 --- a/src/test/ui/reachable/expr_return.rs +++ b/src/test/ui/reachable/expr_return.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_return.stderr b/src/test/ui/reachable/expr_return.stderr index 3876da6541d..2dcc50944c5 100644 --- a/src/test/ui/reachable/expr_return.stderr +++ b/src/test/ui/reachable/expr_return.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_return.rs:21:22 + --> $DIR/expr_return.rs:20:22 | LL | let x = {return {return {return;}}}; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_struct.rs b/src/test/ui/reachable/expr_struct.rs index b5acd395be6..66414f6084b 100644 --- a/src/test/ui/reachable/expr_struct.rs +++ b/src/test/ui/reachable/expr_struct.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] struct Foo { diff --git a/src/test/ui/reachable/expr_struct.stderr b/src/test/ui/reachable/expr_struct.stderr index 43985bbbb5c..3f0ecb20479 100644 --- a/src/test/ui/reachable/expr_struct.stderr +++ b/src/test/ui/reachable/expr_struct.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_struct.rs:25:13 + --> $DIR/expr_struct.rs:24:13 | LL | let x = Foo { a: 22, b: 33, ..return }; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,19 +11,19 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_struct.rs:30:33 + --> $DIR/expr_struct.rs:29:33 | LL | let x = Foo { a: return, b: 33, ..return }; //~ ERROR unreachable | ^^ error: unreachable expression - --> $DIR/expr_struct.rs:35:39 + --> $DIR/expr_struct.rs:34:39 | LL | let x = Foo { a: 22, b: return, ..return }; //~ ERROR unreachable | ^^^^^^ error: unreachable expression - --> $DIR/expr_struct.rs:40:13 + --> $DIR/expr_struct.rs:39:13 | LL | let x = Foo { a: 22, b: return }; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_tup.rs b/src/test/ui/reachable/expr_tup.rs index 089020bf385..e2c10090248 100644 --- a/src/test/ui/reachable/expr_tup.rs +++ b/src/test/ui/reachable/expr_tup.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_tup.stderr b/src/test/ui/reachable/expr_tup.stderr index ff9aa666d8e..d372373ced0 100644 --- a/src/test/ui/reachable/expr_tup.stderr +++ b/src/test/ui/reachable/expr_tup.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_tup.rs:20:38 + --> $DIR/expr_tup.rs:19:38 | LL | let x: (usize, usize) = (return, 2); //~ ERROR unreachable | ^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: unreachable expression - --> $DIR/expr_tup.rs:25:29 + --> $DIR/expr_tup.rs:24:29 | LL | let x: (usize, usize) = (2, return); //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs index 29c59d5304f..2381ea2ac7a 100644 --- a/src/test/ui/reachable/expr_type.rs +++ b/src/test/ui/reachable/expr_type.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] #![feature(type_ascription)] fn a() { diff --git a/src/test/ui/reachable/expr_type.stderr b/src/test/ui/reachable/expr_type.stderr index d6b9f75edf1..9b165d6b3ee 100644 --- a/src/test/ui/reachable/expr_type.stderr +++ b/src/test/ui/reachable/expr_type.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_type.rs:20:13 + --> $DIR/expr_type.rs:19:13 | LL | let x = {return}: !; //~ ERROR unreachable | ^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index ad12cb876fe..524784934c7 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -13,7 +13,6 @@ #![allow(dead_code)] #![deny(unreachable_code)] #![deny(coerce_never)] -#![feature(never_type)] fn foo() { let x: ! = ! { return; 22 }; //~ ERROR unreachable diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index b09721e5957..1239701cabd 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -1,5 +1,5 @@ error: unreachable expression - --> $DIR/expr_unary.rs:19:28 + --> $DIR/expr_unary.rs:18:28 | LL | let x: ! = ! { return; 22 }; //~ ERROR unreachable | ^^ @@ -11,7 +11,7 @@ LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ error: cannot coerce `{integer}` to ! - --> $DIR/expr_unary.rs:19:28 + --> $DIR/expr_unary.rs:18:28 | LL | let x: ! = ! { return; 22 }; //~ ERROR unreachable | ^^ @@ -25,7 +25,7 @@ LL | #![deny(coerce_never)] = note: for more information, see issue #46325 error[E0600]: cannot apply unary operator `!` to type `!` - --> $DIR/expr_unary.rs:19:16 + --> $DIR/expr_unary.rs:18:16 | LL | let x: ! = ! { return; 22 }; //~ ERROR unreachable | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reachable/expr_while.rs b/src/test/ui/reachable/expr_while.rs index 7dcd609fbc8..79fa69a9289 100644 --- a/src/test/ui/reachable/expr_while.rs +++ b/src/test/ui/reachable/expr_while.rs @@ -12,7 +12,6 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(never_type)] fn foo() { while {return} { diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr index cd093906615..90c35bfaa7a 100644 --- a/src/test/ui/reachable/expr_while.stderr +++ b/src/test/ui/reachable/expr_while.stderr @@ -1,5 +1,5 @@ error: unreachable statement - --> $DIR/expr_while.rs:19:9 + --> $DIR/expr_while.rs:18:9 | LL | println!("Hello, world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(unreachable_code)] = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_while.rs:33:9 + --> $DIR/expr_while.rs:32:9 | LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | println!("I am dead."); = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement - --> $DIR/expr_while.rs:35:5 + --> $DIR/expr_while.rs:34:5 | LL | println!("I am, too."); | ^^^^^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 32ddb30715f73498477262c992d1152cf10ca631 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Sun, 21 Jan 2018 18:30:04 +0800 Subject: Fix version number --- src/libcore/cmp.rs | 8 ++++---- src/libcore/fmt/mod.rs | 4 ++-- src/libstd/error.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index fdb9946469b..3923b652afc 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -882,24 +882,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl Eq for ! {} - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[stable(feature = "never_type", since = "1.24.0")] + #[stable(feature = "never_type", since = "1.25.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 3706da7c521..40b88ded27d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1579,14 +1579,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[stable(feature = "never_type", since = "1.24.0")] +#[stable(feature = "never_type", since = "1.25.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[stable(feature = "never_type", since = "1.24.0")] +#[stable(feature = "never_type", since = "1.25.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 347b8224410..1743dfbfb7b 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -234,7 +234,7 @@ impl<'a> From> for Box { } } -#[stable(feature = "never_type", since = "1.24.0")] +#[stable(feature = "never_type", since = "1.25.0")] impl Error for ! { fn description(&self) -> &str { *self } } -- cgit 1.4.1-3-g733a5 From a704624ef5830541acb9912146fa28305b9a920c Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 1 Mar 2018 01:41:10 +0800 Subject: change never_type stabilisation version --- src/libcore/cmp.rs | 8 ++++---- src/libcore/fmt/mod.rs | 4 ++-- src/libstd/error.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 3923b652afc..67445daa436 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -882,24 +882,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl Eq for ! {} - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[stable(feature = "never_type", since = "1.25.0")] + #[stable(feature = "never_type", since = "1.26.0")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 40b88ded27d..2456b5b6654 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1579,14 +1579,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[stable(feature = "never_type", since = "1.25.0")] +#[stable(feature = "never_type", since = "1.26.0")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[stable(feature = "never_type", since = "1.25.0")] +#[stable(feature = "never_type", since = "1.26.0")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 1743dfbfb7b..f8dbe193fed 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -234,7 +234,7 @@ impl<'a> From> for Box { } } -#[stable(feature = "never_type", since = "1.25.0")] +#[stable(feature = "never_type", since = "1.26.0")] impl Error for ! { fn description(&self) -> &str { *self } } -- cgit 1.4.1-3-g733a5 From 92bfcd2b192e59d12d64acf6f46c1897a3273b3e Mon Sep 17 00:00:00 2001 From: snf Date: Thu, 8 Mar 2018 14:36:43 +0000 Subject: implementing fallible allocation API (try_reserve) for Vec, String and HashMap --- src/liballoc/allocator.rs | 18 +++ src/liballoc/lib.rs | 1 + src/liballoc/raw_vec.rs | 102 ++++++++------ src/liballoc/string.rs | 74 ++++++++++ src/liballoc/tests/lib.rs | 1 + src/liballoc/tests/string.rs | 163 ++++++++++++++++++++++ src/liballoc/tests/vec.rs | 209 +++++++++++++++++++++++++++- src/liballoc/tests/vec_deque.rs | 208 +++++++++++++++++++++++++++ src/liballoc/vec.rs | 78 +++++++++++ src/liballoc/vec_deque.rs | 92 ++++++++++++ src/libstd/collections/hash/map.rs | 96 +++++++++++-- src/libstd/collections/hash/table.rs | 57 +++++--- src/libstd/collections/mod.rs | 3 + src/libstd/lib.rs | 1 + src/test/ui/feature-gate-try_reserve.rs | 14 ++ src/test/ui/feature-gate-try_reserve.stderr | 11 ++ 16 files changed, 1056 insertions(+), 72 deletions(-) create mode 100644 src/test/ui/feature-gate-try_reserve.rs create mode 100644 src/test/ui/feature-gate-try_reserve.stderr (limited to 'src/libstd') diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index 55e8c0b430f..fdc4efc66b9 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -373,6 +373,24 @@ impl fmt::Display for CannotReallocInPlace { } } +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr(AllocErr), +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + fn from(err: AllocErr) -> Self { + CollectionAllocErr::AllocErr(err) + } +} + /// An implementation of `Alloc` can allocate, reallocate, and /// deallocate arbitrary blocks of data described via `Layout`. /// diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3f306784558..b93e128d508 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -117,6 +117,7 @@ #![feature(staged_api)] #![feature(str_internals)] #![feature(trusted_len)] +#![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unsize)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 621e1906961..229ae54d747 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -15,6 +15,8 @@ use core::ptr::{self, Unique}; use core::slice; use heap::{Alloc, Layout, Heap}; use super::boxed::Box; +use super::allocator::CollectionAllocErr; +use super::allocator::CollectionAllocErr::*; /// A low-level utility for more ergonomically allocating, reallocating, and deallocating /// a buffer of memory on the heap without having to worry about all the corner cases @@ -84,7 +86,7 @@ impl RawVec { let elem_size = mem::size_of::(); let alloc_size = cap.checked_mul(elem_size).expect("capacity overflow"); - alloc_guard(alloc_size); + alloc_guard(alloc_size).expect("capacity overflow"); // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { @@ -308,7 +310,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; let new_layout = Layout::from_size_align_unchecked(new_size, cur.align()); - alloc_guard(new_size); + alloc_guard(new_size).expect("capacity overflow"); let ptr_res = self.a.realloc(self.ptr.as_ptr() as *mut u8, cur, new_layout); @@ -367,7 +369,7 @@ impl RawVec { // overflow and the alignment is sufficiently small. let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; - alloc_guard(new_size); + alloc_guard(new_size).expect("capacity overflow"); let ptr = self.ptr() as *mut _; let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); match self.a.grow_in_place(ptr, old_layout, new_layout) { @@ -403,7 +405,9 @@ impl RawVec { /// # Aborts /// /// Aborts on OOM - pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { + pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) + -> Result<(), CollectionAllocErr> { + unsafe { // NOTE: we don't early branch on ZSTs here because we want this // to actually catch "asking for more than usize::MAX" in that case. @@ -413,16 +417,15 @@ impl RawVec { // Don't actually need any more capacity. // Wrapping in case they gave a bad `used_cap`. if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { - return; + return Ok(()); } // Nothing we can really do about these checks :( - let new_cap = used_cap.checked_add(needed_extra_cap).expect("capacity overflow"); - let new_layout = match Layout::array::(new_cap) { - Some(layout) => layout, - None => panic!("capacity overflow"), - }; - alloc_guard(new_layout.size()); + let new_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::(new_cap).ok_or(CapacityOverflow)?; + + alloc_guard(new_layout.size())?; + let res = match self.current_layout() { Some(layout) => { let old_ptr = self.ptr.as_ptr() as *mut u8; @@ -430,26 +433,34 @@ impl RawVec { } None => self.a.alloc(new_layout), }; - let uniq = match res { - Ok(ptr) => Unique::new_unchecked(ptr as *mut T), - Err(e) => self.a.oom(e), - }; - self.ptr = uniq; + + self.ptr = Unique::new_unchecked(res? as *mut T); self.cap = new_cap; + + Ok(()) } } + pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { + match self.try_reserve_exact(used_cap, needed_extra_cap) { + Err(CapacityOverflow) => panic!("capacity overflow"), + Err(AllocErr(e)) => self.a.oom(e), + Ok(()) => { /* yay */ } + } + } + /// Calculates the buffer's new size given that it'll hold `used_cap + /// needed_extra_cap` elements. This logic is used in amortized reserve methods. /// Returns `(new_capacity, new_alloc_size)`. - fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize) -> usize { + fn amortized_new_size(&self, used_cap: usize, needed_extra_cap: usize) + -> Result { + // Nothing we can really do about these checks :( - let required_cap = used_cap.checked_add(needed_extra_cap) - .expect("capacity overflow"); + let required_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?; // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`. let double_cap = self.cap * 2; // `double_cap` guarantees exponential growth. - cmp::max(double_cap, required_cap) + Ok(cmp::max(double_cap, required_cap)) } /// Ensures that the buffer contains at least enough space to hold @@ -504,8 +515,9 @@ impl RawVec { /// # vector.push_all(&[1, 3, 5, 7, 9]); /// # } /// ``` - pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { - unsafe { + pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize) + -> Result<(), CollectionAllocErr> { + unsafe { // NOTE: we don't early branch on ZSTs here because we want this // to actually catch "asking for more than usize::MAX" in that case. // If we make it past the first branch then we are guaranteed to @@ -514,17 +526,15 @@ impl RawVec { // Don't actually need any more capacity. // Wrapping in case they give a bad `used_cap` if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { - return; + return Ok(()); } - let new_cap = self.amortized_new_size(used_cap, needed_extra_cap); + let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; + let new_layout = Layout::array::(new_cap).ok_or(CapacityOverflow)?; + + // FIXME: may crash and burn on over-reserve + alloc_guard(new_layout.size())?; - let new_layout = match Layout::array::(new_cap) { - Some(layout) => layout, - None => panic!("capacity overflow"), - }; - // FIXME: may crash and burn on over-reserve - alloc_guard(new_layout.size()); let res = match self.current_layout() { Some(layout) => { let old_ptr = self.ptr.as_ptr() as *mut u8; @@ -532,15 +542,22 @@ impl RawVec { } None => self.a.alloc(new_layout), }; - let uniq = match res { - Ok(ptr) => Unique::new_unchecked(ptr as *mut T), - Err(e) => self.a.oom(e), - }; - self.ptr = uniq; + + self.ptr = Unique::new_unchecked(res? as *mut T); self.cap = new_cap; + + Ok(()) } } + /// The same as try_reserve, but errors are lowered to a call to oom(). + pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { + match self.try_reserve(used_cap, needed_extra_cap) { + Err(CapacityOverflow) => panic!("capacity overflow"), + Err(AllocErr(e)) => self.a.oom(e), + Ok(()) => { /* yay */ } + } + } /// Attempts to ensure that the buffer contains at least enough space to hold /// `used_cap + needed_extra_cap` elements. If it doesn't already have /// enough capacity, will reallocate in place enough space plus comfortable slack @@ -576,7 +593,8 @@ impl RawVec { return false; } - let new_cap = self.amortized_new_size(used_cap, needed_extra_cap); + let new_cap = self.amortized_new_size(used_cap, needed_extra_cap) + .expect("capacity overflow"); // Here, `cap < used_cap + needed_extra_cap <= new_cap` // (regardless of whether `self.cap - used_cap` wrapped). @@ -585,7 +603,7 @@ impl RawVec { let ptr = self.ptr() as *mut _; let new_layout = Layout::new::().repeat(new_cap).unwrap().0; // FIXME: may crash and burn on over-reserve - alloc_guard(new_layout.size()); + alloc_guard(new_layout.size()).expect("capacity overflow"); match self.a.grow_in_place(ptr, old_layout, new_layout) { Ok(_) => { self.cap = new_cap; @@ -709,14 +727,14 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec { // all 4GB in user-space. e.g. PAE or x32 #[inline] -fn alloc_guard(alloc_size: usize) { - if mem::size_of::() < 8 { - assert!(alloc_size <= ::core::isize::MAX as usize, - "capacity overflow"); +fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { + if mem::size_of::() < 8 && alloc_size > ::core::isize::MAX as usize { + Err(CapacityOverflow) + } else { + Ok(()) } } - #[cfg(test)] mod tests { use super::*; diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 370fb6b4e89..dcc81417346 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -71,6 +71,7 @@ use Bound::{Excluded, Included, Unbounded}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; +use super::allocator::CollectionAllocErr; /// A UTF-8 encoded, growable string. /// @@ -920,6 +921,79 @@ impl String { self.vec.reserve_exact(additional) } + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `String`. The collection may reserve more space to avoid + /// frequent reallocations. After calling `reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// + /// fn process_data(data: &str) -> Result { + /// let mut output = String::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.push_str(data); + /// + /// Ok(output) + /// } + /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.vec.try_reserve(additional) + } + + /// Tries to reserves the minimum capacity for exactly `additional` more elements to + /// be inserted in the given `String`. After calling `reserve_exact`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer `reserve` if future insertions are expected. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// + /// fn process_data(data: &str) -> Result { + /// let mut output = String::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.push_str(data); + /// + /// Ok(output) + /// } + /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.vec.try_reserve_exact(additional) + } + /// Shrinks the capacity of this `String` to match its length. /// /// # Examples diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 168dbb2ce9b..285cba0270c 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -26,6 +26,7 @@ #![feature(splice)] #![feature(str_escape)] #![feature(string_retain)] +#![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(exact_chunks)] diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index ef6f5e10a72..d1e746ea43b 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -9,6 +9,9 @@ // except according to those terms. use std::borrow::Cow; +use std::collections::CollectionAllocErr::*; +use std::mem::size_of; +use std::{usize, isize}; pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { fn into_cow(self) -> Cow<'a, B>; @@ -504,3 +507,163 @@ fn test_into_boxed_str() { let ys = xs.into_boxed_str(); assert_eq!(&*ys, "hello my name is bob"); } + +#[test] +fn test_reserve_exact() { + // This is all the same as test_reserve + + let mut s = String::new(); + assert_eq!(s.capacity(), 0); + + s.reserve_exact(2); + assert!(s.capacity() >= 2); + + for _i in 0..16 { + s.push('0'); + } + + assert!(s.capacity() >= 16); + s.reserve_exact(16); + assert!(s.capacity() >= 32); + + s.push('0'); + + s.reserve_exact(16); + assert!(s.capacity() >= 33) +} + +#[test] +fn test_try_reserve() { + + // These are the interesting cases: + // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) + // * > isize::MAX should always fail + // * On 16/32-bit should CapacityOverflow + // * On 64-bit should OOM + // * overflow may trigger when adding `len` to `cap` (in number of elements) + // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + // On 16/32-bit, we check that allocations don't exceed isize::MAX, + // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. + // Any platform that succeeds for these requests is technically broken with + // ptr::offset because LLVM is the worst. + let guards_against_isize = size_of::() < 8; + + { + // Note: basic stuff is checked by test_reserve + let mut empty_string: String = String::new(); + + // Check isize::MAX doesn't count as an overflow + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + // Play it again, frank! (just to be sure) + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + if guards_against_isize { + // Check isize::MAX + 1 does count as overflow + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an overflow!") } + + // Check usize::MAX does count as overflow + if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } else { + // Check isize::MAX + 1 is an OOM + if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + + // Check usize::MAX is an OOM + if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an OOM!") } + } + } + + + { + // Same basic idea, but with non-zero len + let mut ten_bytes: String = String::from("0123456789"); + + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + // Should always overflow in the add-to-len + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + +} + +#[test] +fn test_try_reserve_exact() { + + // This is exactly the same as test_try_reserve with the method changed. + // See that test for comments. + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + let guards_against_isize = size_of::() < 8; + + { + let mut empty_string: String = String::new(); + + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + if guards_against_isize { + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an overflow!") } + + if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } else { + if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + + if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an OOM!") } + } + } + + + { + let mut ten_bytes: String = String::from("0123456789"); + + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + +} diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 9cfde5dcc73..3c17a401bba 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -10,8 +10,9 @@ use std::borrow::Cow; use std::mem::size_of; -use std::panic; +use std::{usize, isize, panic}; use std::vec::{Drain, IntoIter}; +use std::collections::CollectionAllocErr::*; struct DropCounter<'a> { count: &'a mut u32, @@ -965,3 +966,209 @@ fn drain_filter_complex() { assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]); } } + +#[test] +fn test_reserve_exact() { + // This is all the same as test_reserve + + let mut v = Vec::new(); + assert_eq!(v.capacity(), 0); + + v.reserve_exact(2); + assert!(v.capacity() >= 2); + + for i in 0..16 { + v.push(i); + } + + assert!(v.capacity() >= 16); + v.reserve_exact(16); + assert!(v.capacity() >= 32); + + v.push(16); + + v.reserve_exact(16); + assert!(v.capacity() >= 33) +} + +#[test] +fn test_try_reserve() { + + // These are the interesting cases: + // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) + // * > isize::MAX should always fail + // * On 16/32-bit should CapacityOverflow + // * On 64-bit should OOM + // * overflow may trigger when adding `len` to `cap` (in number of elements) + // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + // On 16/32-bit, we check that allocations don't exceed isize::MAX, + // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. + // Any platform that succeeds for these requests is technically broken with + // ptr::offset because LLVM is the worst. + let guards_against_isize = size_of::() < 8; + + { + // Note: basic stuff is checked by test_reserve + let mut empty_bytes: Vec = Vec::new(); + + // Check isize::MAX doesn't count as an overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + // Play it again, frank! (just to be sure) + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + if guards_against_isize { + // Check isize::MAX + 1 does count as overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an overflow!") } + + // Check usize::MAX does count as overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } else { + // Check isize::MAX + 1 is an OOM + if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + + // Check usize::MAX is an OOM + if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an OOM!") } + } + } + + + { + // Same basic idea, but with non-zero len + let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + // Should always overflow in the add-to-len + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + + + { + // Same basic idea, but with interesting type size + let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + // Should fail in the mul-by-size + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + } + +} + +#[test] +fn test_try_reserve_exact() { + + // This is exactly the same as test_try_reserve with the method changed. + // See that test for comments. + + const MAX_CAP: usize = isize::MAX as usize; + const MAX_USIZE: usize = usize::MAX; + + let guards_against_isize = size_of::() < 8; + + { + let mut empty_bytes: Vec = Vec::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + if guards_against_isize { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an overflow!") } + + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } else { + if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + + if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an OOM!") } + } + } + + + { + let mut ten_bytes: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + + + { + let mut ten_u32s: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + +} diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index f2935c05d4f..fc1a0b624a5 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -11,6 +11,9 @@ use std::collections::VecDeque; use std::fmt::Debug; use std::collections::vec_deque::{Drain}; +use std::collections::CollectionAllocErr::*; +use std::mem::size_of; +use std::{usize, isize}; use self::Taggy::*; use self::Taggypar::*; @@ -1022,3 +1025,208 @@ fn test_placement_in() { } assert_eq!(buf, [5,4,3,1,2,6]); } + +#[test] +fn test_reserve_exact_2() { + // This is all the same as test_reserve + + let mut v = VecDeque::new(); + + v.reserve_exact(2); + assert!(v.capacity() >= 2); + + for i in 0..16 { + v.push_back(i); + } + + assert!(v.capacity() >= 16); + v.reserve_exact(16); + assert!(v.capacity() >= 32); + + v.push_back(16); + + v.reserve_exact(16); + assert!(v.capacity() >= 48) +} + +#[test] +fn test_try_reserve() { + + // These are the interesting cases: + // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM) + // * > isize::MAX should always fail + // * On 16/32-bit should CapacityOverflow + // * On 64-bit should OOM + // * overflow may trigger when adding `len` to `cap` (in number of elements) + // * overflow may trigger when multiplying `new_cap` by size_of:: (to get bytes) + + const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; + const MAX_USIZE: usize = usize::MAX; + + // On 16/32-bit, we check that allocations don't exceed isize::MAX, + // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. + // Any platform that succeeds for these requests is technically broken with + // ptr::offset because LLVM is the worst. + let guards_against_isize = size_of::() < 8; + + { + // Note: basic stuff is checked by test_reserve + let mut empty_bytes: VecDeque = VecDeque::new(); + + // Check isize::MAX doesn't count as an overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + // Play it again, frank! (just to be sure) + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + if guards_against_isize { + // Check isize::MAX + 1 does count as overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an overflow!") } + + // Check usize::MAX does count as overflow + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } else { + // Check isize::MAX is an OOM + // VecDeque starts with capacity 7, always adds 1 to the capacity + // and also rounds the number to next power of 2 so this is the + // furthest we can go without triggering CapacityOverflow + if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + } + + + { + // Same basic idea, but with non-zero len + let mut ten_bytes: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + // Should always overflow in the add-to-len + if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + + + { + // Same basic idea, but with interesting type size + let mut ten_u32s: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + // Should fail in the mul-by-size + if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + } + +} + +#[test] +fn test_try_reserve_exact() { + + // This is exactly the same as test_try_reserve with the method changed. + // See that test for comments. + + const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; + const MAX_USIZE: usize = usize::MAX; + + let guards_against_isize = size_of::() < 8; + + { + let mut empty_bytes: VecDeque = VecDeque::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + + if guards_against_isize { + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + } else { panic!("isize::MAX + 1 should trigger an overflow!") } + + if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } else { + // Check isize::MAX is an OOM + // VecDeque starts with capacity 7, always adds 1 to the capacity + // and also rounds the number to next power of 2 so this is the + // furthest we can go without triggering CapacityOverflow + if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + } + + + { + let mut ten_bytes: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + + + { + let mut ten_u32s: VecDeque = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); + + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 10) { + panic!("isize::MAX shouldn't trigger an overflow!"); + } + if guards_against_isize { + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an overflow!"); } + } else { + if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { + } else { panic!("usize::MAX should trigger an overflow!") } + } + +} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 1bb2bed463b..953f95876be 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -86,6 +86,7 @@ use borrow::Cow; use boxed::Box; use raw_vec::RawVec; use super::range::RangeArgument; +use super::allocator::CollectionAllocErr; use Bound::{Excluded, Included, Unbounded}; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. @@ -489,6 +490,83 @@ impl Vec { self.buf.reserve_exact(self.len, additional); } + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `Vec`. The collection may reserve more space to avoid + /// frequent reallocations. After calling `reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// + /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// let mut output = Vec::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.buf.try_reserve(self.len, additional) + } + + /// Tries to reserves the minimum capacity for exactly `additional` more elements to + /// be inserted in the given `Vec`. After calling `reserve_exact`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer `reserve` if future insertions are expected. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// + /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// let mut output = Vec::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.buf.try_reserve_exact(self.len, additional) + } + /// Shrinks the capacity of the vector as much as possible. /// /// It will drop down as close as possible to the length but the allocator diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs index 68add3cbd51..0658777f0a0 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -31,6 +31,7 @@ use core::cmp; use raw_vec::RawVec; +use super::allocator::CollectionAllocErr; use super::range::RangeArgument; use Bound::{Excluded, Included, Unbounded}; use super::vec::Vec; @@ -566,6 +567,97 @@ impl VecDeque { } } + /// Tries to reserves the minimum capacity for exactly `additional` more elements to + /// be inserted in the given `VecDeque`. After calling `reserve_exact`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer `reserve` if future insertions are expected. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// use std::collections::VecDeque; + /// + /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// let mut output = VecDeque::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve_exact(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + self.try_reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `VecDeque`. The collection may reserve more space to avoid + /// frequent reallocations. After calling `reserve`, capacity will be + /// greater than or equal to `self.len() + additional`. Does nothing if + /// capacity is already sufficient. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::CollectionAllocErr; + /// use std::collections::VecDeque; + /// + /// fn process_data(data: &[u32]) -> Result, CollectionAllocErr> { + /// let mut output = VecDeque::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// output.try_reserve(data.len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// output.extend(data.iter().map(|&val| { + /// val * 2 + 5 // very complicated + /// })); + /// + /// Ok(output) + /// } + /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + let old_cap = self.cap(); + let used_cap = self.len() + 1; + let new_cap = used_cap.checked_add(additional) + .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) + .ok_or(CollectionAllocErr::CapacityOverflow)?; + + if new_cap > old_cap { + self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?; + unsafe { + self.handle_cap_increase(old_cap); + } + } + Ok(()) + } + /// Shrinks the capacity of the `VecDeque` as much as possible. /// /// It will drop down as close as possible to the length but the allocator may still inform the diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 6f4528a0e24..b18b38ec302 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,6 +11,8 @@ use self::Entry::*; use self::VacantEntryState::*; +use alloc::heap::{Heap, Alloc}; +use alloc::allocator::CollectionAllocErr; use cell::Cell; use borrow::Borrow; use cmp::max; @@ -42,21 +44,28 @@ impl DefaultResizePolicy { /// provide that capacity, accounting for maximum loading. The raw capacity /// is always zero or a power of two. #[inline] - fn raw_capacity(&self, len: usize) -> usize { + fn try_raw_capacity(&self, len: usize) -> Result { if len == 0 { - 0 + Ok(0) } else { // 1. Account for loading: `raw_capacity >= len * 1.1`. // 2. Ensure it is a power of two. // 3. Ensure it is at least the minimum size. - let mut raw_cap = len * 11 / 10; - assert!(raw_cap >= len, "raw_cap overflow"); - raw_cap = raw_cap.checked_next_power_of_two().expect("raw_capacity overflow"); + let mut raw_cap = len.checked_mul(11) + .map(|l| l / 10) + .and_then(|l| l.checked_next_power_of_two()) + .ok_or(CollectionAllocErr::CapacityOverflow)?; + raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap); - raw_cap + Ok(raw_cap) } } + #[inline] + fn raw_capacity(&self, len: usize) -> usize { + self.try_raw_capacity(len).expect("raw_capacity overflow") + } + /// The capacity of the given raw capacity. #[inline] fn capacity(&self, raw_cap: usize) -> usize { @@ -775,17 +784,45 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { + match self.try_reserve(additional) { + Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), + Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Ok(()) => { /* yay */ } + } + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(try_reserve)] + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { let remaining = self.capacity() - self.len(); // this can't overflow if remaining < additional { - let min_cap = self.len().checked_add(additional).expect("reserve overflow"); - let raw_cap = self.resize_policy.raw_capacity(min_cap); - self.resize(raw_cap); + let min_cap = self.len().checked_add(additional) + .ok_or(CollectionAllocErr::CapacityOverflow)?; + let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?; + self.try_resize(raw_cap)?; } else if self.table.tag() && remaining <= self.len() { // Probe sequence is too long and table is half full, // resize early to reduce probing length. let new_capacity = self.table.capacity() * 2; - self.resize(new_capacity); + self.try_resize(new_capacity)?; } + Ok(()) } /// Resizes the internal vectors to a new capacity. It's your @@ -795,15 +832,15 @@ impl HashMap /// 2) Ensure `new_raw_cap` is a power of two or zero. #[inline(never)] #[cold] - fn resize(&mut self, new_raw_cap: usize) { + fn try_resize(&mut self, new_raw_cap: usize) -> Result<(), CollectionAllocErr> { assert!(self.table.size() <= new_raw_cap); assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); - let mut old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); + let mut old_table = replace(&mut self.table, RawTable::try_new(new_raw_cap)?); let old_size = old_table.size(); if old_table.size() == 0 { - return; + return Ok(()); } let mut bucket = Bucket::head_bucket(&mut old_table); @@ -838,6 +875,7 @@ impl HashMap } assert_eq!(self.table.size(), old_size); + Ok(()) } /// Shrinks the capacity of the map as much as possible. It will drop @@ -2717,6 +2755,9 @@ mod test_map { use cell::RefCell; use rand::{thread_rng, Rng}; use panic; + use realstd::collections::CollectionAllocErr::*; + use realstd::mem::size_of; + use realstd::usize; #[test] fn test_zero_capacities() { @@ -3651,4 +3692,33 @@ mod test_map { let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { hm.entry(0) <- makepanic(); })); assert_eq!(hm.len(), 0); } + + #[test] + fn test_try_reserve() { + + let mut empty_bytes: HashMap = HashMap::new(); + + const MAX_USIZE: usize = usize::MAX; + + // HashMap and RawTables use complicated size calculations + // hashes_size is sizeof(HashUint) * capacity; + // pairs_size is sizeof((K. V)) * capacity; + // alignment_hashes_size is 8 + // alignment_pairs size is 4 + let size_of_multiplier = (size_of::() + size_of::<(u8, u8)>()).next_power_of_two(); + // The following formula is used to calculate the new capacity + let max_no_ovf = ((MAX_USIZE / 11) * 10) / size_of_multiplier - 1; + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + } else { panic!("usize::MAX should trigger an overflow!"); } + + if size_of::() < 8 { + if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { + } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } + } else { + if let Err(AllocErr(_)) = empty_bytes.try_reserve(max_no_ovf) { + } else { panic!("isize::MAX + 1 should trigger an OOM!") } + } + } + } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 73bd5747c10..8e78dc546c6 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -17,6 +17,7 @@ use mem::{align_of, size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, NonNull}; +use alloc::allocator::CollectionAllocErr; use self::BucketState::*; @@ -741,14 +742,15 @@ fn test_offset_calculation() { impl RawTable { /// Does not initialize the buckets. The caller should ensure they, /// at the very least, set every hash to EMPTY_BUCKET. - unsafe fn new_uninitialized(capacity: usize) -> RawTable { + /// Returns an error if it cannot allocate or capacity overflows. + unsafe fn try_new_uninitialized(capacity: usize) -> Result, CollectionAllocErr> { if capacity == 0 { - return RawTable { + return Ok(RawTable { size: 0, capacity_mask: capacity.wrapping_sub(1), hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), marker: marker::PhantomData, - }; + }); } // No need for `checked_mul` before a more restrictive check performed @@ -768,25 +770,38 @@ impl RawTable { align_of::(), pairs_size, align_of::<(K, V)>()); - assert!(!oflo, "capacity overflow"); + if oflo { + return Err(CollectionAllocErr::CapacityOverflow); + } // One check for overflow that covers calculation and rounding of size. - let size_of_bucket = size_of::().checked_add(size_of::<(K, V)>()).unwrap(); - assert!(size >= - capacity.checked_mul(size_of_bucket) - .expect("capacity overflow"), - "capacity overflow"); + let size_of_bucket = size_of::().checked_add(size_of::<(K, V)>()) + .ok_or(CollectionAllocErr::CapacityOverflow)?; + let capacity_mul_size_of_bucket = capacity.checked_mul(size_of_bucket); + if capacity_mul_size_of_bucket.is_none() || size < capacity_mul_size_of_bucket.unwrap() { + return Err(CollectionAllocErr::CapacityOverflow); + } - let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap()) - .unwrap_or_else(|e| Heap.oom(e)); + let buffer = Heap.alloc(Layout::from_size_align(size, alignment) + .ok_or(CollectionAllocErr::CapacityOverflow)?)?; let hashes = buffer as *mut HashUint; - RawTable { + Ok(RawTable { capacity_mask: capacity.wrapping_sub(1), size: 0, hashes: TaggedHashUintPtr::new(hashes), marker: marker::PhantomData, + }) + } + + /// Does not initialize the buckets. The caller should ensure they, + /// at the very least, set every hash to EMPTY_BUCKET. + unsafe fn new_uninitialized(capacity: usize) -> RawTable { + match Self::try_new_uninitialized(capacity) { + Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), + Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Ok(table) => { table } } } @@ -809,13 +824,23 @@ impl RawTable { } } + /// Tries to create a new raw table from a given capacity. If it cannot allocate, + /// it returns with AllocErr. + pub fn try_new(capacity: usize) -> Result, CollectionAllocErr> { + unsafe { + let ret = RawTable::try_new_uninitialized(capacity)?; + ptr::write_bytes(ret.hashes.ptr(), 0, capacity); + Ok(ret) + } + } + /// Creates a new raw table from a given capacity. All buckets are /// initially empty. pub fn new(capacity: usize) -> RawTable { - unsafe { - let ret = RawTable::new_uninitialized(capacity); - ptr::write_bytes(ret.hashes.ptr(), 0, capacity); - ret + match Self::try_new(capacity) { + Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), + Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Ok(table) => { table } } } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index e9a150f34a5..be88f4e268a 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -438,6 +438,9 @@ pub use self::hash_set::HashSet; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::range; +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub use alloc::allocator::CollectionAllocErr; + mod hash; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index da15941374d..ccc5373acc7 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -314,6 +314,7 @@ #![feature(thread_local)] #![feature(toowned_clone_into)] #![feature(try_from)] +#![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(untagged_unions)] diff --git a/src/test/ui/feature-gate-try_reserve.rs b/src/test/ui/feature-gate-try_reserve.rs new file mode 100644 index 00000000000..9322dbd272f --- /dev/null +++ b/src/test/ui/feature-gate-try_reserve.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let v = Vec::new(); + v.try_reserve(10); //~ ERROR: use of unstable library feature 'try_reserve' +} diff --git a/src/test/ui/feature-gate-try_reserve.stderr b/src/test/ui/feature-gate-try_reserve.stderr new file mode 100644 index 00000000000..b1fef61dd24 --- /dev/null +++ b/src/test/ui/feature-gate-try_reserve.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'try_reserve': new API (see issue #48043) + --> $DIR/feature-gate-try_reserve.rs:13:7 + | +LL | v.try_reserve(10); //~ ERROR: use of unstable library feature 'try_reserve' + | ^^^^^^^^^^^ + | + = help: add #![feature(try_reserve)] to the crate attributes to enable + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0658" -- cgit 1.4.1-3-g733a5 From b08b5ae0ec22e67d1cab7495865a0b34d4e6c5a2 Mon Sep 17 00:00:00 2001 From: snf Date: Tue, 13 Mar 2018 03:41:45 -0700 Subject: try_reserve: disabling tests for asmjs, blocked by #48968 --- src/liballoc/tests/string.rs | 5 +++++ src/liballoc/tests/vec.rs | 7 ++++++- src/liballoc/tests/vec_deque.rs | 8 +++++++- src/libstd/collections/hash/map.rs | 4 ++++ 4 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index d1e746ea43b..9bbba4e22b0 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -9,8 +9,11 @@ // except according to those terms. use std::borrow::Cow; +#[cfg(not(target_arch = "asmjs"))] use std::collections::CollectionAllocErr::*; +#[cfg(not(target_arch = "asmjs"))] use std::mem::size_of; +#[cfg(not(target_arch = "asmjs"))] use std::{usize, isize}; pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { @@ -532,6 +535,7 @@ fn test_reserve_exact() { assert!(s.capacity() >= 33) } +#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { @@ -609,6 +613,7 @@ fn test_try_reserve() { } +#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve_exact() { diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 3c17a401bba..85e11d8b8ee 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -10,8 +10,11 @@ use std::borrow::Cow; use std::mem::size_of; -use std::{usize, isize, panic}; +use std::{usize, panic}; +#[cfg(not(target_arch = "asmjs"))] +use std::isize; use std::vec::{Drain, IntoIter}; +#[cfg(not(target_arch = "asmjs"))] use std::collections::CollectionAllocErr::*; struct DropCounter<'a> { @@ -991,6 +994,7 @@ fn test_reserve_exact() { assert!(v.capacity() >= 33) } +#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { @@ -1093,6 +1097,7 @@ fn test_try_reserve() { } +#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve_exact() { diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index fc1a0b624a5..9fd38ed6f6f 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -11,9 +11,13 @@ use std::collections::VecDeque; use std::fmt::Debug; use std::collections::vec_deque::{Drain}; +#[cfg(not(target_arch = "asmjs"))] use std::collections::CollectionAllocErr::*; +#[cfg(not(target_arch = "asmjs"))] use std::mem::size_of; -use std::{usize, isize}; +use std::isize; +#[cfg(not(target_arch = "asmjs"))] +use std::usize; use self::Taggy::*; use self::Taggypar::*; @@ -1049,6 +1053,7 @@ fn test_reserve_exact_2() { assert!(v.capacity() >= 48) } +#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { @@ -1150,6 +1155,7 @@ fn test_try_reserve() { } +#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve_exact() { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index b18b38ec302..5f5dec2dd4f 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2755,8 +2755,11 @@ mod test_map { use cell::RefCell; use rand::{thread_rng, Rng}; use panic; + #[cfg(not(target_arch = "asmjs"))] use realstd::collections::CollectionAllocErr::*; + #[cfg(not(target_arch = "asmjs"))] use realstd::mem::size_of; + #[cfg(not(target_arch = "asmjs"))] use realstd::usize; #[test] @@ -3693,6 +3696,7 @@ mod test_map { assert_eq!(hm.len(), 0); } + #[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { -- cgit 1.4.1-3-g733a5 From 4647156985404f07dc2e61eed6f2e24770b339a9 Mon Sep 17 00:00:00 2001 From: Andrew Cann Date: Thu, 15 Mar 2018 12:35:56 +0800 Subject: replace `convert::Infallible` with `!` --- src/libcore/convert.rs | 21 +-------------------- src/libcore/num/mod.rs | 18 +++++------------- src/libstd/error.rs | 9 --------- 3 files changed, 6 insertions(+), 42 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index d3a83dc795c..a45f1ceab5a 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -48,25 +48,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fmt; - -/// A type used as the error type for implementations of fallible conversion -/// traits in cases where conversions cannot actually fail. -/// -/// Because `Infallible` has no variants, a value of this type can never exist. -/// It is used only to satisfy trait signatures that expect an error type, and -/// signals to both the compiler and the user that the error case is impossible. -#[unstable(feature = "try_from", issue = "33417")] -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Infallible {} - -#[unstable(feature = "try_from", issue = "33417")] -impl fmt::Display for Infallible { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - match *self { - } - } -} /// A cheap reference-to-reference conversion. Used to convert a value to a /// reference value within generic code. /// @@ -438,7 +419,7 @@ impl TryInto for T where U: TryFrom // with an uninhabited error type. #[unstable(feature = "try_from", issue = "33417")] impl TryFrom for T where T: From { - type Error = Infallible; + type Error = !; fn try_from(value: U) -> Result { Ok(T::from(value)) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 09ab7060d37..faeb87cf944 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -12,7 +12,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use convert::{Infallible, TryFrom}; +use convert::TryFrom; use fmt; use intrinsics; use ops; @@ -3595,20 +3595,12 @@ impl fmt::Display for TryFromIntError { } } -#[unstable(feature = "try_from", issue = "33417")] -impl From for TryFromIntError { - fn from(infallible: Infallible) -> TryFromIntError { - match infallible { - } - } -} - // no possible bounds violation macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { - type Error = Infallible; + type Error = !; #[inline] fn try_from(value: $source) -> Result { @@ -3719,7 +3711,7 @@ try_from_lower_bounded!(isize, usize); #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; + use convert::TryFrom; try_from_upper_bounded!(usize, u8); try_from_unbounded!(usize, u16, u32, u64, u128); @@ -3745,7 +3737,7 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "32")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; + use convert::TryFrom; try_from_upper_bounded!(usize, u8, u16); try_from_unbounded!(usize, u32, u64, u128); @@ -3771,7 +3763,7 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "64")] mod ptr_try_from_impls { use super::TryFromIntError; - use convert::{Infallible, TryFrom}; + use convert::TryFrom; try_from_upper_bounded!(usize, u8, u16, u32); try_from_unbounded!(usize, u64, u128); diff --git a/src/libstd/error.rs b/src/libstd/error.rs index f8dbe193fed..79bb6af168f 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -56,7 +56,6 @@ use any::TypeId; use borrow::Cow; use cell; use char; -use convert; use core::array; use fmt::{self, Debug, Display}; use mem::transmute; @@ -371,14 +370,6 @@ impl Error for char::ParseCharError { } } -#[unstable(feature = "try_from", issue = "33417")] -impl Error for convert::Infallible { - fn description(&self) -> &str { - match *self { - } - } -} - // copied from any.rs impl Error + 'static { /// Returns true if the boxed type is the same as `T` -- cgit 1.4.1-3-g733a5 From b5913f2e7695ad247078619bf4c6a6d3dc4dece5 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sun, 28 Jan 2018 03:09:36 +0800 Subject: Stabilize `inclusive_range` library feature. Stabilize std::ops::RangeInclusive and std::ops::RangeInclusiveTo. --- src/liballoc/lib.rs | 1 - src/liballoc/range.rs | 4 ++-- src/liballoc/string.rs | 8 ++++---- src/libcore/iter/range.rs | 12 ++++-------- src/libcore/ops/mod.rs | 2 +- src/libcore/ops/range.rs | 24 +++++++++--------------- src/libcore/slice/mod.rs | 4 ++-- src/libcore/str/mod.rs | 24 ++++++------------------ src/libcore/tests/lib.rs | 1 - src/librustc/lib.rs | 1 - src/librustc_mir/lib.rs | 1 - src/librustc_trans/lib.rs | 1 - src/libstd/lib.rs | 1 - src/test/compile-fail/range_inclusive_gate.rs | 21 --------------------- src/test/compile-fail/range_traits-1.rs | 2 -- src/test/compile-fail/range_traits-6.rs | 2 -- src/test/compile-fail/range_traits-7.rs | 2 +- src/test/parse-fail/range_inclusive.rs | 2 +- src/test/parse-fail/range_inclusive_dotdotdot.rs | 2 +- src/test/parse-fail/range_inclusive_gate.rs | 2 +- src/test/run-pass/range_inclusive.rs | 2 +- 21 files changed, 33 insertions(+), 86 deletions(-) delete mode 100644 src/test/compile-fail/range_inclusive_gate.rs (limited to 'src/libstd') diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3f306784558..cbfec554604 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -98,7 +98,6 @@ #![feature(fundamental)] #![feature(generic_param_attrs)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(iter_rfold)] #![feature(lang_items)] #![feature(needs_allocator)] diff --git a/src/liballoc/range.rs b/src/liballoc/range.rs index f862da0d61e..b03abc85180 100644 --- a/src/liballoc/range.rs +++ b/src/liballoc/range.rs @@ -103,7 +103,7 @@ impl RangeArgument for Range { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl RangeArgument for RangeInclusive { fn start(&self) -> Bound<&T> { Included(&self.start) @@ -113,7 +113,7 @@ impl RangeArgument for RangeInclusive { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl RangeArgument for RangeToInclusive { fn start(&self) -> Bound<&T> { Unbounded diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 370fb6b4e89..185fb61ae9e 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1876,7 +1876,7 @@ impl ops::Index for String { unsafe { str::from_utf8_unchecked(&self.vec) } } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for String { type Output = str; @@ -1885,7 +1885,7 @@ impl ops::Index> for String { Index::index(&**self, index) } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for String { type Output = str; @@ -1923,14 +1923,14 @@ impl ops::IndexMut for String { unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { IndexMut::index_mut(&mut **self, index) } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for String { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 9a3fd215dcf..8d1080bb876 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -186,9 +186,7 @@ macro_rules! range_exact_iter_impl { macro_rules! range_incl_exact_iter_impl { ($($t:ty)*) => ($( - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ExactSizeIterator for ops::RangeInclusive<$t> { } )*) } @@ -202,9 +200,7 @@ macro_rules! range_trusted_len_impl { macro_rules! range_incl_trusted_len_impl { ($($t:ty)*) => ($( - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] unsafe impl TrustedLen for ops::RangeInclusive<$t> { } )*) } @@ -328,7 +324,7 @@ impl FusedIterator for ops::RangeFrom {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for ops::RangeFrom {} -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl Iterator for ops::RangeInclusive { type Item = A; @@ -422,7 +418,7 @@ impl Iterator for ops::RangeInclusive { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 70ef4487334..234970a81fa 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -191,7 +191,7 @@ pub use self::index::{Index, IndexMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] pub use self::range::{RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 1d9c0f873b3..9bdd8094f61 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -283,7 +283,7 @@ impl> RangeTo { /// # Examples /// /// ``` -/// #![feature(inclusive_range,inclusive_range_syntax)] +/// #![feature(inclusive_range_syntax)] /// /// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); @@ -293,21 +293,17 @@ impl> RangeTo { /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { /// The lower bound of the range (inclusive). - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] pub start: Idx, /// The upper bound of the range (inclusive). - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] pub end: Idx, } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeInclusive { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{:?}..={:?}", self.start, self.end) @@ -385,7 +381,7 @@ impl> RangeInclusive { /// The `..=end` syntax is a `RangeToInclusive`: /// /// ``` -/// #![feature(inclusive_range,inclusive_range_syntax)] +/// #![feature(inclusive_range_syntax)] /// assert_eq!((..=5), std::ops::RangeToInclusive{ end: 5 }); /// ``` /// @@ -417,16 +413,14 @@ impl> RangeInclusive { /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html #[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeToInclusive { /// The upper bound of the range (inclusive) - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] pub end: Idx, } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl fmt::Debug for RangeToInclusive { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "..={:?}", self.end) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 19fe4dd36b6..0f1b7cb8fcc 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1039,7 +1039,7 @@ impl SliceIndex<[T]> for ops::RangeFull { } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; @@ -1080,7 +1080,7 @@ impl SliceIndex<[T]> for ops::RangeInclusive { } } -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e225c9522bc..9cf862bd936 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1779,9 +1779,7 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for str { type Output = str; @@ -1791,9 +1789,7 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::Index> for str { type Output = str; @@ -1803,18 +1799,14 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { index.index_mut(self) } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { @@ -1997,9 +1989,7 @@ mod traits { } } - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] @@ -2042,9 +2032,7 @@ mod traits { - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] + #[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5bd5bca19c4..8f01fbeb30e 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,7 +23,6 @@ #![feature(fmt_internals)] #![feature(iterator_step_by)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![feature(iterator_try_fold)] #![feature(iterator_flatten)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 51882385b2e..149ea96b636 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -54,7 +54,6 @@ #![feature(fs_read_write)] #![feature(i128)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] #![feature(match_default_bindings)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 5510e219780..31eb203eefe 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -29,7 +29,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(fs_read_write)] #![feature(i128_type)] #![feature(inclusive_range_syntax)] -#![feature(inclusive_range)] #![feature(macro_vis_matcher)] #![feature(match_default_bindings)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 39eb38658fe..a9334461825 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -26,7 +26,6 @@ #![allow(unused_attributes)] #![feature(i128_type)] #![feature(i128)] -#![feature(inclusive_range)] #![feature(inclusive_range_syntax)] #![feature(libc)] #![feature(quote)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index eea0e6b6752..c71a562b0d1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -271,7 +271,6 @@ #![feature(heap_api)] #![feature(i128)] #![feature(i128_type)] -#![feature(inclusive_range)] #![feature(int_error_internals)] #![feature(integer_atomics)] #![feature(into_cow)] diff --git a/src/test/compile-fail/range_inclusive_gate.rs b/src/test/compile-fail/range_inclusive_gate.rs deleted file mode 100644 index 5b063dc1137..00000000000 --- a/src/test/compile-fail/range_inclusive_gate.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Make sure that #![feature(inclusive_range)] is required. - -#![feature(inclusive_range_syntax)] -// #![feature(inclusive_range)] - -pub fn main() { - let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ..= { use std::intrinsics; 2 }; - //~^ ERROR use of unstable library feature 'inclusive_range' - //~| ERROR core_intrinsics - //~| ERROR core_intrinsics -} diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs index f1ea8b04e5a..7645dbb1a6d 100644 --- a/src/test/compile-fail/range_traits-1.rs +++ b/src/test/compile-fail/range_traits-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(inclusive_range)] - use std::ops::*; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] diff --git a/src/test/compile-fail/range_traits-6.rs b/src/test/compile-fail/range_traits-6.rs index 7c62711feae..f9510b5061c 100644 --- a/src/test/compile-fail/range_traits-6.rs +++ b/src/test/compile-fail/range_traits-6.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(inclusive_range)] - use std::ops::*; #[derive(Copy, Clone)] //~ ERROR Copy diff --git a/src/test/compile-fail/range_traits-7.rs b/src/test/compile-fail/range_traits-7.rs index b6fec773a77..871b55b85cf 100644 --- a/src/test/compile-fail/range_traits-7.rs +++ b/src/test/compile-fail/range_traits-7.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, inclusive_range)] +#![feature(rustc_attrs)] use std::ops::*; diff --git a/src/test/parse-fail/range_inclusive.rs b/src/test/parse-fail/range_inclusive.rs index cc32b9903b5..6c6caa1e649 100644 --- a/src/test/parse-fail/range_inclusive.rs +++ b/src/test/parse-fail/range_inclusive.rs @@ -10,7 +10,7 @@ // Make sure that inclusive ranges with no end point don't parse. -#![feature(inclusive_range_syntax, inclusive_range)] +#![feature(inclusive_range_syntax)] pub fn main() { for _ in 1..= {} //~ERROR inclusive range with no end diff --git a/src/test/parse-fail/range_inclusive_dotdotdot.rs b/src/test/parse-fail/range_inclusive_dotdotdot.rs index a4c36a2f0ba..8a24038638b 100644 --- a/src/test/parse-fail/range_inclusive_dotdotdot.rs +++ b/src/test/parse-fail/range_inclusive_dotdotdot.rs @@ -12,7 +12,7 @@ // Make sure that inclusive ranges with `...` syntax don't parse. -#![feature(inclusive_range_syntax, inclusive_range)] +#![feature(inclusive_range_syntax)] use std::ops::RangeToInclusive; diff --git a/src/test/parse-fail/range_inclusive_gate.rs b/src/test/parse-fail/range_inclusive_gate.rs index 6b6afc504e1..c8c84000e41 100644 --- a/src/test/parse-fail/range_inclusive_gate.rs +++ b/src/test/parse-fail/range_inclusive_gate.rs @@ -12,7 +12,7 @@ // Make sure that #![feature(inclusive_range_syntax)] is required. -// #![feature(inclusive_range_syntax, inclusive_range)] +// #![feature(inclusive_range_syntax)] macro_rules! m { () => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index 71e11804052..29947860ff6 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -10,7 +10,7 @@ // Test inclusive range syntax. -#![feature(inclusive_range_syntax, inclusive_range, iterator_step_by)] +#![feature(inclusive_range_syntax, iterator_step_by)] use std::ops::{RangeInclusive, RangeToInclusive}; -- cgit 1.4.1-3-g733a5 From 9e64946bded0698c8c45d74526e6a8b5a514c4a1 Mon Sep 17 00:00:00 2001 From: snf Date: Wed, 14 Mar 2018 14:56:37 +0000 Subject: setting ABORTING_MALLOC for asmjs backend --- src/liballoc/tests/string.rs | 5 ----- src/liballoc/tests/vec.rs | 7 +------ src/liballoc/tests/vec_deque.rs | 8 +------- src/librustc_back/target/asmjs_unknown_emscripten.rs | 4 +++- src/libstd/collections/hash/map.rs | 4 ---- 5 files changed, 5 insertions(+), 23 deletions(-) (limited to 'src/libstd') diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 9bbba4e22b0..d1e746ea43b 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -9,11 +9,8 @@ // except according to those terms. use std::borrow::Cow; -#[cfg(not(target_arch = "asmjs"))] use std::collections::CollectionAllocErr::*; -#[cfg(not(target_arch = "asmjs"))] use std::mem::size_of; -#[cfg(not(target_arch = "asmjs"))] use std::{usize, isize}; pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { @@ -535,7 +532,6 @@ fn test_reserve_exact() { assert!(s.capacity() >= 33) } -#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { @@ -613,7 +609,6 @@ fn test_try_reserve() { } -#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve_exact() { diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 85e11d8b8ee..3c17a401bba 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -10,11 +10,8 @@ use std::borrow::Cow; use std::mem::size_of; -use std::{usize, panic}; -#[cfg(not(target_arch = "asmjs"))] -use std::isize; +use std::{usize, isize, panic}; use std::vec::{Drain, IntoIter}; -#[cfg(not(target_arch = "asmjs"))] use std::collections::CollectionAllocErr::*; struct DropCounter<'a> { @@ -994,7 +991,6 @@ fn test_reserve_exact() { assert!(v.capacity() >= 33) } -#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { @@ -1097,7 +1093,6 @@ fn test_try_reserve() { } -#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve_exact() { diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 9fd38ed6f6f..fc1a0b624a5 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -11,13 +11,9 @@ use std::collections::VecDeque; use std::fmt::Debug; use std::collections::vec_deque::{Drain}; -#[cfg(not(target_arch = "asmjs"))] use std::collections::CollectionAllocErr::*; -#[cfg(not(target_arch = "asmjs"))] use std::mem::size_of; -use std::isize; -#[cfg(not(target_arch = "asmjs"))] -use std::usize; +use std::{usize, isize}; use self::Taggy::*; use self::Taggypar::*; @@ -1053,7 +1049,6 @@ fn test_reserve_exact_2() { assert!(v.capacity() >= 48) } -#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { @@ -1155,7 +1150,6 @@ fn test_try_reserve() { } -#[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve_exact() { diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index f114926740a..ab7df4ba1c5 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -15,7 +15,9 @@ pub fn target() -> Result { let mut args = LinkArgs::new(); args.insert(LinkerFlavor::Em, vec!["-s".to_string(), - "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]); + "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(), + "-s".to_string(), + "ABORTING_MALLOC=0".to_string()]); let opts = TargetOptions { dynamic_linking: false, diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 5f5dec2dd4f..b18b38ec302 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2755,11 +2755,8 @@ mod test_map { use cell::RefCell; use rand::{thread_rng, Rng}; use panic; - #[cfg(not(target_arch = "asmjs"))] use realstd::collections::CollectionAllocErr::*; - #[cfg(not(target_arch = "asmjs"))] use realstd::mem::size_of; - #[cfg(not(target_arch = "asmjs"))] use realstd::usize; #[test] @@ -3696,7 +3693,6 @@ mod test_map { assert_eq!(hm.len(), 0); } - #[cfg(not(target_arch = "asmjs"))] #[test] fn test_try_reserve() { -- cgit 1.4.1-3-g733a5 From 5e991e1b7ee3ddbd160203dec84bef10b45c1589 Mon Sep 17 00:00:00 2001 From: Anthony Defranceschi Date: Thu, 8 Mar 2018 23:18:45 +0100 Subject: Improve `AddrParseError` documentation. Add a potential cause to `AddrParseError` raising. --- src/libstd/net/parser.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 261d44eebaa..ae5037cc44e 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -372,6 +372,25 @@ impl FromStr for SocketAddr { /// [`IpAddr`], [`Ipv4Addr`], [`Ipv6Addr`], [`SocketAddr`], [`SocketAddrV4`], and /// [`SocketAddrV6`]. /// +/// # Potential causes +/// +/// `AddrParseError` may be thrown because the provided string does not parse as the given type, +/// often because it includes information only handled by a different address type. +/// +/// ```should_panic +/// use std::net::IpAddr; +/// let _foo: IpAddr = "127.0.0.1:8080".parse().expect("Cannot handle the socket port"); +/// ``` +/// +/// [`IpAddr`] doesn't handle the port. Use [`SocketAddr`] instead. +/// +/// ``` +/// use std::net::SocketAddr; +/// +/// // No problem, the `panic!` message has disappeared. +/// let _foo: SocketAddr = "127.0.0.1:8080".parse().expect("unreachable panic"); +/// ``` +/// /// [`FromStr`]: ../../std/str/trait.FromStr.html /// [`IpAddr`]: ../../std/net/enum.IpAddr.html /// [`Ipv4Addr`]: ../../std/net/struct.Ipv4Addr.html -- cgit 1.4.1-3-g733a5 From aaac69f78e6a9f0ee52b41969d81f4bb79da6418 Mon Sep 17 00:00:00 2001 From: Maxwell Powlison Date: Fri, 16 Mar 2018 03:41:53 -0400 Subject: Fix Issue #48345, is_file, is_dir, and is_symlink note mutual exclusion The methods on the structures `fs::FileType` and `fs::Metadata` of (respectively) `is_file`, `is_dir`, and `is_symlink` had some ambiguity in documentation, where it was not noted whether files will pass those tests exclusively or not. It is now written that the tests are mutually exclusive. Fixes #48345. --- src/libstd/fs.rs | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index db52ed67d3a..5caa703ee97 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -906,7 +906,13 @@ impl Metadata { FileType(self.0.file_type()) } - /// Returns whether this metadata is for a directory. + /// Returns whether this metadata is for a directory. The + /// result is mutually exclusive to the result of + /// [`is_file`], and will be false for symlink metadata + /// obtained from [`symlink_metadata`]. + /// + /// [`is_file`]: struct.Metadata.html#method.is_file + /// [`symlink_metadata`]: fn.symlink_metadata.html /// /// # Examples /// @@ -923,7 +929,13 @@ impl Metadata { #[stable(feature = "rust1", since = "1.0.0")] pub fn is_dir(&self) -> bool { self.file_type().is_dir() } - /// Returns whether this metadata is for a regular file. + /// Returns whether this metadata is for a regular file. The + /// result is mutually exclusive to the result of + /// [`is_dir`], and will be false for symlink metadata + /// obtained from [`symlink_metadata`]. + /// + /// [`is_dir`]: struct.Metadata.html#method.is_dir + /// [`symlink_metadata`]: fn.symlink_metadata.html /// /// # Examples /// @@ -1148,7 +1160,13 @@ impl Permissions { } impl FileType { - /// Test whether this file type represents a directory. + /// Test whether this file type represents a directory. The + /// result is mutually exclusive to the results of + /// [`is_file`] and [`is_symlink`]; only zero or one of these + /// tests may pass. + /// + /// [`is_file`]: struct.FileType.html#method.is_file + /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples /// @@ -1167,6 +1185,12 @@ impl FileType { pub fn is_dir(&self) -> bool { self.0.is_dir() } /// Test whether this file type represents a regular file. + /// The result is mutually exclusive to the results of + /// [`is_dir`] and [`is_symlink`]; only zero or one of these + /// tests may pass. + /// + /// [`is_dir`]: struct.FileType.html#method.is_dir + /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples /// @@ -1185,6 +1209,9 @@ impl FileType { pub fn is_file(&self) -> bool { self.0.is_file() } /// Test whether this file type represents a symbolic link. + /// The result is mutually exclusive to the results of + /// [`is_dir`] and [`is_file`]; only zero or one of these + /// tests may pass. /// /// The underlying [`Metadata`] struct needs to be retrieved /// with the [`fs::symlink_metadata`] function and not the @@ -1195,6 +1222,8 @@ impl FileType { /// [`Metadata`]: struct.Metadata.html /// [`fs::metadata`]: fn.metadata.html /// [`fs::symlink_metadata`]: fn.symlink_metadata.html + /// [`is_dir`]: struct.FileType.html#method.is_dir + /// [`is_file`]: struct.FileType.html#method.is_file /// [`is_symlink`]: struct.FileType.html#method.is_symlink /// /// # Examples -- cgit 1.4.1-3-g733a5 From 89ecb0d5424f4eb72de70c0b7b0c3fb819273728 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 17 Mar 2018 11:07:50 +0100 Subject: Mark deprecated unstable SipHasher13 as a doc-hidden impl detail of HashMap. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It stays in libcore rather than being private in HashMap’s module because it shares code with the deprecated *stable* `SipHasher` type. --- src/libcore/hash/mod.rs | 3 ++- src/libcore/hash/sip.rs | 11 ++++++----- src/libcore/tests/lib.rs | 2 +- src/libstd/lib.rs | 3 +-- 4 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 90d9ab3644a..ab714645675 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -99,8 +99,9 @@ use mem; #[allow(deprecated)] pub use self::sip::SipHasher; -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] #[allow(deprecated)] +#[doc(hidden)] pub use self::sip::SipHasher13; mod sip; diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 7790118fbde..e3bdecdc4b1 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -23,10 +23,11 @@ use mem; /// (eg. `collections::HashMap` uses it by default). /// /// See: -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] +#[doc(hidden)] pub struct SipHasher13 { hasher: Hasher, } @@ -34,7 +35,7 @@ pub struct SipHasher13 { /// An implementation of SipHash 2-4. /// /// See: -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] @@ -165,7 +166,7 @@ impl SipHasher { impl SipHasher13 { /// Creates a new `SipHasher13` with the two initial keys set to 0. #[inline] - #[unstable(feature = "sip_hash_13", issue = "34767")] + #[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher13 { @@ -174,7 +175,7 @@ impl SipHasher13 { /// Creates a `SipHasher13` that is keyed off the provided keys. #[inline] - #[unstable(feature = "sip_hash_13", issue = "34767")] + #[unstable(feature = "hashmap_internals", issue = "0")] #[rustc_deprecated(since = "1.13.0", reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { @@ -260,7 +261,7 @@ impl super::Hasher for SipHasher { } } -#[unstable(feature = "sip_hash_13", issue = "34767")] +#[unstable(feature = "hashmap_internals", issue = "0")] impl super::Hasher for SipHasher13 { #[inline] fn write(&mut self, msg: &[u8]) { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e53964b5769..1c876fa0bd7 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -21,6 +21,7 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(hashmap_internals)] #![feature(iterator_step_by)] #![feature(i128_type)] #![cfg_attr(stage0, feature(inclusive_range_syntax))] @@ -35,7 +36,6 @@ #![feature(range_is_empty)] #![feature(raw)] #![feature(refcell_replace_swap)] -#![feature(sip_hash_13)] #![feature(slice_patterns)] #![feature(sort_internals)] #![feature(specialization)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 70a1f82c9a1..62bef4bc499 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -267,7 +267,7 @@ #![feature(fn_traits)] #![feature(fnbox)] #![feature(generic_param_attrs)] -#![feature(hashmap_hasher)] +#![feature(hashmap_internals)] #![feature(heap_api)] #![feature(i128)] #![feature(i128_type)] @@ -298,7 +298,6 @@ #![feature(raw)] #![feature(rustc_attrs)] #![feature(stdsimd)] -#![feature(sip_hash_13)] #![feature(slice_bytes)] #![feature(slice_concat_ext)] #![feature(slice_internals)] -- cgit 1.4.1-3-g733a5 From 4a06708d30cc744583a3bce5508347977de6ac8c Mon Sep 17 00:00:00 2001 From: Niv Kaminer Date: Sat, 9 Dec 2017 21:46:25 +0200 Subject: remove FIXME(#39119) and allow running test on emscripten --- src/libstd/num.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/num.rs b/src/libstd/num.rs index a2c133954a3..33d70538522 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -169,7 +169,6 @@ mod tests { macro_rules! test_checked_next_power_of_two { ($test_name:ident, $T:ident) => ( - #[cfg_attr(target_os = "emscripten", ignore)] // FIXME(#39119) fn $test_name() { #![test] assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); -- cgit 1.4.1-3-g733a5 From f40877feeb17c538a73fe6294d48af123251a8c5 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 16 Feb 2018 10:39:24 +0100 Subject: Add 12 num::NonZero* types for each primitive integer RFC: https://github.com/rust-lang/rfcs/pull/2307 --- src/libcore/nonzero.rs | 2 +- src/libcore/num/mod.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/num.rs | 11 +++++++ 4 files changed, 100 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 2c966eb3b57..c6a1dab5617 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -62,7 +62,7 @@ impl_zeroable_for_integer_types! { /// NULL or 0 that might allow certain optimizations. #[lang = "non_zero"] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] -pub struct NonZero(T); +pub struct NonZero(pub(crate) T); impl NonZero { /// Creates an instance of NonZero with the provided value. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 09ab7060d37..d3556ef742b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,9 +15,96 @@ use convert::{Infallible, TryFrom}; use fmt; use intrinsics; +use nonzero::NonZero; use ops; use str::FromStr; +macro_rules! impl_nonzero_fmt { + ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + $( + #[$stability] + impl fmt::$Trait for $Ty { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.get().fmt(f) + } + } + )+ + } +} + +macro_rules! nonzero_integers { + ( #[$stability: meta] $( $Ty: ident($Int: ty); )+ ) => { + $( + /// An integer that is known not to equal zero. + /// + /// This may enable some memory layout optimization such as: + /// + /// ```rust + /// # #![feature(nonzero)] + /// use std::mem::size_of; + /// assert_eq!(size_of::>(), size_of::()); + /// ``` + #[$stability] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct $Ty(NonZero<$Int>); + + impl $Ty { + /// Create a non-zero without checking the value. + /// + /// # Safety + /// + /// The value must not be zero. + #[$stability] + #[inline] + pub const unsafe fn new_unchecked(n: $Int) -> Self { + $Ty(NonZero(n)) + } + + /// Create a non-zero if the given value is not zero. + #[$stability] + #[inline] + pub fn new(n: $Int) -> Option { + if n != 0 { + Some($Ty(NonZero(n))) + } else { + None + } + } + + /// Returns the value as a primitive type. + #[$stability] + #[inline] + pub fn get(self) -> $Int { + self.0 .0 + } + + } + + impl_nonzero_fmt! { + #[$stability] + (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + } + )+ + } +} + +nonzero_integers! { + #[unstable(feature = "nonzero", issue = "27730")] + NonZeroU8(u8); NonZeroI8(i8); + NonZeroU16(u16); NonZeroI16(i16); + NonZeroU32(u32); NonZeroI32(i32); + NonZeroU64(u64); NonZeroI64(i64); + NonZeroUsize(usize); NonZeroIsize(isize); +} + +nonzero_integers! { + // Change this to `#[unstable(feature = "i128", issue = "35118")]` + // if other NonZero* integer types are stabilizied before 128-bit integers + #[unstable(feature = "nonzero", issue = "27730")] + NonZeroU128(u128); NonZeroI128(i128); +} + /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values is intended to never overflow, diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 70a1f82c9a1..5c0a83fde10 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -282,6 +282,7 @@ #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] #![feature(exhaustive_patterns)] +#![feature(nonzero)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index a2c133954a3..5e0406ca220 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -21,6 +21,17 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError} #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; +#[unstable(feature = "nonzero", issue = "27730")] +pub use core::num::{ + NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, + NonZeroU64, NonZeroI64, NonZeroUsize, NonZeroIsize, +}; + +// Change this to `#[unstable(feature = "i128", issue = "35118")]` +// if other NonZero* integer types are stabilizied before 128-bit integers +#[unstable(feature = "nonzero", issue = "27730")] +pub use core::num::{NonZeroU128, NonZeroI128}; + #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; -- cgit 1.4.1-3-g733a5 From 7cbc93b14f0c5b39003a95f6cfbb74bd4fa04f40 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Sat, 17 Mar 2018 20:02:55 -0400 Subject: elide elidable lifetime in Path::strip_prefix --- src/libstd/path.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 527246fe1cd..c624a0b2a2f 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1880,15 +1880,15 @@ impl Path { /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); /// ``` #[stable(since = "1.7.0", feature = "path_strip_prefix")] - pub fn strip_prefix<'a, P>(&'a self, base: P) - -> Result<&'a Path, StripPrefixError> + pub fn strip_prefix