From a313abe3ba989ba4b6c041627c903488886f8559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sun, 9 Aug 2020 01:28:59 +0200 Subject: [PATCH 01/25] Manually implement Debug for BTreeMap::{IntoKeys,IntoValues} structs --- library/alloc/src/collections/btree/map.rs | 33 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 7e27aeb85392c..37bca05b97640 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -298,14 +298,23 @@ pub struct IntoIter { length: usize, } -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl IntoIter { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { let range = Range { front: self.front.as_ref().map(|f| f.reborrow()), back: self.back.as_ref().map(|b| b.reborrow()), }; - f.debug_list().entries(range).finish() + + Iter { range: range, length: self.length } + } +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } @@ -364,11 +373,17 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// /// [`into_keys`]: BTreeMap::into_keys #[unstable(feature = "map_into_keys_values", issue = "75294")] -#[derive(Debug)] pub struct IntoKeys { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish() + } +} + /// An owning iterator over the values of a `BTreeMap`. /// /// This `struct` is created by the [`into_values`] method on [`BTreeMap`]. @@ -376,11 +391,17 @@ pub struct IntoKeys { /// /// [`into_values`]: BTreeMap::into_values #[unstable(feature = "map_into_keys_values", issue = "75294")] -#[derive(Debug)] pub struct IntoValues { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() + } +} + /// An iterator over a sub-range of entries in a `BTreeMap`. /// /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its From 456738e3d1ad7dadffaed287d3055ca38b5fa375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 10 Aug 2020 17:47:40 +0200 Subject: [PATCH 02/25] Only print values in the Debug of HashMap::ValuesMut struct --- library/std/src/collections/hash/map.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 70f7214e2f1d7..968f81c2c3526 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1885,13 +1885,9 @@ impl ExactSizeIterator for ValuesMut<'_, K, V> { impl FusedIterator for ValuesMut<'_, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ValuesMut<'_, K, V> -where - K: fmt::Debug, - V: fmt::Debug, -{ +impl fmt::Debug for ValuesMut<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.inner.iter()).finish() + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() } } From c346e89db8a57e15111daa35685a2542d3be7c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Mon, 10 Aug 2020 17:49:39 +0200 Subject: [PATCH 03/25] Manually implement Debug for BTreeMap::ValuesMut struct Deriving debug prints all the values including keys. But ValuesMut struct should only print the values. --- library/alloc/src/collections/btree/map.rs | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 37bca05b97640..a08c19e3df4e9 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -361,11 +361,17 @@ impl fmt::Debug for Values<'_, K, V> { /// /// [`values_mut`]: BTreeMap::values_mut #[stable(feature = "map_values_mut", since = "1.10.0")] -#[derive(Debug)] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() + } +} + /// An owning iterator over the keys of a `BTreeMap`. /// /// This `struct` is created by the [`into_keys`] method on [`BTreeMap`]. @@ -1519,6 +1525,14 @@ impl ExactSizeIterator for IterMut<'_, K, V> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IterMut<'_, K, V> {} +impl<'a, K, V> IterMut<'a, K, V> { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { range: self.range.iter(), length: self.length } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { type Item = (K, V); @@ -2006,6 +2020,15 @@ impl<'a, K, V> RangeMut<'a, K, V> { unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } + + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Range<'_, K, V> { + Range { + front: self.front.as_ref().map(|f| f.reborrow()), + back: self.back.as_ref().map(|b| b.reborrow()), + } + } } #[stable(feature = "btree_range", since = "1.17.0")] From 8faf550e5f7211188bc9560ae459c155fb1aafdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Tue, 11 Aug 2020 20:42:02 +0200 Subject: [PATCH 04/25] Remove the unused bounds from Debug impl of HashMap::{IntoKeys,IntoValues} --- library/std/src/collections/hash/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 968f81c2c3526..022bdbe30a0f5 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1915,7 +1915,7 @@ impl ExactSizeIterator for IntoKeys { impl FusedIterator for IntoKeys {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() } @@ -1945,7 +1945,7 @@ impl ExactSizeIterator for IntoValues { impl FusedIterator for IntoValues {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() } From 247b73939a619ea4dcb2affbe1c285d20d93a0b8 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 15 Sep 2020 07:15:01 -0700 Subject: [PATCH 05/25] Move Wrapping ui tests into library --- .../core/tests/num/wrapping.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/wrapping-int-combinations.rs => library/core/tests/num/wrapping.rs (100%) diff --git a/src/test/ui/wrapping-int-combinations.rs b/library/core/tests/num/wrapping.rs similarity index 100% rename from src/test/ui/wrapping-int-combinations.rs rename to library/core/tests/num/wrapping.rs From 797cb9526a627c37b9bb9f6be6d3b54789b67c26 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 15 Sep 2020 07:24:07 -0700 Subject: [PATCH 06/25] Fix to libstd test --- library/core/tests/num/wrapping.rs | 86 +++++++++++++++--------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs index f0bc479ee0ff2..e50bb6f670f17 100644 --- a/library/core/tests/num/wrapping.rs +++ b/library/core/tests/num/wrapping.rs @@ -1,6 +1,4 @@ -// run-pass - -use std::num::Wrapping; +use core::num::Wrapping; macro_rules! wrapping_operation { ($result:expr, $lhs:ident $op:tt $rhs:expr) => { @@ -29,49 +27,53 @@ macro_rules! wrapping_assignment { macro_rules! wrapping_test { ($type:ty, $min:expr, $max:expr) => { - let zero: Wrapping<$type> = Wrapping(0); - let one: Wrapping<$type> = Wrapping(1); - let min: Wrapping<$type> = Wrapping($min); - let max: Wrapping<$type> = Wrapping($max); + #[test] + fn wrapping_$type() { + let zero: Wrapping<$type> = Wrapping(0); + let one: Wrapping<$type> = Wrapping(1); + let min: Wrapping<$type> = Wrapping($min); + let max: Wrapping<$type> = Wrapping($max); - wrapping_operation!(min, max + one); - wrapping_assignment!(min, max += one); - wrapping_operation!(max, min - one); - wrapping_assignment!(max, min -= one); - wrapping_operation!(max, max * one); - wrapping_assignment!(max, max *= one); - wrapping_operation!(max, max / one); - wrapping_assignment!(max, max /= one); - wrapping_operation!(zero, max % one); - wrapping_assignment!(zero, max %= one); - wrapping_operation!(zero, zero & max); - wrapping_assignment!(zero, zero &= max); - wrapping_operation!(max, zero | max); - wrapping_assignment!(max, zero |= max); - wrapping_operation!(zero, max ^ max); - wrapping_assignment!(zero, max ^= max); - wrapping_operation!(zero, zero << 1usize); - wrapping_assignment!(zero, zero <<= 1usize); - wrapping_operation!(zero, zero >> 1usize); - wrapping_assignment!(zero, zero >>= 1usize); - wrapping_operation!(zero, -zero); - wrapping_operation!(max, !min); + wrapping_operation!(min, max + one); + wrapping_assignment!(min, max += one); + wrapping_operation!(max, min - one); + wrapping_assignment!(max, min -= one); + wrapping_operation!(max, max * one); + wrapping_assignment!(max, max *= one); + wrapping_operation!(max, max / one); + wrapping_assignment!(max, max /= one); + wrapping_operation!(zero, max % one); + wrapping_assignment!(zero, max %= one); + wrapping_operation!(zero, zero & max); + wrapping_assignment!(zero, zero &= max); + wrapping_operation!(max, zero | max); + wrapping_assignment!(max, zero |= max); + wrapping_operation!(zero, max ^ max); + wrapping_assignment!(zero, max ^= max); + wrapping_operation!(zero, zero << 1usize); + wrapping_assignment!(zero, zero <<= 1usize); + wrapping_operation!(zero, zero >> 1usize); + wrapping_assignment!(zero, zero >>= 1usize); + wrapping_operation!(zero, -zero); + wrapping_operation!(max, !min); + } }; } -fn main() { - wrapping_test!(i8, std::i8::MIN, std::i8::MAX); - wrapping_test!(i16, std::i16::MIN, std::i16::MAX); - wrapping_test!(i32, std::i32::MIN, std::i32::MAX); - wrapping_test!(i64, std::i64::MIN, std::i64::MAX); +#[cfg(tests)] +mod tests { + wrapping_test!(i8, i8::MIN, i8::MAX); + wrapping_test!(i16, i16::MIN, i16::MAX); + wrapping_test!(i32, i32::MIN, i32::MAX); + wrapping_test!(i64, i64::MIN, i64::MAX); #[cfg(not(target_os = "emscripten"))] - wrapping_test!(i128, std::i128::MIN, std::i128::MAX); - wrapping_test!(isize, std::isize::MIN, std::isize::MAX); - wrapping_test!(u8, std::u8::MIN, std::u8::MAX); - wrapping_test!(u16, std::u16::MIN, std::u16::MAX); - wrapping_test!(u32, std::u32::MIN, std::u32::MAX); - wrapping_test!(u64, std::u64::MIN, std::u64::MAX); + wrapping_test!(i128, i128::MIN, i128::MAX); + wrapping_test!(isize, isize::MIN, isize::MAX); + wrapping_test!(u8, u8::MIN, u8::MAX); + wrapping_test!(u16, u16::MIN, u16::MAX); + wrapping_test!(u32, u32::MIN, u32::MAX); + wrapping_test!(u64, u64::MIN, u64::MAX); #[cfg(not(target_os = "emscripten"))] - wrapping_test!(u128, std::u128::MIN, std::u128::MAX); - wrapping_test!(usize, std::usize::MIN, std::usize::MAX); + wrapping_test!(u128, u128::MIN, u128::MAX); + wrapping_test!(usize, usize::MIN, usize::MAX); } From 980e1ff40f51b6b4b86ee70809d0a0055e6f9cc6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 24 Sep 2020 14:49:59 +0200 Subject: [PATCH 07/25] Add missing examples for Fd traits --- library/std/src/sys/unix/ext/io.rs | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs index ec7a32b675c02..ef780fa8cca29 100644 --- a/library/std/src/sys/unix/ext/io.rs +++ b/library/std/src/sys/unix/ext/io.rs @@ -25,6 +25,20 @@ pub trait AsRawFd { /// This method does **not** pass ownership of the raw file descriptor /// to the caller. The descriptor is only guaranteed to be valid while /// the original object has not yet been destroyed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// use std::os::unix::io::{AsRawFd, RawFd}; + /// + /// fn main() -> std::io::Result<()> { + /// let mut f = File::open("foo.txt")?; + /// // Note that `raw_fd` is only valid as long as `f` exists. + /// let raw_fd: RawFd = f.as_raw_fd(); + /// Ok(()) + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_fd(&self) -> RawFd; } @@ -45,6 +59,22 @@ pub trait FromRawFd { /// descriptor they are wrapping. Usage of this function could /// accidentally allow violating this contract which can cause memory /// unsafety in code that relies on it being true. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// Ok(()) + /// } + /// ``` #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_fd(fd: RawFd) -> Self; } @@ -58,6 +88,19 @@ pub trait IntoRawFd { /// This function **transfers ownership** of the underlying file descriptor /// to the caller. Callers are then the unique owners of the file descriptor /// and must close the descriptor once it's no longer needed. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// use std::os::unix::io::{IntoRawFd, RawFd}; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// Ok(()) + /// } + /// ``` #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_fd(self) -> RawFd; } From 07fd17f7014de6dc209c7dc4de159a2a5acea173 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 27 Sep 2020 15:19:42 +0200 Subject: [PATCH 08/25] Only use LOCAL_{STDOUT,STDERR} when set_{print/panic} is used. The thread local LOCAL_STDOUT and LOCAL_STDERR are only used by the test crate to capture output from tests when running them in the same process in differen threads. However, every program will check these variables on every print, even outside of testing. This involves allocating a thread local key, and registering a thread local destructor. This can be somewhat expensive. This change keeps a global flag (LOCAL_STREAMS) which will be set to true when either of these local streams is used. (So, effectively only in test and benchmark runs.) When this flag is off, these thread locals are not even looked at and therefore will not be initialized on the first output on every thread, which also means no thread local destructors will be registered. --- library/std/src/io/stdio.rs | 63 +++++++++++++++++++++++-------------- library/std/src/lib.rs | 1 + 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 61ccc6f13c8da..814e0dfda54b8 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -9,21 +9,24 @@ use crate::cell::RefCell; use crate::fmt; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; use crate::lazy::SyncOnceCell; +use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Mutex, MutexGuard}; use crate::sys::stdio; use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; +static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false); + thread_local! { - /// Stdout used by print! and println! macros + /// Used by the test crate to capture the output of the print! and println! macros. static LOCAL_STDOUT: RefCell>> = { RefCell::new(None) } } thread_local! { - /// Stderr used by eprint! and eprintln! macros, and panics + /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics. static LOCAL_STDERR: RefCell>> = { RefCell::new(None) } @@ -890,10 +893,14 @@ impl fmt::Debug for StderrLock<'_> { #[doc(hidden)] pub fn set_panic(sink: Option>) -> Option> { use crate::mem; - LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) + let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( + |mut s| { + let _ = s.flush(); + Some(s) + }, + ); + LOCAL_STREAMS.store(true, Ordering::Release); + s } /// Resets the thread-local stdout handle to the specified writer @@ -913,10 +920,14 @@ pub fn set_panic(sink: Option>) -> Option>) -> Option> { use crate::mem; - LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) + let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( + |mut s| { + let _ = s.flush(); + Some(s) + }, + ); + LOCAL_STREAMS.store(true, Ordering::Release); + s } /// Write `args` to output stream `local_s` if possible, `global_s` @@ -937,20 +948,26 @@ fn print_to( ) where T: Write, { - let result = local_s - .try_with(|s| { - // Note that we completely remove a local sink to write to in case - // our printing recursively panics/prints, so the recursive - // panic/print goes to the global sink instead of our local sink. - let prev = s.borrow_mut().take(); - if let Some(mut w) = prev { - let result = w.write_fmt(args); - *s.borrow_mut() = Some(w); - return result; - } - global_s().write_fmt(args) + let result = LOCAL_STREAMS + .load(Ordering::Acquire) + .then(|| { + local_s + .try_with(|s| { + // Note that we completely remove a local sink to write to in case + // our printing recursively panics/prints, so the recursive + // panic/print goes to the global sink instead of our local sink. + let prev = s.borrow_mut().take(); + if let Some(mut w) = prev { + let result = w.write_fmt(args); + *s.borrow_mut() = Some(w); + return result; + } + global_s().write_fmt(args) + }) + .ok() }) - .unwrap_or_else(|_| global_s().write_fmt(args)); + .flatten() + .unwrap_or_else(|| global_s().write_fmt(args)); if let Err(e) = result { panic!("failed printing to {}: {}", label, e); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d03428dd08282..410860b4a5d3f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -226,6 +226,7 @@ #![feature(asm)] #![feature(associated_type_bounds)] #![feature(atomic_mut_ptr)] +#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(c_variadic)] #![feature(cfg_accessible)] From ed3ead013f40c65e2972c794a71b756237a31b46 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 27 Sep 2020 15:32:07 +0200 Subject: [PATCH 09/25] Relax memory ordering of LOCAL_STREAMS and document it. --- library/std/src/io/stdio.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 814e0dfda54b8..df83c32982914 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -16,8 +16,6 @@ use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; -static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false); - thread_local! { /// Used by the test crate to capture the output of the print! and println! macros. static LOCAL_STDOUT: RefCell>> = { @@ -32,6 +30,20 @@ thread_local! { } } +/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used. +/// +/// If both are None and were never set on any thread, this flag is set to +/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all +/// threads, saving some time and memory registering an unused thread local. +/// +/// Note about memory ordering: This contains information about whether two +/// thread local variables might be in use. Although this is a global flag, the +/// memory ordering between threads does not matter: we only want this flag to +/// have a consistent order between set_print/set_panic and print_to *within +/// the same thread*. Within the same thread, things always have a perfectly +/// consistent order. So Ordering::Relaxed is fine. +static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false); + /// A handle to a raw instance of the standard input stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via @@ -899,7 +911,7 @@ pub fn set_panic(sink: Option>) -> Option>) -> Option( T: Write, { let result = LOCAL_STREAMS - .load(Ordering::Acquire) + .load(Ordering::Relaxed) .then(|| { local_s .try_with(|s| { From de597fca40d129435c53a69c6662d7bfac29771d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sun, 27 Sep 2020 15:35:35 +0200 Subject: [PATCH 10/25] Optimize set_{panic,print}(None). --- library/std/src/io/stdio.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index df83c32982914..36b49401591f5 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -905,6 +905,10 @@ impl fmt::Debug for StderrLock<'_> { #[doc(hidden)] pub fn set_panic(sink: Option>) -> Option> { use crate::mem; + if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { + // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false. + return None; + } let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( |mut s| { let _ = s.flush(); @@ -932,6 +936,10 @@ pub fn set_panic(sink: Option>) -> Option>) -> Option> { use crate::mem; + if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { + // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false. + return None; + } let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( |mut s| { let _ = s.flush(); From 2033eb1495b4a0386a0ab08815769477baf20c89 Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sun, 30 Aug 2020 09:56:20 -0400 Subject: [PATCH 11/25] Write manifest for MAJOR.MINOR channel to enable rustup convenience This connects to https://github.com/rust-lang/rustup/issues/794. It's hard to remember if there have been patch releases for old versions when you'd like to install the latest in a MAJOR.MINOR series. When we're doing a stable release, we write duplicate manifests to `stable`. With this change, only when we're doing a stable release, also write duplicate manifests to `MAJOR.MINOR` to eventually enable rustup (and any other tooling that builds Rust release URLs) to request, say, `1.45` and get `1.45.2` (assuming `1.45.2` is the latest available `1.45` and assuming that we never publish patch releases out of order). --- src/tools/build-manifest/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index be3e862e7aecd..5170833660086 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -293,6 +293,8 @@ impl Builder { self.write_channel_files(self.versions.channel(), &manifest); if self.versions.channel() != rust_version { self.write_channel_files(&rust_version, &manifest); + let major_minor = rust_version.split('.').take(2).collect::>().join("."); + self.write_channel_files(&major_minor, &manifest); } } From 17db1cb5d5a864d611e17d6e2466731c3b50a794 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Sep 2020 21:14:31 -0400 Subject: [PATCH 12/25] Bypass const_item_mutation if const's type has Drop impl --- .../src/transform/check_const_item_mutation.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 0281c478a6ca0..b556e2d217d6d 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -31,6 +31,15 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { None } } + + fn is_const_item_without_destructor(&self, local: Local) -> Option { + let def_id = self.is_const_item(local)?; + match self.tcx.adt_def(def_id).destructor(self.tcx) { + Some(_) => None, + None => Some(def_id), + } + } + fn lint_const_item_usage( &self, const_item: DefId, @@ -59,7 +68,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, // so emitting a lint would be redundant. if !lhs.projection.is_empty() { - if let Some(def_id) = self.is_const_item(lhs.local) { + if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) { // Don't lint on writes through a pointer // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`) if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) { @@ -89,7 +98,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue { let local = place.local; - if let Some(def_id) = self.is_const_item(local) { + if let Some(def_id) = self.is_const_item_without_destructor(local) { // If this Rvalue is being used as the right-hand side of a // `StatementKind::Assign`, see if it ends up getting used as // the `self` parameter of a method call (as the terminator of our current From 0dfe7b6434f6aabbe9673a891ba74c7c7922661d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Sep 2020 21:19:08 -0400 Subject: [PATCH 13/25] Add justification of the destructor filter --- .../src/transform/check_const_item_mutation.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index b556e2d217d6d..aae6794994594 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -34,6 +34,18 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { fn is_const_item_without_destructor(&self, local: Local) -> Option { let def_id = self.is_const_item(local)?; + + // We avoid linting mutation of a const item if the const's type has a + // Drop impl. The Drop logic observes the mutation which was performed. + // + // struct Log { msg: &'static str } + // const LOG: Log = Log { msg: "" }; + // impl Drop for Log { + // fn drop(&mut self) { println!("{}", self.msg); } + // } + // + // LOG.msg = "wow"; // prints "wow" + // match self.tcx.adt_def(def_id).destructor(self.tcx) { Some(_) => None, None => Some(def_id), From bb760b53bf7f9593c09a03e5dea28ef5f31065d7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Sep 2020 18:36:01 -0700 Subject: [PATCH 14/25] Simplify defid destructor check --- compiler/rustc_mir/src/transform/check_const_item_mutation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index aae6794994594..112c25a312930 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { // // LOG.msg = "wow"; // prints "wow" // - match self.tcx.adt_def(def_id).destructor(self.tcx) { + match self.tcx.adt_destructor(def_id) { Some(_) => None, None => Some(def_id), } From 0f6284c88d521904bb0ada34325a0372a1ea26f1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Sep 2020 18:42:19 -0700 Subject: [PATCH 15/25] Add test of const item mutation with Drop impl --- src/test/ui/lint/lint-const-item-mutation.rs | 12 ++++++++++ .../ui/lint/lint-const-item-mutation.stderr | 24 +++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs index 43371560e02c1..0fb97367737d6 100644 --- a/src/test/ui/lint/lint-const-item-mutation.rs +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -9,9 +9,19 @@ impl MyStruct { fn use_mut(&mut self) {} } +struct Mutable { + msg: &'static str, +} +impl Drop for Mutable { + fn drop(&mut self) { + println!("{}", self.msg); + } +} + const ARRAY: [u8; 1] = [25]; const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; const RAW_PTR: *mut u8 = 1 as *mut u8; +const MUTABLE: Mutable = Mutable { msg: "" }; fn main() { ARRAY[0] = 5; //~ WARN attempting to modify @@ -29,4 +39,6 @@ fn main() { *RAW_PTR = 0; *MY_STRUCT.raw_ptr = 0; } + + MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation } diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index c5a221128ffab..6ede7b31666c8 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -1,5 +1,5 @@ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:17:5 + --> $DIR/lint-const-item-mutation.rs:27:5 | LL | ARRAY[0] = 5; | ^^^^^^^^^^^^ @@ -7,39 +7,39 @@ LL | ARRAY[0] = 5; = note: `#[warn(const_item_mutation)]` on by default = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:12:1 + --> $DIR/lint-const-item-mutation.rs:21:1 | LL | const ARRAY: [u8; 1] = [25]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:18:5 + --> $DIR/lint-const-item-mutation.rs:28:5 | LL | MY_STRUCT.field = false; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:22:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:19:5 + --> $DIR/lint-const-item-mutation.rs:29:5 | LL | MY_STRUCT.inner_array[0] = 'b'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:22:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:20:5 + --> $DIR/lint-const-item-mutation.rs:30:5 | LL | MY_STRUCT.use_mut(); | ^^^^^^^^^^^^^^^^^^^ @@ -52,13 +52,13 @@ note: mutable reference created due to call to this method LL | fn use_mut(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^ note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:22:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:21:5 + --> $DIR/lint-const-item-mutation.rs:31:5 | LL | &mut MY_STRUCT; | ^^^^^^^^^^^^^^ @@ -66,13 +66,13 @@ LL | &mut MY_STRUCT; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:22:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:22:5 + --> $DIR/lint-const-item-mutation.rs:32:5 | LL | (&mut MY_STRUCT).use_mut(); | ^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | (&mut MY_STRUCT).use_mut(); = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:22:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 352ce8b29990d62465675b46b42a695a4206d5be Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Sep 2020 21:19:46 -0700 Subject: [PATCH 16/25] Test a type with drop glue but no Drop impl --- src/test/ui/lint/lint-const-item-mutation.rs | 7 ++++ .../ui/lint/lint-const-item-mutation.stderr | 39 ++++++++++++------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs index 0fb97367737d6..37e6420fc9832 100644 --- a/src/test/ui/lint/lint-const-item-mutation.rs +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -18,10 +18,16 @@ impl Drop for Mutable { } } +struct Mutable2 { // this one has drop glue but not a Drop impl + msg: &'static str, + other: String, +} + const ARRAY: [u8; 1] = [25]; const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; const RAW_PTR: *mut u8 = 1 as *mut u8; const MUTABLE: Mutable = Mutable { msg: "" }; +const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; fn main() { ARRAY[0] = 5; //~ WARN attempting to modify @@ -41,4 +47,5 @@ fn main() { } MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation + MUTABLE2.msg = "wow"; //~ WARN attempting to modify } diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index 6ede7b31666c8..20a8ed0d78386 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -1,5 +1,5 @@ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:27:5 + --> $DIR/lint-const-item-mutation.rs:33:5 | LL | ARRAY[0] = 5; | ^^^^^^^^^^^^ @@ -7,39 +7,39 @@ LL | ARRAY[0] = 5; = note: `#[warn(const_item_mutation)]` on by default = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:21:1 + --> $DIR/lint-const-item-mutation.rs:26:1 | LL | const ARRAY: [u8; 1] = [25]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:28:5 + --> $DIR/lint-const-item-mutation.rs:34:5 | LL | MY_STRUCT.field = false; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:22:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:29:5 + --> $DIR/lint-const-item-mutation.rs:35:5 | LL | MY_STRUCT.inner_array[0] = 'b'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:22:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:30:5 + --> $DIR/lint-const-item-mutation.rs:36:5 | LL | MY_STRUCT.use_mut(); | ^^^^^^^^^^^^^^^^^^^ @@ -52,13 +52,13 @@ note: mutable reference created due to call to this method LL | fn use_mut(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^ note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:22:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:31:5 + --> $DIR/lint-const-item-mutation.rs:37:5 | LL | &mut MY_STRUCT; | ^^^^^^^^^^^^^^ @@ -66,13 +66,13 @@ LL | &mut MY_STRUCT; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:22:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:32:5 + --> $DIR/lint-const-item-mutation.rs:38:5 | LL | (&mut MY_STRUCT).use_mut(); | ^^^^^^^^^^^^^^^^ @@ -80,10 +80,23 @@ LL | (&mut MY_STRUCT).use_mut(); = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:22:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 6 warnings emitted +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:50:5 + | +LL | MUTABLE2.msg = "wow"; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:30:1 + | +LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 7 warnings emitted From 41baa090ad1c40a7fc96f96664543ce4c26746c2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Sep 2020 18:43:19 -0700 Subject: [PATCH 17/25] Skip dropck::check_drop_impl in is_const_item_without_destructor adt_destructor by default also validates the Drop impl using dropck::check_drop_impl, which contains an expect_local(). This leads to ICE in check_const_item_mutation if the const's type is not a local type. thread 'rustc' panicked at 'DefId::expect_local: `DefId(5:4805 ~ alloc[d7e9]::vec::{impl#50})` isn't local', compiler/rustc_span/src/def_id.rs:174:43 stack backtrace: 0: rust_begin_unwind 1: rustc_span::def_id::DefId::expect_local::{{closure}} 2: rustc_typeck::check::dropck::check_drop_impl 3: rustc_middle::ty::util::::calculate_dtor::{{closure}} 4: rustc_middle::ty::trait_def::::for_each_relevant_impl 5: rustc_middle::ty::util::::calculate_dtor 6: rustc_typeck::check::adt_destructor 7: rustc_middle::ty::query:: for rustc_middle::ty::query::queries::adt_destructor>::compute 8: rustc_query_system::dep_graph::graph::DepGraph::with_task_impl 9: rustc_query_system::query::plumbing::get_query_impl 10: rustc_mir::transform::check_const_item_mutation::ConstMutationChecker::is_const_item_without_destructor --- compiler/rustc_mir/src/transform/check_const_item_mutation.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 112c25a312930..98477b032372e 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -34,6 +34,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { fn is_const_item_without_destructor(&self, local: Local) -> Option { let def_id = self.is_const_item(local)?; + let mut any_dtor = |_tcx, _def_id| Ok(()); // We avoid linting mutation of a const item if the const's type has a // Drop impl. The Drop logic observes the mutation which was performed. @@ -46,7 +47,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { // // LOG.msg = "wow"; // prints "wow" // - match self.tcx.adt_destructor(def_id) { + match self.tcx.calculate_dtor(def_id, &mut any_dtor) { Some(_) => None, None => Some(def_id), } From eef5104c53114bf9a074fe8d83cfd782bd78652d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 30 Sep 2020 22:13:33 -0700 Subject: [PATCH 18/25] Add test of VEC.push on a const --- src/test/ui/lint/lint-const-item-mutation.rs | 2 ++ src/test/ui/lint/lint-const-item-mutation.stderr | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs index 37e6420fc9832..9f6a4e5908858 100644 --- a/src/test/ui/lint/lint-const-item-mutation.rs +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -28,6 +28,7 @@ const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: const RAW_PTR: *mut u8 = 1 as *mut u8; const MUTABLE: Mutable = Mutable { msg: "" }; const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; +const VEC: Vec = Vec::new(); fn main() { ARRAY[0] = 5; //~ WARN attempting to modify @@ -48,4 +49,5 @@ fn main() { MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation MUTABLE2.msg = "wow"; //~ WARN attempting to modify + VEC.push(0); // no warning } diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index 20a8ed0d78386..0e02ba928bb35 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -1,5 +1,5 @@ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:33:5 + --> $DIR/lint-const-item-mutation.rs:34:5 | LL | ARRAY[0] = 5; | ^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | const ARRAY: [u8; 1] = [25]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:34:5 + --> $DIR/lint-const-item-mutation.rs:35:5 | LL | MY_STRUCT.field = false; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:35:5 + --> $DIR/lint-const-item-mutation.rs:36:5 | LL | MY_STRUCT.inner_array[0] = 'b'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:36:5 + --> $DIR/lint-const-item-mutation.rs:37:5 | LL | MY_STRUCT.use_mut(); | ^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:37:5 + --> $DIR/lint-const-item-mutation.rs:38:5 | LL | &mut MY_STRUCT; | ^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:38:5 + --> $DIR/lint-const-item-mutation.rs:39:5 | LL | (&mut MY_STRUCT).use_mut(); | ^^^^^^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:50:5 + --> $DIR/lint-const-item-mutation.rs:51:5 | LL | MUTABLE2.msg = "wow"; | ^^^^^^^^^^^^^^^^^^^^ From 75c2fdf34a5384627db9ba240c5dcc0723aea763 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 30 Sep 2020 22:16:32 -0700 Subject: [PATCH 19/25] Warn on method call mutating const, even if it has destructor --- .../transform/check_const_item_mutation.rs | 2 +- src/test/ui/lint/lint-const-item-mutation.rs | 2 +- .../ui/lint/lint-const-item-mutation.stderr | 27 ++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 98477b032372e..a0edb3772439a 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) { if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue { let local = place.local; - if let Some(def_id) = self.is_const_item_without_destructor(local) { + if let Some(def_id) = self.is_const_item(local) { // If this Rvalue is being used as the right-hand side of a // `StatementKind::Assign`, see if it ends up getting used as // the `self` parameter of a method call (as the terminator of our current diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs index 9f6a4e5908858..c49a13f1065b5 100644 --- a/src/test/ui/lint/lint-const-item-mutation.rs +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -49,5 +49,5 @@ fn main() { MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation MUTABLE2.msg = "wow"; //~ WARN attempting to modify - VEC.push(0); // no warning + VEC.push(0); //~ WARN taking a mutable reference to a `const` item } diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index 0e02ba928bb35..11b5124b2d26a 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -98,5 +98,30 @@ note: `const` item defined here LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 7 warnings emitted +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:52:5 + | +LL | VEC.push(0); + | ^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: mutable reference created due to call to this method + --> $SRC_DIR/alloc/src/vec.rs:LL:COL + | +LL | / pub fn push(&mut self, value: T) { +LL | | // This will panic or abort if we would allocate > isize::MAX bytes +LL | | // or if the length increment would overflow for zero-sized types. +LL | | if self.len == self.buf.capacity() { +... | +LL | | } +LL | | } + | |_____^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:31:1 + | +LL | const VEC: Vec = Vec::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 8 warnings emitted From a8fe6544482593073118dbdc3b25c2fb1fa7506c Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" <193874+carols10cents@users.noreply.github.com> Date: Thu, 1 Oct 2020 12:06:45 -0400 Subject: [PATCH 20/25] Write MAJOR.MINOR manifest for stable channel only --- src/tools/build-manifest/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 5170833660086..e1dc9111bf326 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -293,6 +293,8 @@ impl Builder { self.write_channel_files(self.versions.channel(), &manifest); if self.versions.channel() != rust_version { self.write_channel_files(&rust_version, &manifest); + } + if self.versions.channel() == "stable" { let major_minor = rust_version.split('.').take(2).collect::>().join("."); self.write_channel_files(&major_minor, &manifest); } From 804d159c6276025e26ade90a6ef013bda33207c3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 1 Oct 2020 13:41:29 -0700 Subject: [PATCH 21/25] Fixme with link for re-enabling const mutation lint for Drop consts --- .../src/transform/check_const_item_mutation.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index a0edb3772439a..b6d57b899ddab 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -39,14 +39,21 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { // We avoid linting mutation of a const item if the const's type has a // Drop impl. The Drop logic observes the mutation which was performed. // - // struct Log { msg: &'static str } - // const LOG: Log = Log { msg: "" }; + // pub struct Log { msg: &'static str } + // pub const LOG: Log = Log { msg: "" }; // impl Drop for Log { // fn drop(&mut self) { println!("{}", self.msg); } // } // // LOG.msg = "wow"; // prints "wow" // + // FIXME(https://github.com/rust-lang/rust/issues/77425): + // Drop this exception once there is a stable attribute to suppress the + // const item mutation lint for a single specific const only. Something + // equivalent to: + // + // #[const_mutation_allowed] + // pub const LOG: Log = Log { msg: "" }; match self.tcx.calculate_dtor(def_id, &mut any_dtor) { Some(_) => None, None => Some(def_id), From b20bce8ce54ea9d47c2e3eb0b17cbb6baf916ae2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 1 Oct 2020 20:47:25 +0300 Subject: [PATCH 22/25] Revert "resolve: Avoid "self-confirming" import resolutions in one more case" --- compiler/rustc_resolve/src/imports.rs | 13 ++----------- src/test/ui/imports/issue-62767.rs | 23 ++++++++++++++++++----- src/test/ui/imports/issue-62767.stderr | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/imports/issue-62767.stderr diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index bf8a2f269dd57..adff4542b0ff8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -875,12 +875,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: &'b Import<'b>) -> Option { let orig_vis = import.vis.replace(ty::Visibility::Invisible); - let orig_unusable_binding = match &import.kind { - ImportKind::Single { target_bindings, .. } => { - Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get())) - } - _ => None, - }; let prev_ambiguity_errors_len = self.r.ambiguity_errors.len(); let path_res = self.r.resolve_path( &import.module_path, @@ -891,9 +885,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { import.crate_lint(), ); let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; - if let Some(orig_unusable_binding) = orig_unusable_binding { - self.r.unusable_binding = orig_unusable_binding; - } import.vis.set(orig_vis); if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res { // Consider erroneous imports used to avoid duplicate diagnostics. @@ -904,7 +895,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Consistency checks, analogous to `finalize_macro_resolutions`. if let Some(initial_module) = import.imported_module.get() { if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity { - span_bug!(import.span, "inconsistent resolution for an import"); + let msg = "inconsistent resolution for an import"; + self.r.session.span_err(import.span, msg); } } else { if self.r.privacy_errors.is_empty() { @@ -926,7 +918,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => { if no_ambiguity { - assert!(import.imported_module.get().is_none()); let err = match self.make_path_suggestion( span, import.module_path.clone(), diff --git a/src/test/ui/imports/issue-62767.rs b/src/test/ui/imports/issue-62767.rs index 984d3f0ca92f4..0e0f915ea53c2 100644 --- a/src/test/ui/imports/issue-62767.rs +++ b/src/test/ui/imports/issue-62767.rs @@ -1,5 +1,4 @@ -// check-pass - +// Minimized case from #62767. mod m { pub enum Same { Same, @@ -8,8 +7,22 @@ mod m { use m::*; -// The variant `Same` introduced by this import is not considered when resolving the prefix -// `Same::` during import validation (issue #62767). -use Same::Same; +// The variant `Same` introduced by this import is also considered when resolving the prefix +// `Same::` during import validation to avoid effects similar to time travel (#74556). +use Same::Same; //~ ERROR unresolved import `Same` + +// Case from #74556. +mod foo { + pub mod bar { + pub mod bar { + pub fn foobar() {} + } + } +} + +use foo::*; +use bar::bar; //~ ERROR unresolved import `bar::bar` + //~| ERROR inconsistent resolution for an import +use bar::foobar; fn main() {} diff --git a/src/test/ui/imports/issue-62767.stderr b/src/test/ui/imports/issue-62767.stderr new file mode 100644 index 0000000000000..a4334bda6dd87 --- /dev/null +++ b/src/test/ui/imports/issue-62767.stderr @@ -0,0 +1,21 @@ +error: inconsistent resolution for an import + --> $DIR/issue-62767.rs:24:5 + | +LL | use bar::bar; + | ^^^^^^^^ + +error[E0432]: unresolved import `Same` + --> $DIR/issue-62767.rs:12:5 + | +LL | use Same::Same; + | ^^^^ `Same` is a variant, not a module + +error[E0432]: unresolved import `bar::bar` + --> $DIR/issue-62767.rs:24:5 + | +LL | use bar::bar; + | ^^^^^^^^ no `bar` in `foo::bar::bar` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. From 89fdfe682870bd60e759a38c0509af605eaff759 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Fri, 2 Oct 2020 09:28:05 -0400 Subject: [PATCH 23/25] Permit ty::Bool in const generics for v0 mangling --- compiler/rustc_symbol_mangling/src/v0.rs | 1 + src/test/ui/symbol-names/issue-76365.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/test/ui/symbol-names/issue-76365.rs diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 091d488138e46..da9c93143bfb3 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -504,6 +504,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { match ct.ty.kind() { ty::Uint(_) => {} + ty::Bool => {} _ => { bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct); } diff --git a/src/test/ui/symbol-names/issue-76365.rs b/src/test/ui/symbol-names/issue-76365.rs new file mode 100644 index 0000000000000..61ba255dac04d --- /dev/null +++ b/src/test/ui/symbol-names/issue-76365.rs @@ -0,0 +1,18 @@ +// check-pass +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib + //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib + +#![feature(min_const_generics)] + +pub struct Bar; + +impl Bar { + pub fn foo() {} +} + +impl Bar { + pub fn bar() {} +} + +fn main() {} From d6b838b93a7e0acd51e0cc9bbb3415a517b7b3cd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Oct 2020 16:38:15 +0200 Subject: [PATCH 24/25] Simplify fd examples --- library/std/src/sys/unix/ext/io.rs | 35 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs index ef780fa8cca29..d929c8bbd68a1 100644 --- a/library/std/src/sys/unix/ext/io.rs +++ b/library/std/src/sys/unix/ext/io.rs @@ -30,14 +30,13 @@ pub trait AsRawFd { /// /// ```no_run /// use std::fs::File; + /// # use std::io; /// use std::os::unix::io::{AsRawFd, RawFd}; /// - /// fn main() -> std::io::Result<()> { - /// let mut f = File::open("foo.txt")?; - /// // Note that `raw_fd` is only valid as long as `f` exists. - /// let raw_fd: RawFd = f.as_raw_fd(); - /// Ok(()) - /// } + /// let mut f = File::open("foo.txt")?; + /// // Note that `raw_fd` is only valid as long as `f` exists. + /// let raw_fd: RawFd = f.as_raw_fd(); + /// # Ok::<(), io::Error>(()) /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_fd(&self) -> RawFd; @@ -64,16 +63,15 @@ pub trait FromRawFd { /// /// ```no_run /// use std::fs::File; + /// # use std::io; /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; - /// let raw_fd: RawFd = f.into_raw_fd(); - /// // SAFETY: no other functions should call `from_raw_fd`, so there - /// // is only one owner for the file descriptor. - /// let f = unsafe { File::from_raw_fd(raw_fd) }; - /// Ok(()) - /// } + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// # Ok::<(), io::Error>(()) /// ``` #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_fd(fd: RawFd) -> Self; @@ -93,13 +91,12 @@ pub trait IntoRawFd { /// /// ```no_run /// use std::fs::File; + /// # use std::io; /// use std::os::unix::io::{IntoRawFd, RawFd}; /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("foo.txt")?; - /// let raw_fd: RawFd = f.into_raw_fd(); - /// Ok(()) - /// } + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// # Ok::<(), io::Error>(()) /// ``` #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_fd(self) -> RawFd; From 4e973966b95e5157754f91216456a3c37a1472b2 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 2 Oct 2020 11:40:57 -0700 Subject: [PATCH 25/25] Remove unnecessary mod-cfg --- library/core/tests/num/wrapping.rs | 31 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs index e50bb6f670f17..5d4ecb2669a96 100644 --- a/library/core/tests/num/wrapping.rs +++ b/library/core/tests/num/wrapping.rs @@ -60,20 +60,17 @@ macro_rules! wrapping_test { }; } -#[cfg(tests)] -mod tests { - wrapping_test!(i8, i8::MIN, i8::MAX); - wrapping_test!(i16, i16::MIN, i16::MAX); - wrapping_test!(i32, i32::MIN, i32::MAX); - wrapping_test!(i64, i64::MIN, i64::MAX); - #[cfg(not(target_os = "emscripten"))] - wrapping_test!(i128, i128::MIN, i128::MAX); - wrapping_test!(isize, isize::MIN, isize::MAX); - wrapping_test!(u8, u8::MIN, u8::MAX); - wrapping_test!(u16, u16::MIN, u16::MAX); - wrapping_test!(u32, u32::MIN, u32::MAX); - wrapping_test!(u64, u64::MIN, u64::MAX); - #[cfg(not(target_os = "emscripten"))] - wrapping_test!(u128, u128::MIN, u128::MAX); - wrapping_test!(usize, usize::MIN, usize::MAX); -} +wrapping_test!(i8, i8::MIN, i8::MAX); +wrapping_test!(i16, i16::MIN, i16::MAX); +wrapping_test!(i32, i32::MIN, i32::MAX); +wrapping_test!(i64, i64::MIN, i64::MAX); +#[cfg(not(target_os = "emscripten"))] +wrapping_test!(i128, i128::MIN, i128::MAX); +wrapping_test!(isize, isize::MIN, isize::MAX); +wrapping_test!(u8, u8::MIN, u8::MAX); +wrapping_test!(u16, u16::MIN, u16::MAX); +wrapping_test!(u32, u32::MIN, u32::MAX); +wrapping_test!(u64, u64::MIN, u64::MAX); +#[cfg(not(target_os = "emscripten"))] +wrapping_test!(u128, u128::MIN, u128::MAX); +wrapping_test!(usize, usize::MIN, usize::MAX);